use of com.google.android.exoplayer2.decoder.DecoderInputBuffer in project ExoPlayer by google.
the class FfmpegAudioDecoder method decode.
@Override
@Nullable
protected FfmpegDecoderException decode(DecoderInputBuffer inputBuffer, SimpleDecoderOutputBuffer outputBuffer, boolean reset) {
if (reset) {
nativeContext = ffmpegReset(nativeContext, extraData);
if (nativeContext == 0) {
return new FfmpegDecoderException("Error resetting (see logcat).");
}
}
ByteBuffer inputData = Util.castNonNull(inputBuffer.data);
int inputSize = inputData.limit();
ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
if (result == AUDIO_DECODER_ERROR_OTHER) {
return new FfmpegDecoderException("Error decoding (see logcat).");
} else if (result == AUDIO_DECODER_ERROR_INVALID_DATA) {
// Treat invalid data errors as non-fatal to match the behavior of MediaCodec. No output will
// be produced for this buffer, so mark it as decode-only to ensure that the audio sink's
// position is reset when more audio is produced.
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
return null;
} else if (result == 0) {
// There's no need to output empty buffers.
outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
return null;
}
if (!hasOutputFormat) {
channelCount = ffmpegGetChannelCount(nativeContext);
sampleRate = ffmpegGetSampleRate(nativeContext);
if (sampleRate == 0 && "alac".equals(codecName)) {
Assertions.checkNotNull(extraData);
// ALAC decoder did not set the sample rate in earlier versions of FFmpeg. See
// https://trac.ffmpeg.org/ticket/6096.
ParsableByteArray parsableExtraData = new ParsableByteArray(extraData);
parsableExtraData.setPosition(extraData.length - 4);
sampleRate = parsableExtraData.readUnsignedIntToInt();
}
hasOutputFormat = true;
}
outputData.position(0);
outputData.limit(result);
return null;
}
use of com.google.android.exoplayer2.decoder.DecoderInputBuffer in project ExoPlayer by google.
the class MergingMediaPeriodTest method selectTracks_withPeriodOffsets_selectTracksWithOffset_andCreatesSampleStreamsCorrectingOffset.
@Test
public void selectTracks_withPeriodOffsets_selectTracksWithOffset_andCreatesSampleStreamsCorrectingOffset() throws Exception {
MergingMediaPeriod mergingMediaPeriod = prepareMergingPeriod(new MergingPeriodDefinition(/* timeOffsetUs= */
0, /* singleSampleTimeUs= */
123_000, childFormat11, childFormat12), new MergingPeriodDefinition(/* timeOffsetUs= */
-3000, /* singleSampleTimeUs= */
456_000, childFormat21, childFormat22));
ExoTrackSelection selectionForChild1 = new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(0), /* track= */
0);
ExoTrackSelection selectionForChild2 = new FixedTrackSelection(mergingMediaPeriod.getTrackGroups().get(2), /* track= */
0);
SampleStream[] streams = new SampleStream[2];
mergingMediaPeriod.selectTracks(/* selections= */
new ExoTrackSelection[] { selectionForChild1, selectionForChild2 }, /* mayRetainStreamFlags= */
new boolean[] { false, false }, streams, /* streamResetFlags= */
new boolean[] { false, false }, /* positionUs= */
0);
mergingMediaPeriod.continueLoading(/* positionUs= */
0);
FormatHolder formatHolder = new FormatHolder();
DecoderInputBuffer inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
streams[0].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT);
streams[1].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT);
FakeMediaPeriodWithSelectTracksPosition childMediaPeriod1 = (FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(0);
assertThat(childMediaPeriod1.selectTracksPositionUs).isEqualTo(0);
assertThat(streams[0].readData(formatHolder, inputBuffer, /* readFlags= */
0)).isEqualTo(C.RESULT_BUFFER_READ);
assertThat(inputBuffer.timeUs).isEqualTo(123_000L);
FakeMediaPeriodWithSelectTracksPosition childMediaPeriod2 = (FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(1);
assertThat(childMediaPeriod2.selectTracksPositionUs).isEqualTo(3000L);
assertThat(streams[1].readData(formatHolder, inputBuffer, /* readFlags= */
0)).isEqualTo(C.RESULT_BUFFER_READ);
assertThat(inputBuffer.timeUs).isEqualTo(456_000 - 3000);
}
use of com.google.android.exoplayer2.decoder.DecoderInputBuffer in project ExoPlayer by google.
the class EventSampleStreamTest method skipDataThenUpdateStreamContinueToReadFromSkippedPosition.
/**
* Tests that {@link EventSampleStream#updateEventStream(EventStream, boolean)} will update the
* underlying event stream, but keep the timestamp the stream has skipped to, so the next {@link
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return sample data
* from the skipped position.
*/
@Test
public void skipDataThenUpdateStreamContinueToReadFromSkippedPosition() {
long presentationTimeUs1 = 1000000;
long presentationTimeUs2 = 2000000;
long presentationTimeUs3 = 3000000;
EventMessage eventMessage1 = newEventMessageWithId(1);
EventMessage eventMessage2 = newEventMessageWithId(2);
EventMessage eventMessage3 = newEventMessageWithId(3);
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE, new long[] { presentationTimeUs1, presentationTimeUs2 }, new EventMessage[] { eventMessage1, eventMessage2 });
EventStream eventStream2 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE, new long[] { presentationTimeUs1, presentationTimeUs2, presentationTimeUs3 }, new EventMessage[] { eventMessage1, eventMessage2, eventMessage3 });
EventSampleStream sampleStream = new EventSampleStream(eventStream1, FORMAT, true);
// first read - read format
readData(sampleStream);
sampleStream.skipData(presentationTimeUs2 + 1);
sampleStream.updateEventStream(eventStream2, true);
int result = readData(sampleStream);
assertThat(result).isEqualTo(C.RESULT_BUFFER_READ);
assertThat(inputBuffer.data.array()).isEqualTo(getEncodedMessage(eventMessage3));
}
use of com.google.android.exoplayer2.decoder.DecoderInputBuffer in project ExoPlayer by google.
the class EventSampleStreamTest method skipDataThenReadDataReturnDataFromSkippedPosition.
/**
* Tests that {@link EventSampleStream#skipData(long)} will skip until the given position, and the
* next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return
* sample data from that position.
*/
@Test
public void skipDataThenReadDataReturnDataFromSkippedPosition() {
long presentationTimeUs1 = 1000000;
long presentationTimeUs2 = 2000000;
EventMessage eventMessage1 = newEventMessageWithId(1);
EventMessage eventMessage2 = newEventMessageWithId(2);
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE, new long[] { presentationTimeUs1, presentationTimeUs2 }, new EventMessage[] { eventMessage1, eventMessage2 });
EventSampleStream sampleStream = new EventSampleStream(eventStream, FORMAT, false);
// first read - read format
readData(sampleStream);
int skipped = sampleStream.skipData(presentationTimeUs2);
int result = readData(sampleStream);
assertThat(skipped).isEqualTo(1);
assertThat(result).isEqualTo(C.RESULT_BUFFER_READ);
assertThat(inputBuffer.data.array()).isEqualTo(getEncodedMessage(eventMessage2));
}
use of com.google.android.exoplayer2.decoder.DecoderInputBuffer in project ExoPlayer by google.
the class TransformerBaseRenderer method feedPipelineFromInput.
/**
* Attempts to read input data and pass the input data to the sample pipeline.
*
* @return Whether it may be possible to read more data immediately by calling this method again.
* @throws TransformationException If a {@link SamplePipeline} problem occurs.
*/
@RequiresNonNull("samplePipeline")
private boolean feedPipelineFromInput() throws TransformationException {
@Nullable DecoderInputBuffer samplePipelineInputBuffer = samplePipeline.dequeueInputBuffer();
if (samplePipelineInputBuffer == null) {
return false;
}
@ReadDataResult int result = readSource(getFormatHolder(), samplePipelineInputBuffer, /* readFlags= */
0);
switch(result) {
case C.RESULT_BUFFER_READ:
samplePipelineInputBuffer.flip();
if (samplePipelineInputBuffer.isEndOfStream()) {
samplePipeline.queueInputBuffer();
return false;
}
mediaClock.updateTimeForTrackType(getTrackType(), samplePipelineInputBuffer.timeUs);
samplePipelineInputBuffer.timeUs -= streamOffsetUs;
checkStateNotNull(samplePipelineInputBuffer.data);
maybeQueueSampleToPipeline(samplePipelineInputBuffer);
return true;
case C.RESULT_FORMAT_READ:
throw new IllegalStateException("Format changes are not supported.");
case C.RESULT_NOTHING_READ:
default:
return false;
}
}
Aggregations