mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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 DrmInitData drmInitData;
|
||||||
private MediaCodec codec;
|
private MediaCodec codec;
|
||||||
private boolean codecIsAdaptive;
|
private boolean codecIsAdaptive;
|
||||||
|
private boolean codecNeedsEndOfStreamWorkaround;
|
||||||
private ByteBuffer[] inputBuffers;
|
private ByteBuffer[] inputBuffers;
|
||||||
private ByteBuffer[] outputBuffers;
|
private ByteBuffer[] outputBuffers;
|
||||||
private long codecHotswapTimeMs;
|
private long codecHotswapTimeMs;
|
||||||
|
|
@ -357,6 +358,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
|
|
||||||
String decoderName = decoderInfo.name;
|
String decoderName = decoderInfo.name;
|
||||||
codecIsAdaptive = decoderInfo.adaptive;
|
codecIsAdaptive = decoderInfo.adaptive;
|
||||||
|
codecNeedsEndOfStreamWorkaround = codecNeedsEndOfStreamWorkaround(decoderName);
|
||||||
try {
|
try {
|
||||||
long codecInitializingTimestamp = SystemClock.elapsedRealtime();
|
long codecInitializingTimestamp = SystemClock.elapsedRealtime();
|
||||||
TraceUtil.beginSection("createByCodecName(" + decoderName + ")");
|
TraceUtil.beginSection("createByCodecName(" + decoderName + ")");
|
||||||
|
|
@ -432,6 +434,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
codecReconfigured = false;
|
codecReconfigured = false;
|
||||||
codecHasQueuedBuffers = false;
|
codecHasQueuedBuffers = false;
|
||||||
codecIsAdaptive = false;
|
codecIsAdaptive = false;
|
||||||
|
codecNeedsEndOfStreamWorkaround = false;
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
||||||
codecReinitializationState = REINITIALIZATION_STATE_NONE;
|
codecReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||||
codecCounters.codecReleaseCount++;
|
codecCounters.codecReleaseCount++;
|
||||||
|
|
@ -581,8 +584,12 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
|
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
|
// 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.
|
// that it outputs any remaining buffers before we release it.
|
||||||
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
if (codecNeedsEndOfStreamWorkaround) {
|
||||||
inputIndex = -1;
|
// Do nothing.
|
||||||
|
} else {
|
||||||
|
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
inputIndex = -1;
|
||||||
|
}
|
||||||
codecReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM;
|
codecReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -634,8 +641,12 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
}
|
}
|
||||||
inputStreamEnded = true;
|
inputStreamEnded = true;
|
||||||
try {
|
try {
|
||||||
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
if (codecNeedsEndOfStreamWorkaround) {
|
||||||
inputIndex = -1;
|
// Do nothing.
|
||||||
|
} else {
|
||||||
|
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
inputIndex = -1;
|
||||||
|
}
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
notifyCryptoError(e);
|
notifyCryptoError(e);
|
||||||
throw new ExoPlaybackException(e);
|
throw new ExoPlaybackException(e);
|
||||||
|
|
@ -832,35 +843,25 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
codecCounters.outputBuffersChangedCount++;
|
codecCounters.outputBuffersChangedCount++;
|
||||||
return true;
|
return true;
|
||||||
} else if (outputIndex < 0) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decodeOnlyIndex = getDecodeOnlyIndex(outputBufferInfo.presentationTimeUs);
|
int decodeOnlyIndex = getDecodeOnlyIndex(outputBufferInfo.presentationTimeUs);
|
||||||
boolean isEndOfStream = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
|
if (processOutputBuffer(positionUs, elapsedRealtimeUs, codec, outputBuffers[outputIndex],
|
||||||
|
outputBufferInfo, outputIndex, decodeOnlyIndex != -1)) {
|
||||||
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 (decodeOnlyIndex != -1) {
|
if (decodeOnlyIndex != -1) {
|
||||||
decodeOnlyPresentationTimestamps.remove(decodeOnlyIndex);
|
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;
|
outputIndex = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -879,6 +880,21 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
MediaCodec codec, ByteBuffer buffer, MediaCodec.BufferInfo bufferInfo, int bufferIndex,
|
MediaCodec codec, ByteBuffer buffer, MediaCodec.BufferInfo bufferInfo, int bufferIndex,
|
||||||
boolean shouldSkip) throws ExoPlaybackException;
|
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) {
|
private void notifyDecoderInitializationError(final DecoderInitializationException e) {
|
||||||
if (eventHandler != null && eventListener != null) {
|
if (eventHandler != null && eventListener != null) {
|
||||||
eventHandler.post(new Runnable() {
|
eventHandler.post(new Runnable() {
|
||||||
|
|
@ -924,4 +940,20 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
return -1;
|
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