Signal end of stream in SampleHolder flags.

Also use MediaCodec buffer flag constants instead of those on MediaExtractor.

This is in preparation for merging InputBuffer and SampleHolder.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=117810136
This commit is contained in:
andrewlewis 2016-03-22 04:20:56 -07:00 committed by Oliver Woodman
parent 733f2ccd1c
commit fc716b5711
12 changed files with 54 additions and 42 deletions

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaExtractor;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -29,8 +28,8 @@ public class CTest extends TestCase {
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
public static final void testContants() { public static final void testContants() {
// Sanity check that constant values match those defined by the platform. // Sanity check that constant values match those defined by the platform.
assertEquals(MediaExtractor.SAMPLE_FLAG_SYNC, C.SAMPLE_FLAG_SYNC); assertEquals(MediaCodec.BUFFER_FLAG_KEY_FRAME, C.SAMPLE_FLAG_SYNC);
assertEquals(MediaExtractor.SAMPLE_FLAG_ENCRYPTED, C.SAMPLE_FLAG_ENCRYPTED); assertEquals(MediaCodec.BUFFER_FLAG_END_OF_STREAM, C.SAMPLE_FLAG_END_OF_STREAM);
assertEquals(MediaCodec.CRYPTO_MODE_AES_CTR, C.CRYPTO_MODE_AES_CTR); assertEquals(MediaCodec.CRYPTO_MODE_AES_CTR, C.CRYPTO_MODE_AES_CTR);
} }

View File

@ -19,7 +19,6 @@ import com.google.android.exoplayer.util.Util;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaExtractor;
/** /**
* Defines constants that are generally useful throughout the library. * Defines constants that are generally useful throughout the library.
@ -89,21 +88,26 @@ public final class C {
? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; ? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
/** /**
* @see MediaExtractor#SAMPLE_FLAG_SYNC * Indicates that a sample is a synchronization sample.
*/ */
@SuppressWarnings("InlinedApi") @SuppressWarnings("InlinedApi")
public static final int SAMPLE_FLAG_SYNC = MediaExtractor.SAMPLE_FLAG_SYNC; public static final int SAMPLE_FLAG_SYNC = MediaCodec.BUFFER_FLAG_KEY_FRAME;
/** /**
* @see MediaExtractor#SAMPLE_FLAG_ENCRYPTED * Flag for empty buffers that signal that the end of the stream was reached.
*/ */
@SuppressWarnings("InlinedApi") @SuppressWarnings("InlinedApi")
public static final int SAMPLE_FLAG_ENCRYPTED = MediaExtractor.SAMPLE_FLAG_ENCRYPTED; public static final int SAMPLE_FLAG_END_OF_STREAM = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
/**
* Indicates that a sample is (at least partially) encrypted.
*/
public static final int SAMPLE_FLAG_ENCRYPTED = 0x40000000;
/** /**
* Indicates that a sample should be decoded but not rendered. * Indicates that a sample should be decoded but not rendered.
*/ */
public static final int SAMPLE_FLAG_DECODE_ONLY = 0x8000000; public static final int SAMPLE_FLAG_DECODE_ONLY = 0x80000000;
/** /**
* A return value for methods where the end of an input was encountered. * A return value for methods where the end of an input was encountered.

View File

@ -56,8 +56,6 @@ import java.util.UUID;
@TargetApi(16) @TargetApi(16)
public final class FrameworkSampleSource implements SampleSource { public final class FrameworkSampleSource implements SampleSource {
private static final int ALLOWED_FLAGS_MASK = C.SAMPLE_FLAG_SYNC | C.SAMPLE_FLAG_ENCRYPTED;
private static final int TRACK_STATE_DISABLED = 0; private static final int TRACK_STATE_DISABLED = 0;
private static final int TRACK_STATE_ENABLED = 1; private static final int TRACK_STATE_ENABLED = 1;
private static final int TRACK_STATE_FORMAT_SENT = 2; private static final int TRACK_STATE_FORMAT_SENT = 2;
@ -196,6 +194,7 @@ public final class FrameworkSampleSource implements SampleSource {
return TrackStream.FORMAT_READ; return TrackStream.FORMAT_READ;
} }
int extractorTrackIndex = extractor.getSampleTrackIndex(); int extractorTrackIndex = extractor.getSampleTrackIndex();
sampleHolder.flags = 0;
if (extractorTrackIndex == track) { if (extractorTrackIndex == track) {
if (sampleHolder.data != null) { if (sampleHolder.data != null) {
int offset = sampleHolder.data.position(); int offset = sampleHolder.data.position();
@ -205,15 +204,22 @@ public final class FrameworkSampleSource implements SampleSource {
sampleHolder.size = 0; sampleHolder.size = 0;
} }
sampleHolder.timeUs = extractor.getSampleTime(); sampleHolder.timeUs = extractor.getSampleTime();
sampleHolder.flags = extractor.getSampleFlags() & ALLOWED_FLAGS_MASK; int flags = extractor.getSampleFlags();
if (sampleHolder.isEncrypted()) { if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
sampleHolder.flags |= C.SAMPLE_FLAG_SYNC;
}
if ((flags & MediaExtractor.SAMPLE_FLAG_ENCRYPTED) != 0) {
sampleHolder.flags |= C.SAMPLE_FLAG_ENCRYPTED;
sampleHolder.cryptoInfo.setFromExtractorV16(extractor); sampleHolder.cryptoInfo.setFromExtractorV16(extractor);
} }
pendingSeekPositionUs = C.UNKNOWN_TIME_US; pendingSeekPositionUs = C.UNKNOWN_TIME_US;
extractor.advance(); extractor.advance();
return TrackStream.SAMPLE_READ; return TrackStream.SAMPLE_READ;
} else if (extractorTrackIndex < 0) {
sampleHolder.flags |= C.SAMPLE_FLAG_END_OF_STREAM;
return TrackStream.END_OF_STREAM;
} else { } else {
return extractorTrackIndex < 0 ? TrackStream.END_OF_STREAM : TrackStream.NOTHING_READ; return TrackStream.NOTHING_READ;
} }
} }

View File

@ -50,8 +50,7 @@ public final class SampleHolder {
public int size; public int size;
/** /**
* Flags that accompany the sample. A combination of {@link C#SAMPLE_FLAG_SYNC}, * Flags that accompany the sample. A combination of the {@code C.SAMPLE_FLAG_*} constants.
* {@link C#SAMPLE_FLAG_ENCRYPTED} and {@link C#SAMPLE_FLAG_DECODE_ONLY}.
*/ */
public int flags; public int flags;

View File

@ -67,7 +67,9 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
* @param formatHolder A {@link FormatHolder} object to populate in the case of a new format. * @param formatHolder A {@link FormatHolder} object to populate in the case of a new format.
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample. * @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample.
* If the caller requires the sample data then it must ensure that {@link SampleHolder#data} * If the caller requires the sample data then it must ensure that {@link SampleHolder#data}
* references a valid output buffer. * references a valid output buffer. If the end of the stream has been reached,
* {@link TrackStream#END_OF_STREAM} will be returned and {@link C#SAMPLE_FLAG_END_OF_STREAM}
* will be set on the sample holder.
* @return The result, which can be {@link TrackStream#SAMPLE_READ}, * @return The result, which can be {@link TrackStream#SAMPLE_READ},
* {@link TrackStream#FORMAT_READ}, {@link TrackStream#NOTHING_READ} or * {@link TrackStream#FORMAT_READ}, {@link TrackStream#NOTHING_READ} or
* {@link TrackStream#END_OF_STREAM}. * {@link TrackStream#END_OF_STREAM}.

View File

@ -162,6 +162,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
@Override @Override
public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) { public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) {
if (state == STATE_END_OF_STREAM) { if (state == STATE_END_OF_STREAM) {
sampleHolder.flags = C.SAMPLE_FLAG_END_OF_STREAM;
return END_OF_STREAM; return END_OF_STREAM;
} else if (state == STATE_SEND_FORMAT) { } else if (state == STATE_SEND_FORMAT) {
formatHolder.format = format; formatHolder.format = format;

View File

@ -77,7 +77,9 @@ public interface TrackStream {
* @param formatHolder A {@link FormatHolder} to populate in the case of a new format. * @param formatHolder A {@link FormatHolder} to populate in the case of a new format.
* @param sampleHolder A {@link SampleHolder} to populate in the case of a new sample. If the * @param sampleHolder A {@link SampleHolder} to populate in the case of a new sample. If the
* caller requires the sample data then it must ensure that {@link SampleHolder#data} * caller requires the sample data then it must ensure that {@link SampleHolder#data}
* references a valid output buffer. * references a valid output buffer. If the end of the stream has been reached,
* {@link #END_OF_STREAM} will be returned and {@link C#SAMPLE_FLAG_END_OF_STREAM} will be set
* on the sample holder.
* @return The result, which can be {@link #END_OF_STREAM}, {@link #NOTHING_READ}, * @return The result, which can be {@link #END_OF_STREAM}, {@link #NOTHING_READ},
* {@link #FORMAT_READ} or {@link #SAMPLE_READ}. * {@link #FORMAT_READ} or {@link #SAMPLE_READ}.
*/ */

View File

@ -273,6 +273,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
if (!haveSamples) { if (!haveSamples) {
if (loadingFinished) { if (loadingFinished) {
sampleHolder.flags = C.SAMPLE_FLAG_END_OF_STREAM;
return END_OF_STREAM; return END_OF_STREAM;
} }
return NOTHING_READ; return NOTHING_READ;

View File

@ -460,6 +460,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
} }
if (loadingFinished) { if (loadingFinished) {
sampleHolder.flags = C.SAMPLE_FLAG_END_OF_STREAM;
return TrackStream.END_OF_STREAM; return TrackStream.END_OF_STREAM;
} }

View File

@ -337,6 +337,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
} }
if (loadingFinished) { if (loadingFinished) {
sampleHolder.flags = C.SAMPLE_FLAG_END_OF_STREAM;
return TrackStream.END_OF_STREAM; return TrackStream.END_OF_STREAM;
} }

View File

@ -20,19 +20,6 @@ package com.google.android.exoplayer.util.extensions;
*/ */
public abstract class Buffer { public abstract class Buffer {
/**
* Flag for empty input/output buffers that signal that the end of the stream was reached.
*/
public static final int FLAG_END_OF_STREAM = 1;
/**
* Flag for non-empty input buffers which signals that the decoder must be reset before decoding.
*/
public static final int FLAG_RESET = 2;
/**
* Flag for non-empty input/output buffers that should only be decoded (not rendered).
*/
public static final int FLAG_DECODE_ONLY = 4;
private int flags; private int flags;
public void reset() { public void reset() {

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer.util.extensions; package com.google.android.exoplayer.util.extensions;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import java.util.LinkedList; import java.util.LinkedList;
@ -219,16 +220,23 @@ public abstract class SimpleDecoder<I extends InputBuffer, O extends OutputBuffe
flushDecodedOutputBuffer = false; flushDecodedOutputBuffer = false;
} }
outputBuffer.reset();
if (inputBuffer.getFlag(C.SAMPLE_FLAG_END_OF_STREAM)) {
outputBuffer.setFlag(C.SAMPLE_FLAG_END_OF_STREAM);
} else {
if (inputBuffer.getFlag(C.SAMPLE_FLAG_DECODE_ONLY)) {
outputBuffer.setFlag(C.SAMPLE_FLAG_DECODE_ONLY);
}
exception = decode(inputBuffer, outputBuffer); exception = decode(inputBuffer, outputBuffer);
if (exception != null) { if (exception != null) {
// Memory barrier to ensure that the decoder exception is visible from the playback thread. // Memory barrier to ensure that the decoder exception is visible from the playback thread.
synchronized (lock) {} synchronized (lock) {}
return false; return false;
} }
}
boolean decodeOnly = outputBuffer.getFlag(Buffer.FLAG_DECODE_ONLY);
synchronized (lock) { synchronized (lock) {
if (flushDecodedOutputBuffer || decodeOnly) { if (flushDecodedOutputBuffer || outputBuffer.getFlag(C.SAMPLE_FLAG_DECODE_ONLY)) {
// If a flush occurred while decoding or the buffer was only for decoding (not presentation) // If a flush occurred while decoding or the buffer was only for decoding (not presentation)
// then make the output buffer available again rather than queueing it to be consumed. // then make the output buffer available again rather than queueing it to be consumed.
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer; availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
@ -261,10 +269,11 @@ public abstract class SimpleDecoder<I extends InputBuffer, O extends OutputBuffe
* Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}. * Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}.
* *
* @param inputBuffer The buffer to decode. * @param inputBuffer The buffer to decode.
* @param outputBuffer The output buffer to store decoded data. If the flag * @param outputBuffer The output buffer to store decoded data. The flag
* {@link Buffer#FLAG_DECODE_ONLY} is set after this method returns, any output should not be * {@link C#SAMPLE_FLAG_DECODE_ONLY} will be set if the same flag is set on
* presented. * {@code inputBuffer}, but the decoder may set/unset the flag if required. If the flag is set
* @return A decode exception if an error occurred, or null if the decode was successful. * after this method returns, any output will not be presented.
* @return A decoder exception if an error occurred, or null if decoding was successful.
*/ */
protected abstract E decode(I inputBuffer, O outputBuffer); protected abstract E decode(I inputBuffer, O outputBuffer);