mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Update MediaCodecTrackRenderer.
1. Workaround for decoders that fail to handle the END_OF_STREAM flag.
2. Revert processing of final output buffer if it's non-empty. This
introduced another bug (#596)
Reverts: b88012f51f
Issue: #417
Issue: #596
This commit is contained in:
parent
884e7a4170
commit
4282d7c22b
1 changed files with 58 additions and 26 deletions
|
|
@ -195,6 +195,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
private DrmInitData drmInitData;
|
||||
private MediaCodec codec;
|
||||
private boolean codecIsAdaptive;
|
||||
private boolean codecNeedsEndOfStreamWorkaround;
|
||||
private ByteBuffer[] inputBuffers;
|
||||
private ByteBuffer[] outputBuffers;
|
||||
private long codecHotswapTimeMs;
|
||||
|
|
@ -357,6 +358,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
|
||||
String decoderName = decoderInfo.name;
|
||||
codecIsAdaptive = decoderInfo.adaptive;
|
||||
codecNeedsEndOfStreamWorkaround = codecNeedsEndOfStreamWorkaround(decoderName);
|
||||
try {
|
||||
long codecInitializingTimestamp = SystemClock.elapsedRealtime();
|
||||
TraceUtil.beginSection("createByCodecName(" + decoderName + ")");
|
||||
|
|
@ -432,6 +434,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
codecReconfigured = false;
|
||||
codecHasQueuedBuffers = false;
|
||||
codecIsAdaptive = false;
|
||||
codecNeedsEndOfStreamWorkaround = false;
|
||||
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
||||
codecReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||
codecCounters.codecReleaseCount++;
|
||||
|
|
@ -581,8 +584,12 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
|
||||
// We need to re-initialize the codec. Send an end of stream signal to the existing codec so
|
||||
// that it outputs any remaining buffers before we release it.
|
||||
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
inputIndex = -1;
|
||||
if (codecNeedsEndOfStreamWorkaround) {
|
||||
// Do nothing.
|
||||
} else {
|
||||
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
inputIndex = -1;
|
||||
}
|
||||
codecReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -634,8 +641,12 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
}
|
||||
inputStreamEnded = true;
|
||||
try {
|
||||
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
inputIndex = -1;
|
||||
if (codecNeedsEndOfStreamWorkaround) {
|
||||
// Do nothing.
|
||||
} else {
|
||||
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
inputIndex = -1;
|
||||
}
|
||||
} catch (CryptoException e) {
|
||||
notifyCryptoError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
|
|
@ -832,35 +843,25 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
codecCounters.outputBuffersChangedCount++;
|
||||
return true;
|
||||
} else if (outputIndex < 0) {
|
||||
if (codecNeedsEndOfStreamWorkaround && (inputStreamEnded
|
||||
|| codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM)) {
|
||||
processEndOfStream();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
processEndOfStream();
|
||||
return false;
|
||||
}
|
||||
|
||||
int decodeOnlyIndex = getDecodeOnlyIndex(outputBufferInfo.presentationTimeUs);
|
||||
boolean isEndOfStream = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
|
||||
|
||||
boolean processedOutputBuffer;
|
||||
if (isEndOfStream && outputBufferInfo.size == 0) {
|
||||
// Empty buffer indicating the end of the stream.
|
||||
codec.releaseOutputBuffer(outputIndex, false);
|
||||
processedOutputBuffer = true;
|
||||
} else {
|
||||
processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs, codec,
|
||||
outputBuffers[outputIndex], outputBufferInfo, outputIndex, decodeOnlyIndex != -1);
|
||||
}
|
||||
|
||||
if (processedOutputBuffer) {
|
||||
if (processOutputBuffer(positionUs, elapsedRealtimeUs, codec, outputBuffers[outputIndex],
|
||||
outputBufferInfo, outputIndex, decodeOnlyIndex != -1)) {
|
||||
if (decodeOnlyIndex != -1) {
|
||||
decodeOnlyPresentationTimestamps.remove(decodeOnlyIndex);
|
||||
}
|
||||
if (isEndOfStream) {
|
||||
if (codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
|
||||
// We're waiting to re-initialize the codec, and have now processed all final buffers.
|
||||
releaseCodec();
|
||||
maybeInitCodec();
|
||||
} else {
|
||||
outputStreamEnded = true;
|
||||
}
|
||||
}
|
||||
outputIndex = -1;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -879,6 +880,21 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
MediaCodec codec, ByteBuffer buffer, MediaCodec.BufferInfo bufferInfo, int bufferIndex,
|
||||
boolean shouldSkip) throws ExoPlaybackException;
|
||||
|
||||
/**
|
||||
* Processes an end of stream signal.
|
||||
*
|
||||
* @throws ExoPlaybackException If an error occurs processing the signal.
|
||||
*/
|
||||
private void processEndOfStream() throws ExoPlaybackException {
|
||||
if (codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
|
||||
// We're waiting to re-initialize the codec, and have now processed all final buffers.
|
||||
releaseCodec();
|
||||
maybeInitCodec();
|
||||
} else {
|
||||
outputStreamEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDecoderInitializationError(final DecoderInitializationException e) {
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
eventHandler.post(new Runnable() {
|
||||
|
|
@ -924,4 +940,20 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the decoder is known to handle {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM}
|
||||
* incorrectly on the host device.
|
||||
* <p>
|
||||
* If true is returned, the renderer will work around the issue by approximating end of stream
|
||||
* behavior without involvement of the underlying decoder.
|
||||
*
|
||||
* @param name The name of the decoder.
|
||||
* @return True if the decoder is known to handle {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM}
|
||||
* incorrectly on the host device. False otherwise.
|
||||
*/
|
||||
private static boolean codecNeedsEndOfStreamWorkaround(String name) {
|
||||
return Util.SDK_INT <= 17 && "ht7s3".equals(Util.DEVICE) // Tesco HUDL
|
||||
&& "OMX.rk.video_decoder.avc".equals(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue