mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
better handling of input format change for non-adaptive codecs
* this fixes a bug when switching from HE-AAC 22050Hz to AAC 44100Hz (the AudioTrack was not reset and we were trying to send a bad number of bytes, triggering a "AudioTrack.write() called with invalid size" error) * this also improves quality switches, making it almost seamless
This commit is contained in:
parent
69c7cb09c8
commit
e8a8c49a97
@ -135,6 +135,25 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
*/
|
*/
|
||||||
private static final int RECONFIGURATION_STATE_QUEUE_PENDING = 2;
|
private static final int RECONFIGURATION_STATE_QUEUE_PENDING = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No reinit is needed
|
||||||
|
*/
|
||||||
|
private static final int REINIT_STATE_NONE = 0;
|
||||||
|
/**
|
||||||
|
* The input format has just changed. Signal an end of stream to the codec so that we can
|
||||||
|
* retrieve the very last decoded samples from the previous format.
|
||||||
|
*/
|
||||||
|
private static final int REINIT_STATE_SIGNAL_END_OF_STREAM = 1;
|
||||||
|
/**
|
||||||
|
* The end of stream has been sent, wait for the codec to acknowledge it.
|
||||||
|
*/
|
||||||
|
private static final int REINIT_STATE_WAIT_END_OF_STREAM = 2;
|
||||||
|
/**
|
||||||
|
* The last sample has been processed, we can safely reinit now.
|
||||||
|
*/
|
||||||
|
private static final int REINIT_STATE_DO_REINIT_NOW = 3;
|
||||||
|
|
||||||
|
|
||||||
public final CodecCounters codecCounters;
|
public final CodecCounters codecCounters;
|
||||||
|
|
||||||
private final DrmSessionManager drmSessionManager;
|
private final DrmSessionManager drmSessionManager;
|
||||||
@ -159,6 +178,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
private boolean openedDrmSession;
|
private boolean openedDrmSession;
|
||||||
private boolean codecReconfigured;
|
private boolean codecReconfigured;
|
||||||
private int codecReconfigurationState;
|
private int codecReconfigurationState;
|
||||||
|
private int codecReinitState;
|
||||||
|
|
||||||
private int trackIndex;
|
private int trackIndex;
|
||||||
private int sourceState;
|
private int sourceState;
|
||||||
@ -166,6 +186,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
private boolean outputStreamEnded;
|
private boolean outputStreamEnded;
|
||||||
private boolean waitingForKeys;
|
private boolean waitingForKeys;
|
||||||
private boolean waitingForFirstSyncFrame;
|
private boolean waitingForFirstSyncFrame;
|
||||||
|
private boolean hasQueuedOneInputBuffer;
|
||||||
private long currentPositionUs;
|
private long currentPositionUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,6 +215,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
formatHolder = new MediaFormatHolder();
|
formatHolder = new MediaFormatHolder();
|
||||||
decodeOnlyPresentationTimestamps = new ArrayList<Long>();
|
decodeOnlyPresentationTimestamps = new ArrayList<Long>();
|
||||||
outputBufferInfo = new MediaCodec.BufferInfo();
|
outputBufferInfo = new MediaCodec.BufferInfo();
|
||||||
|
codecReinitState = REINIT_STATE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -302,6 +324,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
inputIndex = -1;
|
inputIndex = -1;
|
||||||
outputIndex = -1;
|
outputIndex = -1;
|
||||||
waitingForFirstSyncFrame = true;
|
waitingForFirstSyncFrame = true;
|
||||||
|
hasQueuedOneInputBuffer = false;
|
||||||
codecCounters.codecInitCount++;
|
codecCounters.codecInitCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +369,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
codecReconfigured = false;
|
codecReconfigured = false;
|
||||||
codecIsAdaptive = false;
|
codecIsAdaptive = false;
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
||||||
|
codecReinitState = REINIT_STATE_NONE;
|
||||||
codecCounters.codecReleaseCount++;
|
codecCounters.codecReleaseCount++;
|
||||||
try {
|
try {
|
||||||
codec.stop();
|
codec.stop();
|
||||||
@ -493,6 +517,13 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
if (inputStreamEnded) {
|
if (inputStreamEnded) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (codecReinitState == REINIT_STATE_DO_REINIT_NOW) {
|
||||||
|
releaseCodec();
|
||||||
|
maybeInitCodec();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (inputIndex < 0) {
|
if (inputIndex < 0) {
|
||||||
inputIndex = codec.dequeueInputBuffer(0);
|
inputIndex = codec.dequeueInputBuffer(0);
|
||||||
if (inputIndex < 0) {
|
if (inputIndex < 0) {
|
||||||
@ -502,6 +533,16 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
sampleHolder.data.clear();
|
sampleHolder.data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (codecReinitState == REINIT_STATE_SIGNAL_END_OF_STREAM) {
|
||||||
|
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
inputIndex = -1;
|
||||||
|
codecReinitState = REINIT_STATE_WAIT_END_OF_STREAM;
|
||||||
|
return false;
|
||||||
|
} else if (codecReinitState != REINIT_STATE_NONE) {
|
||||||
|
// we are still waiting for the last samples to be output
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
if (waitingForKeys) {
|
if (waitingForKeys) {
|
||||||
// We've already read an encrypted sample into sampleHolder, and are waiting for keys.
|
// We've already read an encrypted sample into sampleHolder, and are waiting for keys.
|
||||||
@ -591,6 +632,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
codec.queueInputBuffer(inputIndex, 0 , bufferSize, presentationTimeUs, 0);
|
codec.queueInputBuffer(inputIndex, 0 , bufferSize, presentationTimeUs, 0);
|
||||||
}
|
}
|
||||||
inputIndex = -1;
|
inputIndex = -1;
|
||||||
|
hasQueuedOneInputBuffer = true;
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
notifyCryptoError(e);
|
notifyCryptoError(e);
|
||||||
@ -644,8 +686,12 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
codecReconfigured = true;
|
codecReconfigured = true;
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
||||||
} else {
|
} else {
|
||||||
releaseCodec();
|
if (!hasQueuedOneInputBuffer) {
|
||||||
maybeInitCodec();
|
// no need to signal end of stream if nothing has been queued, we can just reinit asap
|
||||||
|
codecReinitState = REINIT_STATE_DO_REINIT_NOW;
|
||||||
|
} else {
|
||||||
|
codecReinitState = REINIT_STATE_SIGNAL_END_OF_STREAM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,7 +779,12 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||||
outputStreamEnded = true;
|
if (codecReinitState == REINIT_STATE_WAIT_END_OF_STREAM) {
|
||||||
|
codecReinitState = REINIT_STATE_DO_REINIT_NOW;
|
||||||
|
} else {
|
||||||
|
outputStreamEnded = true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user