Rename SampleHolder to DecoderInputBuffer.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=118040127
This commit is contained in:
parent
98fb6d150d
commit
ce9b309aa1
@ -28,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(MediaCodec.BUFFER_FLAG_KEY_FRAME, C.SAMPLE_FLAG_SYNC);
|
assertEquals(MediaCodec.BUFFER_FLAG_KEY_FRAME, C.BUFFER_FLAG_KEY_FRAME);
|
||||||
assertEquals(MediaCodec.BUFFER_FLAG_END_OF_STREAM, C.SAMPLE_FLAG_END_OF_STREAM);
|
assertEquals(MediaCodec.BUFFER_FLAG_END_OF_STREAM, C.BUFFER_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length);
|
videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length);
|
||||||
for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) {
|
for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) {
|
||||||
byte[] sampleData = getOutputSampleData(i, true);
|
byte[] sampleData = getOutputSampleData(i, true);
|
||||||
int sampleFlags = SAMPLE_IS_SYNC[i] ? C.SAMPLE_FLAG_SYNC : 0;
|
int sampleFlags = SAMPLE_IS_SYNC[i] ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]);
|
long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]);
|
||||||
videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null);
|
videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null);
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length);
|
videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length);
|
||||||
for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) {
|
for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) {
|
||||||
byte[] sampleData = getOutputSampleData(i, true);
|
byte[] sampleData = getOutputSampleData(i, true);
|
||||||
int sampleFlags = C.SAMPLE_FLAG_SYNC;
|
int sampleFlags = C.BUFFER_FLAG_KEY_FRAME;
|
||||||
long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]);
|
long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]);
|
||||||
videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null);
|
videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null);
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length);
|
videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length);
|
||||||
for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) {
|
for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) {
|
||||||
byte[] sampleData = getOutputSampleData(i, false);
|
byte[] sampleData = getOutputSampleData(i, false);
|
||||||
int sampleFlags = SAMPLE_IS_SYNC[i] ? C.SAMPLE_FLAG_SYNC : 0;
|
int sampleFlags = SAMPLE_IS_SYNC[i] ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]);
|
long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]);
|
||||||
videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null);
|
videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ public class AdtsReaderTest extends TestCase {
|
|||||||
ADTS_CONTENT));
|
ADTS_CONTENT));
|
||||||
feed();
|
feed();
|
||||||
assertSampleCounts(0, 1);
|
assertSampleCounts(0, 1);
|
||||||
adtsOutput.assertSample(0, ADTS_CONTENT, 0, C.SAMPLE_FLAG_SYNC, null);
|
adtsOutput.assertSample(0, ADTS_CONTENT, 0, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNoData() throws Exception {
|
public void testNoData() throws Exception {
|
||||||
@ -120,20 +120,20 @@ public class AdtsReaderTest extends TestCase {
|
|||||||
public void testConsumeWholeId3Packet() throws Exception {
|
public void testConsumeWholeId3Packet() throws Exception {
|
||||||
feedLimited(ID3_DATA_1.length);
|
feedLimited(ID3_DATA_1.length);
|
||||||
assertSampleCounts(1, 0);
|
assertSampleCounts(1, 0);
|
||||||
id3Output.assertSample(0, ID3_DATA_1, 0, C.SAMPLE_FLAG_SYNC, null);
|
id3Output.assertSample(0, ID3_DATA_1, 0, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultiId3Packet() throws Exception {
|
public void testMultiId3Packet() throws Exception {
|
||||||
feedLimited(ID3_DATA_1.length + ID3_DATA_2.length - 1);
|
feedLimited(ID3_DATA_1.length + ID3_DATA_2.length - 1);
|
||||||
assertSampleCounts(1, 0);
|
assertSampleCounts(1, 0);
|
||||||
id3Output.assertSample(0, ID3_DATA_1, 0, C.SAMPLE_FLAG_SYNC, null);
|
id3Output.assertSample(0, ID3_DATA_1, 0, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultiId3PacketConsumed() throws Exception {
|
public void testMultiId3PacketConsumed() throws Exception {
|
||||||
feedLimited(ID3_DATA_1.length + ID3_DATA_2.length);
|
feedLimited(ID3_DATA_1.length + ID3_DATA_2.length);
|
||||||
assertSampleCounts(2, 0);
|
assertSampleCounts(2, 0);
|
||||||
id3Output.assertSample(0, ID3_DATA_1, 0, C.SAMPLE_FLAG_SYNC, null);
|
id3Output.assertSample(0, ID3_DATA_1, 0, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
id3Output.assertSample(1, ID3_DATA_2, 0, C.SAMPLE_FLAG_SYNC, null);
|
id3Output.assertSample(1, ID3_DATA_2, 0, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultiPacketConsumed() throws Exception {
|
public void testMultiPacketConsumed() throws Exception {
|
||||||
@ -145,9 +145,9 @@ public class AdtsReaderTest extends TestCase {
|
|||||||
int j = i * 2;
|
int j = i * 2;
|
||||||
assertSampleCounts(j + 2, i + 1);
|
assertSampleCounts(j + 2, i + 1);
|
||||||
|
|
||||||
id3Output.assertSample(j, ID3_DATA_1, timeUs, C.SAMPLE_FLAG_SYNC, null);
|
id3Output.assertSample(j, ID3_DATA_1, timeUs, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
id3Output.assertSample(j + 1, ID3_DATA_2, timeUs, C.SAMPLE_FLAG_SYNC, null);
|
id3Output.assertSample(j + 1, ID3_DATA_2, timeUs, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
adtsOutput.assertSample(i, ADTS_CONTENT, timeUs, C.SAMPLE_FLAG_SYNC, null);
|
adtsOutput.assertSample(i, ADTS_CONTENT, timeUs, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ public class AdtsReaderTest extends TestCase {
|
|||||||
data.setPosition(ID3_DATA_1.length + ID3_DATA_2.length);
|
data.setPosition(ID3_DATA_1.length + ID3_DATA_2.length);
|
||||||
feed();
|
feed();
|
||||||
assertSampleCounts(0, 1);
|
assertSampleCounts(0, 1);
|
||||||
adtsOutput.assertSample(0, ADTS_CONTENT, 0, C.SAMPLE_FLAG_SYNC, null);
|
adtsOutput.assertSample(0, ADTS_CONTENT, 0, C.BUFFER_FLAG_KEY_FRAME, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void feedLimited(int limit) {
|
private void feedLimited(int limit) {
|
||||||
|
@ -788,9 +788,9 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
|||||||
StreamBuilder.TEST_INITIALIZATION_VECTOR, expectedMedia);
|
StreamBuilder.TEST_INITIALIZATION_VECTOR, expectedMedia);
|
||||||
}
|
}
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
flags |= keyframe ? C.SAMPLE_FLAG_SYNC : 0;
|
flags |= keyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
flags |= invisible ? C.SAMPLE_FLAG_DECODE_ONLY : 0;
|
flags |= invisible ? C.BUFFER_FLAG_DECODE_ONLY : 0;
|
||||||
flags |= encryptionKey != null ? C.SAMPLE_FLAG_ENCRYPTED : 0;
|
flags |= encryptionKey != null ? C.BUFFER_FLAG_ENCRYPTED : 0;
|
||||||
output.assertSample(index, expectedMedia, timeUs, flags, encryptionKey);
|
output.assertSample(index, expectedMedia, timeUs, flags, encryptionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,26 +88,26 @@ public final class C {
|
|||||||
? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
|
? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a sample is a synchronization sample.
|
* Indicates that a buffer holds a synchronization sample.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("InlinedApi")
|
@SuppressWarnings("InlinedApi")
|
||||||
public static final int SAMPLE_FLAG_SYNC = MediaCodec.BUFFER_FLAG_KEY_FRAME;
|
public static final int BUFFER_FLAG_KEY_FRAME = MediaCodec.BUFFER_FLAG_KEY_FRAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag for empty buffers that signal that the end of the stream was reached.
|
* Flag for empty buffers that signal that the end of the stream was reached.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("InlinedApi")
|
@SuppressWarnings("InlinedApi")
|
||||||
public static final int SAMPLE_FLAG_END_OF_STREAM = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
|
public static final int BUFFER_FLAG_END_OF_STREAM = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a sample is (at least partially) encrypted.
|
* Indicates that a buffer is (at least partially) encrypted.
|
||||||
*/
|
*/
|
||||||
public static final int SAMPLE_FLAG_ENCRYPTED = 0x40000000;
|
public static final int BUFFER_FLAG_ENCRYPTED = 0x40000000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a sample should be decoded but not rendered.
|
* Indicates that a buffer should be decoded but not rendered.
|
||||||
*/
|
*/
|
||||||
public static final int SAMPLE_FLAG_DECODE_ONLY = 0x80000000;
|
public static final int BUFFER_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.
|
||||||
|
@ -20,9 +20,9 @@ import com.google.android.exoplayer.util.Buffer;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds sample data and corresponding metadata.
|
* Holds input for a decoder and corresponding metadata.
|
||||||
*/
|
*/
|
||||||
public class SampleHolder extends Buffer {
|
public class DecoderInputBuffer extends Buffer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disallows buffer replacement.
|
* Disallows buffer replacement.
|
||||||
@ -40,17 +40,17 @@ public class SampleHolder extends Buffer {
|
|||||||
public static final int BUFFER_REPLACEMENT_MODE_DIRECT = 2;
|
public static final int BUFFER_REPLACEMENT_MODE_DIRECT = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link CryptoInfo} for encrypted samples.
|
* {@link CryptoInfo} for encrypted data.
|
||||||
*/
|
*/
|
||||||
public final CryptoInfo cryptoInfo;
|
public final CryptoInfo cryptoInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A buffer holding the sample data, or {@code null} if no sample data has been set.
|
* The buffer's data, or {@code null} if no data has been set.
|
||||||
*/
|
*/
|
||||||
public ByteBuffer data;
|
public ByteBuffer data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size of the sample in bytes.
|
* The size of the data in bytes.
|
||||||
*/
|
*/
|
||||||
public int size;
|
public int size;
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ public class SampleHolder extends Buffer {
|
|||||||
* of {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and
|
* of {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and
|
||||||
* {@link #BUFFER_REPLACEMENT_MODE_DIRECT}.
|
* {@link #BUFFER_REPLACEMENT_MODE_DIRECT}.
|
||||||
*/
|
*/
|
||||||
public SampleHolder(int bufferReplacementMode) {
|
public DecoderInputBuffer(int bufferReplacementMode) {
|
||||||
this.cryptoInfo = new CryptoInfo();
|
this.cryptoInfo = new CryptoInfo();
|
||||||
this.bufferReplacementMode = bufferReplacementMode;
|
this.bufferReplacementMode = bufferReplacementMode;
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ public class SampleHolder extends Buffer {
|
|||||||
*/
|
*/
|
||||||
public void ensureSpaceForWrite(int length) throws IllegalStateException {
|
public void ensureSpaceForWrite(int length) throws IllegalStateException {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
data = createReplacementBuffer(length);
|
data = createReplacementByteBuffer(length);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check whether the current buffer is sufficient.
|
// Check whether the current buffer is sufficient.
|
||||||
@ -96,7 +96,7 @@ public class SampleHolder extends Buffer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Instantiate a new buffer if possible.
|
// Instantiate a new buffer if possible.
|
||||||
ByteBuffer newData = createReplacementBuffer(requiredCapacity);
|
ByteBuffer newData = createReplacementByteBuffer(requiredCapacity);
|
||||||
// Copy data up to the current position from the old buffer to the new one.
|
// Copy data up to the current position from the old buffer to the new one.
|
||||||
if (position > 0) {
|
if (position > 0) {
|
||||||
data.position(0);
|
data.position(0);
|
||||||
@ -108,10 +108,10 @@ public class SampleHolder extends Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the sample has the {@link C#SAMPLE_FLAG_ENCRYPTED} flag set.
|
* Returns whether the {@link C#BUFFER_FLAG_ENCRYPTED} flag is set.
|
||||||
*/
|
*/
|
||||||
public final boolean isEncrypted() {
|
public final boolean isEncrypted() {
|
||||||
return getFlag(C.SAMPLE_FLAG_ENCRYPTED);
|
return getFlag(C.BUFFER_FLAG_ENCRYPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -122,7 +122,7 @@ public class SampleHolder extends Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuffer createReplacementBuffer(int requiredCapacity) {
|
private ByteBuffer createReplacementByteBuffer(int requiredCapacity) {
|
||||||
if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_NORMAL) {
|
if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_NORMAL) {
|
||||||
return ByteBuffer.allocate(requiredCapacity);
|
return ByteBuffer.allocate(requiredCapacity);
|
||||||
} else if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DIRECT) {
|
} else if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DIRECT) {
|
@ -212,7 +212,7 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
return TrackStream.NO_RESET;
|
return TrackStream.NO_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ int readData(int track, FormatHolder formatHolder, SampleHolder sampleHolder) {
|
/* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED);
|
Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED);
|
||||||
if (pendingResets[track]) {
|
if (pendingResets[track]) {
|
||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
@ -225,28 +225,28 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
}
|
}
|
||||||
int extractorTrackIndex = extractor.getSampleTrackIndex();
|
int extractorTrackIndex = extractor.getSampleTrackIndex();
|
||||||
if (extractorTrackIndex == track) {
|
if (extractorTrackIndex == track) {
|
||||||
if (sampleHolder.data != null) {
|
if (buffer.data != null) {
|
||||||
int offset = sampleHolder.data.position();
|
int offset = buffer.data.position();
|
||||||
sampleHolder.size = extractor.readSampleData(sampleHolder.data, offset);
|
buffer.size = extractor.readSampleData(buffer.data, offset);
|
||||||
sampleHolder.data.position(offset + sampleHolder.size);
|
buffer.data.position(offset + buffer.size);
|
||||||
} else {
|
} else {
|
||||||
sampleHolder.size = 0;
|
buffer.size = 0;
|
||||||
}
|
}
|
||||||
sampleHolder.timeUs = extractor.getSampleTime();
|
buffer.timeUs = extractor.getSampleTime();
|
||||||
int flags = extractor.getSampleFlags();
|
int flags = extractor.getSampleFlags();
|
||||||
if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
|
if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_SYNC);
|
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||||
}
|
}
|
||||||
if ((flags & MediaExtractor.SAMPLE_FLAG_ENCRYPTED) != 0) {
|
if ((flags & MediaExtractor.SAMPLE_FLAG_ENCRYPTED) != 0) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_ENCRYPTED);
|
buffer.addFlag(C.BUFFER_FLAG_ENCRYPTED);
|
||||||
sampleHolder.cryptoInfo.setFromExtractorV16(extractor);
|
buffer.cryptoInfo.setFromExtractorV16(extractor);
|
||||||
}
|
}
|
||||||
pendingSeekPositionUs = C.UNKNOWN_TIME_US;
|
pendingSeekPositionUs = C.UNKNOWN_TIME_US;
|
||||||
extractor.advance();
|
extractor.advance();
|
||||||
return TrackStream.SAMPLE_READ;
|
return TrackStream.BUFFER_READ;
|
||||||
} else if (extractorTrackIndex < 0) {
|
} else if (extractorTrackIndex < 0) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
return TrackStream.END_OF_STREAM;
|
return TrackStream.BUFFER_READ;
|
||||||
} else {
|
} else {
|
||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
@ -392,8 +392,8 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
return FrameworkSampleSource.this.readData(track, formatHolder, sampleHolder);
|
return FrameworkSampleSource.this.readData(track, formatHolder, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
private final MediaCodecSelector mediaCodecSelector;
|
private final MediaCodecSelector mediaCodecSelector;
|
||||||
private final DrmSessionManager drmSessionManager;
|
private final DrmSessionManager drmSessionManager;
|
||||||
private final boolean playClearSamplesWithoutKeys;
|
private final boolean playClearSamplesWithoutKeys;
|
||||||
private final SampleHolder sampleHolder;
|
private final DecoderInputBuffer buffer;
|
||||||
private final FormatHolder formatHolder;
|
private final FormatHolder formatHolder;
|
||||||
private final List<Long> decodeOnlyPresentationTimestamps;
|
private final List<Long> decodeOnlyPresentationTimestamps;
|
||||||
private final MediaCodec.BufferInfo outputBufferInfo;
|
private final MediaCodec.BufferInfo outputBufferInfo;
|
||||||
@ -255,7 +255,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
codecCounters = new CodecCounters();
|
codecCounters = new CodecCounters();
|
||||||
sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DISABLED);
|
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
||||||
formatHolder = new FormatHolder();
|
formatHolder = new FormatHolder();
|
||||||
decodeOnlyPresentationTimestamps = new ArrayList<>();
|
decodeOnlyPresentationTimestamps = new ArrayList<>();
|
||||||
outputBufferInfo = new MediaCodec.BufferInfo();
|
outputBufferInfo = new MediaCodec.BufferInfo();
|
||||||
@ -554,8 +554,8 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
if (inputIndex < 0) {
|
if (inputIndex < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sampleHolder.data = inputBuffers[inputIndex];
|
buffer.data = inputBuffers[inputIndex];
|
||||||
sampleHolder.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
|
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
|
||||||
@ -574,19 +574,19 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
|
|
||||||
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 buffer, and are waiting for keys.
|
||||||
result = TrackStream.SAMPLE_READ;
|
result = TrackStream.BUFFER_READ;
|
||||||
} else {
|
} else {
|
||||||
// For adaptive reconfiguration OMX decoders expect all reconfiguration data to be supplied
|
// For adaptive reconfiguration OMX decoders expect all reconfiguration data to be supplied
|
||||||
// at the start of the buffer that also contains the first frame in the new format.
|
// at the start of the buffer that also contains the first frame in the new format.
|
||||||
if (codecReconfigurationState == RECONFIGURATION_STATE_WRITE_PENDING) {
|
if (codecReconfigurationState == RECONFIGURATION_STATE_WRITE_PENDING) {
|
||||||
for (int i = 0; i < format.initializationData.size(); i++) {
|
for (int i = 0; i < format.initializationData.size(); i++) {
|
||||||
byte[] data = format.initializationData.get(i);
|
byte[] data = format.initializationData.get(i);
|
||||||
sampleHolder.data.put(data);
|
buffer.data.put(data);
|
||||||
}
|
}
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
|
||||||
}
|
}
|
||||||
result = readSource(formatHolder, sampleHolder);
|
result = readSource(formatHolder, buffer);
|
||||||
if (firstFeed && sourceState == SOURCE_STATE_READY && result == TrackStream.NOTHING_READ) {
|
if (firstFeed && sourceState == SOURCE_STATE_READY && result == TrackStream.NOTHING_READ) {
|
||||||
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
|
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
|
||||||
}
|
}
|
||||||
@ -599,18 +599,20 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
||||||
// We received two formats in a row. Clear the current buffer of any reconfiguration data
|
// We received two formats in a row. Clear the current buffer of any reconfiguration data
|
||||||
// associated with the first format.
|
// associated with the first format.
|
||||||
sampleHolder.clear();
|
buffer.clear();
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
||||||
}
|
}
|
||||||
onInputFormatChanged(formatHolder);
|
onInputFormatChanged(formatHolder);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (result == TrackStream.END_OF_STREAM) {
|
|
||||||
|
// We've read a buffer.
|
||||||
|
if (buffer.isEndOfStream()) {
|
||||||
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
||||||
// We received a new format immediately before the end of the stream. We need to clear
|
// We received a new format immediately before the end of the stream. We need to clear
|
||||||
// the corresponding reconfiguration data from the current buffer, but re-write it into
|
// the corresponding reconfiguration data from the current buffer, but re-write it into
|
||||||
// a subsequent buffer if there are any (e.g. if the user seeks backwards).
|
// a subsequent buffer if there are any (e.g. if the user seeks backwards).
|
||||||
sampleHolder.clear();
|
buffer.clear();
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
|
||||||
}
|
}
|
||||||
inputStreamEnded = true;
|
inputStreamEnded = true;
|
||||||
@ -632,30 +634,30 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean sampleEncrypted = sampleHolder.isEncrypted();
|
boolean bufferEncrypted = buffer.isEncrypted();
|
||||||
waitingForKeys = shouldWaitForKeys(sampleEncrypted);
|
waitingForKeys = shouldWaitForKeys(bufferEncrypted);
|
||||||
if (waitingForKeys) {
|
if (waitingForKeys) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (codecNeedsDiscardToSpsWorkaround && !sampleEncrypted) {
|
if (codecNeedsDiscardToSpsWorkaround && !bufferEncrypted) {
|
||||||
NalUnitUtil.discardToSps(sampleHolder.data);
|
NalUnitUtil.discardToSps(buffer.data);
|
||||||
if (sampleHolder.data.position() == 0) {
|
if (buffer.data.position() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
codecNeedsDiscardToSpsWorkaround = false;
|
codecNeedsDiscardToSpsWorkaround = false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int bufferSize = sampleHolder.data.position();
|
int bufferSize = buffer.data.position();
|
||||||
int adaptiveReconfigurationBytes = bufferSize - sampleHolder.size;
|
int adaptiveReconfigurationBytes = bufferSize - buffer.size;
|
||||||
long presentationTimeUs = sampleHolder.timeUs;
|
long presentationTimeUs = buffer.timeUs;
|
||||||
if (sampleHolder.isDecodeOnly()) {
|
if (buffer.isDecodeOnly()) {
|
||||||
decodeOnlyPresentationTimestamps.add(presentationTimeUs);
|
decodeOnlyPresentationTimestamps.add(presentationTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
onQueuedInputBuffer(presentationTimeUs, sampleHolder.data, bufferSize, sampleEncrypted);
|
onQueuedInputBuffer(presentationTimeUs, buffer.data, bufferSize, bufferEncrypted);
|
||||||
|
|
||||||
if (sampleEncrypted) {
|
if (bufferEncrypted) {
|
||||||
MediaCodec.CryptoInfo cryptoInfo = getFrameworkCryptoInfo(sampleHolder,
|
MediaCodec.CryptoInfo cryptoInfo = getFrameworkCryptoInfo(buffer,
|
||||||
adaptiveReconfigurationBytes);
|
adaptiveReconfigurationBytes);
|
||||||
codec.queueSecureInputBuffer(inputIndex, 0, cryptoInfo, presentationTimeUs, 0);
|
codec.queueSecureInputBuffer(inputIndex, 0, cryptoInfo, presentationTimeUs, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -672,9 +674,9 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaCodec.CryptoInfo getFrameworkCryptoInfo(SampleHolder sampleHolder,
|
private static MediaCodec.CryptoInfo getFrameworkCryptoInfo(DecoderInputBuffer buffer,
|
||||||
int adaptiveReconfigurationBytes) {
|
int adaptiveReconfigurationBytes) {
|
||||||
MediaCodec.CryptoInfo cryptoInfo = sampleHolder.cryptoInfo.getFrameworkCryptoInfoV16();
|
MediaCodec.CryptoInfo cryptoInfo = buffer.cryptoInfo.getFrameworkCryptoInfoV16();
|
||||||
if (adaptiveReconfigurationBytes == 0) {
|
if (adaptiveReconfigurationBytes == 0) {
|
||||||
return cryptoInfo;
|
return cryptoInfo;
|
||||||
}
|
}
|
||||||
@ -688,7 +690,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
return cryptoInfo;
|
return cryptoInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldWaitForKeys(boolean sampleEncrypted) throws ExoPlaybackException {
|
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
||||||
if (!openedDrmSession) {
|
if (!openedDrmSession) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -697,7 +699,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
throw ExoPlaybackException.createForRenderer(drmSessionManager.getError(), getIndex());
|
throw ExoPlaybackException.createForRenderer(drmSessionManager.getError(), getIndex());
|
||||||
}
|
}
|
||||||
if (drmManagerState != DrmSessionManager.STATE_OPENED_WITH_KEYS &&
|
if (drmManagerState != DrmSessionManager.STATE_OPENED_WITH_KEYS &&
|
||||||
(sampleEncrypted || !playClearSamplesWithoutKeys)) {
|
(bufferEncrypted || !playClearSamplesWithoutKeys)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -758,11 +760,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
*
|
*
|
||||||
* @param presentationTimeUs The timestamp associated with the input buffer.
|
* @param presentationTimeUs The timestamp associated with the input buffer.
|
||||||
* @param buffer The buffer to be queued.
|
* @param buffer The buffer to be queued.
|
||||||
* @param bufferSize the size of the sample data stored in the buffer.
|
* @param bufferSize The size of the sample data stored in the buffer.
|
||||||
* @param sampleEncrypted Whether the sample data is encrypted.
|
* @param bufferEncrypted Whether the buffer is encrypted.
|
||||||
*/
|
*/
|
||||||
protected void onQueuedInputBuffer(
|
protected void onQueuedInputBuffer(long presentationTimeUs, ByteBuffer buffer, int bufferSize,
|
||||||
long presentationTimeUs, ByteBuffer buffer, int bufferSize, boolean sampleEncrypted) {
|
boolean bufferEncrypted) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,18 +64,10 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
|||||||
/**
|
/**
|
||||||
* Reads from the enabled upstream source.
|
* Reads from the enabled upstream source.
|
||||||
*
|
*
|
||||||
* @param formatHolder A {@link FormatHolder} object to populate in the case of a new format.
|
* @see TrackStream#readData(FormatHolder, DecoderInputBuffer)
|
||||||
* @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}
|
|
||||||
* 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},
|
|
||||||
* {@link TrackStream#FORMAT_READ}, {@link TrackStream#NOTHING_READ} or
|
|
||||||
* {@link TrackStream#END_OF_STREAM}.
|
|
||||||
*/
|
*/
|
||||||
protected final int readSource(FormatHolder formatHolder, SampleHolder sampleHolder) {
|
protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
return trackStream.readData(formatHolder, sampleHolder);
|
return trackStream.readData(formatHolder, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abstract methods.
|
// Abstract methods.
|
||||||
|
@ -186,10 +186,10 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
return END_OF_STREAM;
|
return BUFFER_READ;
|
||||||
} else if (streamState == STREAM_STATE_SEND_FORMAT) {
|
} else if (streamState == STREAM_STATE_SEND_FORMAT) {
|
||||||
formatHolder.format = format;
|
formatHolder.format = format;
|
||||||
streamState = STREAM_STATE_SEND_SAMPLE;
|
streamState = STREAM_STATE_SEND_SAMPLE;
|
||||||
@ -200,13 +200,13 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
|||||||
if (!loadingFinished) {
|
if (!loadingFinished) {
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
} else {
|
} else {
|
||||||
sampleHolder.timeUs = 0;
|
buffer.timeUs = 0;
|
||||||
sampleHolder.size = sampleSize;
|
buffer.size = sampleSize;
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_SYNC);
|
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||||
sampleHolder.ensureSpaceForWrite(sampleHolder.size);
|
buffer.ensureSpaceForWrite(buffer.size);
|
||||||
sampleHolder.data.put(sampleData, 0, sampleSize);
|
buffer.data.put(sampleData, 0, sampleSize);
|
||||||
streamState = STREAM_STATE_END_OF_STREAM;
|
streamState = STREAM_STATE_END_OF_STREAM;
|
||||||
return SAMPLE_READ;
|
return BUFFER_READ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,22 +22,18 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public interface TrackStream {
|
public interface TrackStream {
|
||||||
|
|
||||||
/**
|
|
||||||
* The end of stream has been reached.
|
|
||||||
*/
|
|
||||||
int END_OF_STREAM = -1;
|
|
||||||
/**
|
/**
|
||||||
* Nothing was read.
|
* Nothing was read.
|
||||||
*/
|
*/
|
||||||
int NOTHING_READ = -2;
|
int NOTHING_READ = -1;
|
||||||
/**
|
/**
|
||||||
* A sample was read.
|
* The buffer was populated.
|
||||||
*/
|
*/
|
||||||
int SAMPLE_READ = -3;
|
int BUFFER_READ = -2;
|
||||||
/**
|
/**
|
||||||
* A format was read.
|
* A format was read.
|
||||||
*/
|
*/
|
||||||
int FORMAT_READ = -4;
|
int FORMAT_READ = -3;
|
||||||
/**
|
/**
|
||||||
* Returned from {@link #readReset()} to indicate no reset is required.
|
* Returned from {@link #readReset()} to indicate no reset is required.
|
||||||
*/
|
*/
|
||||||
@ -46,8 +42,8 @@ public interface TrackStream {
|
|||||||
/**
|
/**
|
||||||
* Returns whether data is available to be read.
|
* Returns whether data is available to be read.
|
||||||
* <p>
|
* <p>
|
||||||
* Note: If the stream has ended then {@link #END_OF_STREAM} can always be read from
|
* Note: If the stream has ended then a buffer with the end of stream flag can always be read from
|
||||||
* {@link #readData(FormatHolder, SampleHolder)}. Hence an ended stream is always ready.
|
* {@link #readData(FormatHolder, DecoderInputBuffer)}. Hence an ended stream is always ready.
|
||||||
*
|
*
|
||||||
* @return True if data is available to be read. False otherwise.
|
* @return True if data is available to be read. False otherwise.
|
||||||
*/
|
*/
|
||||||
@ -69,20 +65,19 @@ public interface TrackStream {
|
|||||||
long readReset();
|
long readReset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to read the next format or sample.
|
* Attempts to read from the stream.
|
||||||
* <p>
|
* <p>
|
||||||
* This method will always return {@link #NOTHING_READ} in the case that there's a pending
|
* This method will always return {@link #NOTHING_READ} in the case that there's a pending
|
||||||
* discontinuity to be read from {@link #readReset} for the specified track.
|
* discontinuity to be read from {@link #readReset} for the specified track.
|
||||||
*
|
*
|
||||||
* @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 reading a format.
|
||||||
* @param sampleHolder A {@link SampleHolder} to populate in the case of a new sample. If the
|
* @param buffer A {@link DecoderInputBuffer} to populate in the case of reading a sample or the
|
||||||
* caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
* end of the stream. If the caller requires the sample data then it must ensure that
|
||||||
* references a valid output buffer. If the end of the stream has been reached,
|
* {@link DecoderInputBuffer#data} references a valid buffer. If the end of the stream has
|
||||||
* {@link #END_OF_STREAM} will be returned and {@link C#SAMPLE_FLAG_END_OF_STREAM} will be set
|
* been reached, the {@link C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer.
|
||||||
* on the sample holder.
|
* @return The result, which can be {@link #NOTHING_READ}, {@link #FORMAT_READ} or
|
||||||
* @return The result, which can be {@link #END_OF_STREAM}, {@link #NOTHING_READ},
|
* {@link #BUFFER_READ}.
|
||||||
* {@link #FORMAT_READ} or {@link #SAMPLE_READ}.
|
|
||||||
*/
|
*/
|
||||||
int readData(FormatHolder formatHolder, SampleHolder sampleHolder);
|
int readData(FormatHolder formatHolder, DecoderInputBuffer buffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
package com.google.android.exoplayer.chunk;
|
package com.google.android.exoplayer.chunk;
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.LoadControl;
|
import com.google.android.exoplayer.LoadControl;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
@ -246,7 +246,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
if (pendingReset || isPendingReset()) {
|
if (pendingReset || isPendingReset()) {
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
@ -277,18 +277,18 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
|
|
||||||
if (!haveSamples) {
|
if (!haveSamples) {
|
||||||
if (loadingFinished) {
|
if (loadingFinished) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
return END_OF_STREAM;
|
return BUFFER_READ;
|
||||||
}
|
}
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleQueue.getSample(sampleHolder)) {
|
if (sampleQueue.getSample(buffer)) {
|
||||||
if (sampleHolder.timeUs < lastSeekPositionUs) {
|
if (buffer.timeUs < lastSeekPositionUs) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_DECODE_ONLY);
|
buffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||||
}
|
}
|
||||||
onSampleRead(currentChunk, sampleHolder);
|
onSampleRead(currentChunk, buffer);
|
||||||
return SAMPLE_READ;
|
return BUFFER_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
@ -395,9 +395,9 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
* the sample is returned.
|
* the sample is returned.
|
||||||
*
|
*
|
||||||
* @param mediaChunk The chunk from which the sample was obtained.
|
* @param mediaChunk The chunk from which the sample was obtained.
|
||||||
* @param sampleHolder Holds the read sample.
|
* @param buffer Holds the read sample.
|
||||||
*/
|
*/
|
||||||
protected void onSampleRead(MediaChunk mediaChunk, SampleHolder sampleHolder) {
|
protected void onSampleRead(MediaChunk mediaChunk, DecoderInputBuffer buffer) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
|
|||||||
result = getOutput().sampleData(extractorInput, Integer.MAX_VALUE, true);
|
result = getOutput().sampleData(extractorInput, Integer.MAX_VALUE, true);
|
||||||
}
|
}
|
||||||
int sampleSize = bytesLoaded;
|
int sampleSize = bytesLoaded;
|
||||||
getOutput().sampleMetadata(startTimeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
|
getOutput().sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||||
} finally {
|
} finally {
|
||||||
dataSource.close();
|
dataSource.close();
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.extractor;
|
package com.google.android.exoplayer.extractor;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.upstream.Allocator;
|
import com.google.android.exoplayer.upstream.Allocator;
|
||||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ import java.io.IOException;
|
|||||||
public class DefaultTrackOutput implements TrackOutput {
|
public class DefaultTrackOutput implements TrackOutput {
|
||||||
|
|
||||||
private final RollingSampleBuffer rollingBuffer;
|
private final RollingSampleBuffer rollingBuffer;
|
||||||
private final SampleHolder sampleInfoHolder;
|
private final DecoderInputBuffer sampleBuffer;
|
||||||
|
|
||||||
// Accessed only by the consuming thread.
|
// Accessed only by the consuming thread.
|
||||||
private boolean needKeyframe;
|
private boolean needKeyframe;
|
||||||
@ -45,7 +45,7 @@ public class DefaultTrackOutput implements TrackOutput {
|
|||||||
*/
|
*/
|
||||||
public DefaultTrackOutput(Allocator allocator) {
|
public DefaultTrackOutput(Allocator allocator) {
|
||||||
rollingBuffer = new RollingSampleBuffer(allocator);
|
rollingBuffer = new RollingSampleBuffer(allocator);
|
||||||
sampleInfoHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DISABLED);
|
sampleBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
||||||
needKeyframe = true;
|
needKeyframe = true;
|
||||||
lastReadTimeUs = Long.MIN_VALUE;
|
lastReadTimeUs = Long.MIN_VALUE;
|
||||||
spliceOutTimeUs = Long.MIN_VALUE;
|
spliceOutTimeUs = Long.MIN_VALUE;
|
||||||
@ -79,7 +79,7 @@ public class DefaultTrackOutput implements TrackOutput {
|
|||||||
*/
|
*/
|
||||||
public void discardUpstreamSamples(int discardFromIndex) {
|
public void discardUpstreamSamples(int discardFromIndex) {
|
||||||
rollingBuffer.discardUpstreamSamples(discardFromIndex);
|
rollingBuffer.discardUpstreamSamples(discardFromIndex);
|
||||||
largestParsedTimestampUs = rollingBuffer.peekSample(sampleInfoHolder) ? sampleInfoHolder.timeUs
|
largestParsedTimestampUs = rollingBuffer.peekSample(sampleBuffer) ? sampleBuffer.timeUs
|
||||||
: Long.MIN_VALUE;
|
: Long.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,23 +122,23 @@ public class DefaultTrackOutput implements TrackOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the next sample from the head of the queue, writing it into the provided holder.
|
* Removes the next sample from the head of the queue, writing it into the provided buffer.
|
||||||
* <p>
|
* <p>
|
||||||
* The first sample returned is guaranteed to be a keyframe, since any non-keyframe samples
|
* The first sample returned is guaranteed to be a keyframe, since any non-keyframe samples
|
||||||
* queued prior to the first keyframe are discarded.
|
* queued prior to the first keyframe are discarded.
|
||||||
*
|
*
|
||||||
* @param holder A {@link SampleHolder} into which the sample should be read.
|
* @param buffer A {@link DecoderInputBuffer} into which the sample should be read.
|
||||||
* @return True if a sample was read. False otherwise.
|
* @return True if a sample was read. False otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean getSample(SampleHolder holder) {
|
public boolean getSample(DecoderInputBuffer buffer) {
|
||||||
boolean foundEligibleSample = advanceToEligibleSample();
|
boolean foundEligibleSample = advanceToEligibleSample();
|
||||||
if (!foundEligibleSample) {
|
if (!foundEligibleSample) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Write the sample into the holder.
|
// Write the sample into the buffer.
|
||||||
rollingBuffer.readSample(holder);
|
rollingBuffer.readSample(buffer);
|
||||||
needKeyframe = false;
|
needKeyframe = false;
|
||||||
lastReadTimeUs = holder.timeUs;
|
lastReadTimeUs = buffer.timeUs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ public class DefaultTrackOutput implements TrackOutput {
|
|||||||
* @param timeUs The time up to which samples should be discarded, in microseconds.
|
* @param timeUs The time up to which samples should be discarded, in microseconds.
|
||||||
*/
|
*/
|
||||||
public void discardUntil(long timeUs) {
|
public void discardUntil(long timeUs) {
|
||||||
while (rollingBuffer.peekSample(sampleInfoHolder) && sampleInfoHolder.timeUs < timeUs) {
|
while (rollingBuffer.peekSample(sampleBuffer) && sampleBuffer.timeUs < timeUs) {
|
||||||
rollingBuffer.skipSample();
|
rollingBuffer.skipSample();
|
||||||
// We're discarding one or more samples. A subsequent read will need to start at a keyframe.
|
// We're discarding one or more samples. A subsequent read will need to start at a keyframe.
|
||||||
needKeyframe = true;
|
needKeyframe = true;
|
||||||
@ -178,22 +178,22 @@ public class DefaultTrackOutput implements TrackOutput {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
long firstPossibleSpliceTime;
|
long firstPossibleSpliceTime;
|
||||||
if (rollingBuffer.peekSample(sampleInfoHolder)) {
|
if (rollingBuffer.peekSample(sampleBuffer)) {
|
||||||
firstPossibleSpliceTime = sampleInfoHolder.timeUs;
|
firstPossibleSpliceTime = sampleBuffer.timeUs;
|
||||||
} else {
|
} else {
|
||||||
firstPossibleSpliceTime = lastReadTimeUs + 1;
|
firstPossibleSpliceTime = lastReadTimeUs + 1;
|
||||||
}
|
}
|
||||||
RollingSampleBuffer nextRollingBuffer = nextQueue.rollingBuffer;
|
RollingSampleBuffer nextRollingBuffer = nextQueue.rollingBuffer;
|
||||||
while (nextRollingBuffer.peekSample(sampleInfoHolder)
|
while (nextRollingBuffer.peekSample(sampleBuffer)
|
||||||
&& (sampleInfoHolder.timeUs < firstPossibleSpliceTime || !sampleInfoHolder.isSyncFrame())) {
|
&& (sampleBuffer.timeUs < firstPossibleSpliceTime || !sampleBuffer.isKeyFrame())) {
|
||||||
// Discard samples from the next queue for as long as they are before the earliest possible
|
// Discard samples from the next queue for as long as they are before the earliest possible
|
||||||
// splice time, or not keyframes.
|
// splice time, or not keyframes.
|
||||||
nextRollingBuffer.skipSample();
|
nextRollingBuffer.skipSample();
|
||||||
}
|
}
|
||||||
if (nextRollingBuffer.peekSample(sampleInfoHolder)) {
|
if (nextRollingBuffer.peekSample(sampleBuffer)) {
|
||||||
// We've found a keyframe in the next queue that can serve as the splice point. Set the
|
// We've found a keyframe in the next queue that can serve as the splice point. Set the
|
||||||
// splice point now.
|
// splice point now.
|
||||||
spliceOutTimeUs = sampleInfoHolder.timeUs;
|
spliceOutTimeUs = sampleBuffer.timeUs;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -206,17 +206,17 @@ public class DefaultTrackOutput implements TrackOutput {
|
|||||||
* buffer has been emptied.
|
* buffer has been emptied.
|
||||||
*/
|
*/
|
||||||
private boolean advanceToEligibleSample() {
|
private boolean advanceToEligibleSample() {
|
||||||
boolean haveNext = rollingBuffer.peekSample(sampleInfoHolder);
|
boolean haveNext = rollingBuffer.peekSample(sampleBuffer);
|
||||||
if (needKeyframe) {
|
if (needKeyframe) {
|
||||||
while (haveNext && !sampleInfoHolder.isSyncFrame()) {
|
while (haveNext && !sampleBuffer.isKeyFrame()) {
|
||||||
rollingBuffer.skipSample();
|
rollingBuffer.skipSample();
|
||||||
haveNext = rollingBuffer.peekSample(sampleInfoHolder);
|
haveNext = rollingBuffer.peekSample(sampleBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!haveNext) {
|
if (!haveNext) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (spliceOutTimeUs != Long.MIN_VALUE && sampleInfoHolder.timeUs >= spliceOutTimeUs) {
|
if (spliceOutTimeUs != Long.MIN_VALUE && sampleBuffer.timeUs >= spliceOutTimeUs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
package com.google.android.exoplayer.extractor;
|
package com.google.android.exoplayer.extractor;
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.ParserException;
|
import com.google.android.exoplayer.ParserException;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
@ -445,7 +445,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
return TrackStream.NO_RESET;
|
return TrackStream.NO_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ int readData(int track, FormatHolder formatHolder, SampleHolder sampleHolder) {
|
/* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
if (pendingResets[track] || isPendingReset()) {
|
if (pendingResets[track] || isPendingReset()) {
|
||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
@ -458,22 +458,22 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
return TrackStream.FORMAT_READ;
|
return TrackStream.FORMAT_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleQueue.getSample(sampleHolder)) {
|
if (sampleQueue.getSample(buffer)) {
|
||||||
if (sampleHolder.timeUs < lastSeekPositionUs) {
|
if (buffer.timeUs < lastSeekPositionUs) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_DECODE_ONLY);
|
buffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||||
}
|
}
|
||||||
if (havePendingNextSampleUs) {
|
if (havePendingNextSampleUs) {
|
||||||
// Set the offset to make the timestamp of this sample equal to pendingNextSampleUs.
|
// Set the offset to make the timestamp of this sample equal to pendingNextSampleUs.
|
||||||
sampleTimeOffsetUs = pendingNextSampleUs - sampleHolder.timeUs;
|
sampleTimeOffsetUs = pendingNextSampleUs - buffer.timeUs;
|
||||||
havePendingNextSampleUs = false;
|
havePendingNextSampleUs = false;
|
||||||
}
|
}
|
||||||
sampleHolder.timeUs += sampleTimeOffsetUs;
|
buffer.timeUs += sampleTimeOffsetUs;
|
||||||
return TrackStream.SAMPLE_READ;
|
return TrackStream.BUFFER_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadingFinished) {
|
if (loadingFinished) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
return TrackStream.END_OF_STREAM;
|
return TrackStream.BUFFER_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
@ -764,8 +764,8 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
return ExtractorSampleSource.this.readData(track, formatHolder, sampleHolder);
|
return ExtractorSampleSource.this.readData(track, formatHolder, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
package com.google.android.exoplayer.extractor;
|
package com.google.android.exoplayer.extractor;
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.upstream.Allocation;
|
import com.google.android.exoplayer.upstream.Allocation;
|
||||||
import com.google.android.exoplayer.upstream.Allocator;
|
import com.google.android.exoplayer.upstream.Allocator;
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
@ -40,7 +40,7 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
|
|
||||||
private final InfoQueue infoQueue;
|
private final InfoQueue infoQueue;
|
||||||
private final LinkedBlockingDeque<Allocation> dataQueue;
|
private final LinkedBlockingDeque<Allocation> dataQueue;
|
||||||
private final SampleExtrasHolder extrasHolder;
|
private final BufferExtrasHolder extrasHolder;
|
||||||
private final ParsableByteArray scratch;
|
private final ParsableByteArray scratch;
|
||||||
|
|
||||||
// Accessed only by the consuming thread.
|
// Accessed only by the consuming thread.
|
||||||
@ -59,7 +59,7 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
allocationLength = allocator.getIndividualAllocationLength();
|
allocationLength = allocator.getIndividualAllocationLength();
|
||||||
infoQueue = new InfoQueue();
|
infoQueue = new InfoQueue();
|
||||||
dataQueue = new LinkedBlockingDeque<>();
|
dataQueue = new LinkedBlockingDeque<>();
|
||||||
extrasHolder = new SampleExtrasHolder();
|
extrasHolder = new BufferExtrasHolder();
|
||||||
scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE);
|
scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE);
|
||||||
lastAllocationOffset = allocationLength;
|
lastAllocationOffset = allocationLength;
|
||||||
}
|
}
|
||||||
@ -133,15 +133,16 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills {@code holder} with information about the current sample, but does not write its data.
|
* Fills {@code buffer} with information about the current sample, but does not write its data.
|
||||||
* <p>
|
* <p>
|
||||||
* Populates {@link SampleHolder#size}, {@link SampleHolder#timeUs} and the sample flags.
|
* Populates {@link DecoderInputBuffer#size}, {@link DecoderInputBuffer#timeUs} and the buffer
|
||||||
|
* flags.
|
||||||
*
|
*
|
||||||
* @param holder The holder into which the current sample information should be written.
|
* @param buffer The buffer into which the current sample information should be written.
|
||||||
* @return True if the holder was filled. False if there is no current sample.
|
* @return True if the buffer was filled. False if there is no current sample.
|
||||||
*/
|
*/
|
||||||
public boolean peekSample(SampleHolder holder) {
|
public boolean peekSample(DecoderInputBuffer buffer) {
|
||||||
return infoQueue.peekSample(holder, extrasHolder);
|
return infoQueue.peekSample(buffer, extrasHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,23 +171,23 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
/**
|
/**
|
||||||
* Reads the current sample, advancing the read index to the next sample.
|
* Reads the current sample, advancing the read index to the next sample.
|
||||||
*
|
*
|
||||||
* @param sampleHolder The holder into which the current sample should be written.
|
* @param buffer The buffer into which the current sample should be written.
|
||||||
* @return True if a sample was read. False if there is no current sample.
|
* @return True if a sample was read. False if there is no current sample.
|
||||||
*/
|
*/
|
||||||
public boolean readSample(SampleHolder sampleHolder) {
|
public boolean readSample(DecoderInputBuffer buffer) {
|
||||||
// Write the sample information into the holder and extrasHolder.
|
// Write the sample information into the buffer and extrasHolder.
|
||||||
boolean haveSample = infoQueue.peekSample(sampleHolder, extrasHolder);
|
boolean haveSample = infoQueue.peekSample(buffer, extrasHolder);
|
||||||
if (!haveSample) {
|
if (!haveSample) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read encryption data if the sample is encrypted.
|
// Read encryption data if the sample is encrypted.
|
||||||
if (sampleHolder.isEncrypted()) {
|
if (buffer.isEncrypted()) {
|
||||||
readEncryptionData(sampleHolder, extrasHolder);
|
readEncryptionData(buffer, extrasHolder);
|
||||||
}
|
}
|
||||||
// Write the sample data into the holder.
|
// Write the sample data into the holder.
|
||||||
sampleHolder.ensureSpaceForWrite(sampleHolder.size);
|
buffer.ensureSpaceForWrite(buffer.size);
|
||||||
readData(extrasHolder.offset, sampleHolder.data, sampleHolder.size);
|
readData(extrasHolder.offset, buffer.data, buffer.size);
|
||||||
// Advance the read head.
|
// Advance the read head.
|
||||||
long nextOffset = infoQueue.moveToNextSample();
|
long nextOffset = infoQueue.moveToNextSample();
|
||||||
dropDownstreamTo(nextOffset);
|
dropDownstreamTo(nextOffset);
|
||||||
@ -196,14 +197,14 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
/**
|
/**
|
||||||
* Reads encryption data for the current sample.
|
* Reads encryption data for the current sample.
|
||||||
* <p>
|
* <p>
|
||||||
* The encryption data is written into {@code sampleHolder.cryptoInfo}, and
|
* The encryption data is written into {@link DecoderInputBuffer#cryptoInfo}, and
|
||||||
* {@code sampleHolder.size} is adjusted to subtract the number of bytes that were read. The
|
* {@link DecoderInputBuffer#size} is adjusted to subtract the number of bytes that were read. The
|
||||||
* same value is added to {@code extrasHolder.offset}.
|
* same value is added to {@link BufferExtrasHolder#offset}.
|
||||||
*
|
*
|
||||||
* @param sampleHolder The holder into which the encryption data should be written.
|
* @param buffer The buffer into which the encryption data should be written.
|
||||||
* @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
|
* @param extrasHolder The extras holder whose offset should be read and subsequently adjusted.
|
||||||
*/
|
*/
|
||||||
private void readEncryptionData(SampleHolder sampleHolder, SampleExtrasHolder extrasHolder) {
|
private void readEncryptionData(DecoderInputBuffer buffer, BufferExtrasHolder extrasHolder) {
|
||||||
long offset = extrasHolder.offset;
|
long offset = extrasHolder.offset;
|
||||||
|
|
||||||
// Read the signal byte.
|
// Read the signal byte.
|
||||||
@ -214,10 +215,10 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
int ivSize = signalByte & 0x7F;
|
int ivSize = signalByte & 0x7F;
|
||||||
|
|
||||||
// Read the initialization vector.
|
// Read the initialization vector.
|
||||||
if (sampleHolder.cryptoInfo.iv == null) {
|
if (buffer.cryptoInfo.iv == null) {
|
||||||
sampleHolder.cryptoInfo.iv = new byte[16];
|
buffer.cryptoInfo.iv = new byte[16];
|
||||||
}
|
}
|
||||||
readData(offset, sampleHolder.cryptoInfo.iv, ivSize);
|
readData(offset, buffer.cryptoInfo.iv, ivSize);
|
||||||
offset += ivSize;
|
offset += ivSize;
|
||||||
|
|
||||||
// Read the subsample count, if present.
|
// Read the subsample count, if present.
|
||||||
@ -232,11 +233,11 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the clear and encrypted subsample sizes.
|
// Write the clear and encrypted subsample sizes.
|
||||||
int[] clearDataSizes = sampleHolder.cryptoInfo.numBytesOfClearData;
|
int[] clearDataSizes = buffer.cryptoInfo.numBytesOfClearData;
|
||||||
if (clearDataSizes == null || clearDataSizes.length < subsampleCount) {
|
if (clearDataSizes == null || clearDataSizes.length < subsampleCount) {
|
||||||
clearDataSizes = new int[subsampleCount];
|
clearDataSizes = new int[subsampleCount];
|
||||||
}
|
}
|
||||||
int[] encryptedDataSizes = sampleHolder.cryptoInfo.numBytesOfEncryptedData;
|
int[] encryptedDataSizes = buffer.cryptoInfo.numBytesOfEncryptedData;
|
||||||
if (encryptedDataSizes == null || encryptedDataSizes.length < subsampleCount) {
|
if (encryptedDataSizes == null || encryptedDataSizes.length < subsampleCount) {
|
||||||
encryptedDataSizes = new int[subsampleCount];
|
encryptedDataSizes = new int[subsampleCount];
|
||||||
}
|
}
|
||||||
@ -252,17 +253,17 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clearDataSizes[0] = 0;
|
clearDataSizes[0] = 0;
|
||||||
encryptedDataSizes[0] = sampleHolder.size - (int) (offset - extrasHolder.offset);
|
encryptedDataSizes[0] = buffer.size - (int) (offset - extrasHolder.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the cryptoInfo.
|
// Populate the cryptoInfo.
|
||||||
sampleHolder.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes,
|
buffer.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes,
|
||||||
extrasHolder.encryptionKeyId, sampleHolder.cryptoInfo.iv, C.CRYPTO_MODE_AES_CTR);
|
extrasHolder.encryptionKeyId, buffer.cryptoInfo.iv, C.CRYPTO_MODE_AES_CTR);
|
||||||
|
|
||||||
// Adjust the offset and size to take into account the bytes read.
|
// Adjust the offset and size to take into account the bytes read.
|
||||||
int bytesRead = (int) (offset - extrasHolder.offset);
|
int bytesRead = (int) (offset - extrasHolder.offset);
|
||||||
extrasHolder.offset += bytesRead;
|
extrasHolder.offset += bytesRead;
|
||||||
sampleHolder.size -= bytesRead;
|
buffer.size -= bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -418,7 +419,7 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
* Indicates the end point for the current sample, making it available for consumption.
|
* Indicates the end point for the current sample, making it available for consumption.
|
||||||
*
|
*
|
||||||
* @param sampleTimeUs The sample timestamp.
|
* @param sampleTimeUs The sample timestamp.
|
||||||
* @param flags Flags that accompany the sample. See {@code C.SAMPLE_FLAG_*}.
|
* @param flags Flags that accompany the sample. See {@code C.BUFFER_FLAG_*}.
|
||||||
* @param position The position of the sample data in the rolling buffer.
|
* @param position The position of the sample data in the rolling buffer.
|
||||||
* @param size The size of the sample, in bytes.
|
* @param size The size of the sample, in bytes.
|
||||||
* @param encryptionKey The encryption key associated with the sample, or null.
|
* @param encryptionKey The encryption key associated with the sample, or null.
|
||||||
@ -523,24 +524,25 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills {@code holder} with information about the current sample, but does not write its data.
|
* Fills {@code buffer} with information about the current sample, but does not write its data.
|
||||||
* The first entry in {@code offsetHolder} is filled with the absolute position of the sample's
|
* The absolute position of the sample's data in the rolling buffer is stored in
|
||||||
* data in the rolling buffer.
|
|
||||||
* <p>
|
|
||||||
* Populates {@link SampleHolder#size}, {@link SampleHolder#timeUs}, the sample flags and
|
|
||||||
* {@code extrasHolder}.
|
* {@code extrasHolder}.
|
||||||
|
* <p>
|
||||||
|
* Populates {@link DecoderInputBuffer#size}, {@link DecoderInputBuffer#timeUs}, the buffer
|
||||||
|
* flags and {@code extrasHolder}.
|
||||||
*
|
*
|
||||||
* @param holder The holder into which the current sample information should be written.
|
* @param buffer The buffer into which the current sample information should be written.
|
||||||
* @param extrasHolder The holder into which extra sample information should be written.
|
* @param extrasHolder The holder into which extra sample information should be written.
|
||||||
* @return True if the holders were filled. False if there is no current sample.
|
* @return True if the buffer and extras were filled. False if there is no current sample.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean peekSample(SampleHolder holder, SampleExtrasHolder extrasHolder) {
|
public synchronized boolean peekSample(DecoderInputBuffer buffer,
|
||||||
|
BufferExtrasHolder extrasHolder) {
|
||||||
if (queueSize == 0) {
|
if (queueSize == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
holder.timeUs = timesUs[relativeReadIndex];
|
buffer.timeUs = timesUs[relativeReadIndex];
|
||||||
holder.size = sizes[relativeReadIndex];
|
buffer.size = sizes[relativeReadIndex];
|
||||||
holder.setFlags(flags[relativeReadIndex]);
|
buffer.setFlags(flags[relativeReadIndex]);
|
||||||
extrasHolder.offset = offsets[relativeReadIndex];
|
extrasHolder.offset = offsets[relativeReadIndex];
|
||||||
extrasHolder.encryptionKeyId = encryptionKeys[relativeReadIndex];
|
extrasHolder.encryptionKeyId = encryptionKeys[relativeReadIndex];
|
||||||
return true;
|
return true;
|
||||||
@ -590,7 +592,7 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
if (timesUs[searchIndex] > timeUs) {
|
if (timesUs[searchIndex] > timeUs) {
|
||||||
// We've gone too far.
|
// We've gone too far.
|
||||||
break;
|
break;
|
||||||
} else if ((flags[searchIndex] & C.SAMPLE_FLAG_SYNC) != 0) {
|
} else if ((flags[searchIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) {
|
||||||
// We've found a keyframe, and we're still before the seek position.
|
// We've found a keyframe, and we're still before the seek position.
|
||||||
sampleCountToKeyframe = sampleCount;
|
sampleCountToKeyframe = sampleCount;
|
||||||
}
|
}
|
||||||
@ -660,9 +662,9 @@ import java.util.concurrent.LinkedBlockingDeque;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds additional sample information not held by {@link SampleHolder}.
|
* Holds additional buffer information not held by {@link DecoderInputBuffer}.
|
||||||
*/
|
*/
|
||||||
private static final class SampleExtrasHolder {
|
private static final class BufferExtrasHolder {
|
||||||
|
|
||||||
public long offset;
|
public long offset;
|
||||||
public byte[] encryptionKeyId;
|
public byte[] encryptionKeyId;
|
||||||
|
@ -65,7 +65,7 @@ public interface TrackOutput {
|
|||||||
* {@link #sampleData(ParsableByteArray, int)}.
|
* {@link #sampleData(ParsableByteArray, int)}.
|
||||||
*
|
*
|
||||||
* @param timeUs The media timestamp associated with the sample, in microseconds.
|
* @param timeUs The media timestamp associated with the sample, in microseconds.
|
||||||
* @param flags Flags associated with the sample. See {@code C.SAMPLE_FLAG_*}.
|
* @param flags Flags associated with the sample. See {@code C.BUFFER_FLAG_*}.
|
||||||
* @param size The size of the sample data, in bytes.
|
* @param size The size of the sample data, in bytes.
|
||||||
* @param offset The number of bytes that have been passed to
|
* @param offset The number of bytes that have been passed to
|
||||||
* {@link #sampleData(ExtractorInput, int, boolean)} or
|
* {@link #sampleData(ExtractorInput, int, boolean)} or
|
||||||
|
@ -95,7 +95,7 @@ import java.util.Collections;
|
|||||||
// Sample audio AAC frames
|
// Sample audio AAC frames
|
||||||
int bytesToWrite = data.bytesLeft();
|
int bytesToWrite = data.bytesLeft();
|
||||||
output.sampleData(data, bytesToWrite);
|
output.sampleData(data, bytesToWrite);
|
||||||
output.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, bytesToWrite, 0, null);
|
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, bytesToWrite, 0, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ import java.util.List;
|
|||||||
output.sampleData(data, bytesToWrite);
|
output.sampleData(data, bytesToWrite);
|
||||||
bytesWritten += bytesToWrite;
|
bytesWritten += bytesToWrite;
|
||||||
}
|
}
|
||||||
output.sampleMetadata(timeUs, frameType == VIDEO_FRAME_KEYFRAME ? C.SAMPLE_FLAG_SYNC : 0,
|
output.sampleMetadata(timeUs, frameType == VIDEO_FRAME_KEYFRAME ? C.BUFFER_FLAG_KEY_FRAME : 0,
|
||||||
bytesWritten, 0, null);
|
bytesWritten, 0, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,8 @@ public final class Mp3Extractor implements Extractor {
|
|||||||
return RESULT_CONTINUE;
|
return RESULT_CONTINUE;
|
||||||
}
|
}
|
||||||
long timeUs = basisTimeUs + (samplesRead * C.MICROS_PER_SECOND / synchronizedHeader.sampleRate);
|
long timeUs = basisTimeUs + (samplesRead * C.MICROS_PER_SECOND / synchronizedHeader.sampleRate);
|
||||||
trackOutput.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, synchronizedHeader.frameSize, 0, null);
|
trackOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, synchronizedHeader.frameSize, 0,
|
||||||
|
null);
|
||||||
samplesRead += synchronizedHeader.samplesPerFrame;
|
samplesRead += synchronizedHeader.samplesPerFrame;
|
||||||
sampleBytesRemaining = 0;
|
sampleBytesRemaining = 0;
|
||||||
return RESULT_CONTINUE;
|
return RESULT_CONTINUE;
|
||||||
|
@ -196,9 +196,9 @@ import java.util.List;
|
|||||||
timestamps[i] = timestampTimeUnits + timestampOffset;
|
timestamps[i] = timestampTimeUnits + timestampOffset;
|
||||||
|
|
||||||
// All samples are synchronization samples if the stss is not present.
|
// All samples are synchronization samples if the stss is not present.
|
||||||
flags[i] = stss == null ? C.SAMPLE_FLAG_SYNC : 0;
|
flags[i] = stss == null ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
if (i == nextSynchronizationSampleIndex) {
|
if (i == nextSynchronizationSampleIndex) {
|
||||||
flags[i] = C.SAMPLE_FLAG_SYNC;
|
flags[i] = C.BUFFER_FLAG_KEY_FRAME;
|
||||||
remainingSynchronizationSamples--;
|
remainingSynchronizationSamples--;
|
||||||
if (remainingSynchronizationSamples > 0) {
|
if (remainingSynchronizationSamples > 0) {
|
||||||
nextSynchronizationSampleIndex = stss.readUnsignedIntToInt() - 1;
|
nextSynchronizationSampleIndex = stss.readUnsignedIntToInt() - 1;
|
||||||
@ -330,7 +330,7 @@ import java.util.List;
|
|||||||
|
|
||||||
boolean hasSyncSample = false;
|
boolean hasSyncSample = false;
|
||||||
for (int i = 0; i < editedFlags.length && !hasSyncSample; i++) {
|
for (int i = 0; i < editedFlags.length && !hasSyncSample; i++) {
|
||||||
hasSyncSample |= (editedFlags[i] & C.SAMPLE_FLAG_SYNC) != 0;
|
hasSyncSample |= (editedFlags[i] & C.BUFFER_FLAG_KEY_FRAME) != 0;
|
||||||
}
|
}
|
||||||
if (!hasSyncSample) {
|
if (!hasSyncSample) {
|
||||||
throw new ParserException("The edited sample sequence does not contain a sync sample.");
|
throw new ParserException("The edited sample sequence does not contain a sync sample.");
|
||||||
|
@ -874,8 +874,8 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long sampleTimeUs = fragment.getSamplePresentationTime(sampleIndex) * 1000L;
|
long sampleTimeUs = fragment.getSamplePresentationTime(sampleIndex) * 1000L;
|
||||||
int sampleFlags = (fragment.definesEncryptionData ? C.SAMPLE_FLAG_ENCRYPTED : 0)
|
int sampleFlags = (fragment.definesEncryptionData ? C.BUFFER_FLAG_ENCRYPTED : 0)
|
||||||
| (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.SAMPLE_FLAG_SYNC : 0);
|
| (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0);
|
||||||
int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex;
|
int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex;
|
||||||
byte[] encryptionKey = fragment.definesEncryptionData
|
byte[] encryptionKey = fragment.definesEncryptionData
|
||||||
? track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex].keyId : null;
|
? track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex].keyId : null;
|
||||||
|
@ -79,7 +79,7 @@ import com.google.android.exoplayer.util.Util;
|
|||||||
// Frames are not reordered past synchronization samples so this works in practice.
|
// Frames are not reordered past synchronization samples so this works in practice.
|
||||||
int startIndex = Util.binarySearchFloor(timestampsUs, timeUs, true, false);
|
int startIndex = Util.binarySearchFloor(timestampsUs, timeUs, true, false);
|
||||||
for (int i = startIndex; i >= 0; i--) {
|
for (int i = startIndex; i >= 0; i--) {
|
||||||
if ((flags[i] & C.SAMPLE_FLAG_SYNC) != 0) {
|
if ((flags[i] & C.BUFFER_FLAG_KEY_FRAME) != 0) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ import com.google.android.exoplayer.util.Util;
|
|||||||
public int getIndexOfLaterOrEqualSynchronizationSample(long timeUs) {
|
public int getIndexOfLaterOrEqualSynchronizationSample(long timeUs) {
|
||||||
int startIndex = Util.binarySearchCeil(timestampsUs, timeUs, true, false);
|
int startIndex = Util.binarySearchCeil(timestampsUs, timeUs, true, false);
|
||||||
for (int i = startIndex; i < timestampsUs.length; i++) {
|
for (int i = startIndex; i < timestampsUs.length; i++) {
|
||||||
if ((flags[i] & C.SAMPLE_FLAG_SYNC) != 0) {
|
if ((flags[i] & C.BUFFER_FLAG_KEY_FRAME) != 0) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ public final class OggVorbisExtractor implements Extractor, SeekMap {
|
|||||||
// Calculate time and send audio data to codec.
|
// Calculate time and send audio data to codec.
|
||||||
long timeUs = elapsedSamples * C.MICROS_PER_SECOND / vorbisSetup.idHeader.sampleRate;
|
long timeUs = elapsedSamples * C.MICROS_PER_SECOND / vorbisSetup.idHeader.sampleRate;
|
||||||
trackOutput.sampleData(scratch, scratch.limit());
|
trackOutput.sampleData(scratch, scratch.limit());
|
||||||
trackOutput.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, scratch.limit(), 0, null);
|
trackOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, scratch.limit(), 0, null);
|
||||||
targetGranule = -1;
|
targetGranule = -1;
|
||||||
}
|
}
|
||||||
// Update state in members for next iteration.
|
// Update state in members for next iteration.
|
||||||
|
@ -103,7 +103,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||||||
output.sampleData(data, bytesToRead);
|
output.sampleData(data, bytesToRead);
|
||||||
bytesRead += bytesToRead;
|
bytesRead += bytesToRead;
|
||||||
if (bytesRead == sampleSize) {
|
if (bytesRead == sampleSize) {
|
||||||
output.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
|
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||||
timeUs += sampleDurationUs;
|
timeUs += sampleDurationUs;
|
||||||
state = STATE_FINDING_SYNC;
|
state = STATE_FINDING_SYNC;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ import java.util.Collections;
|
|||||||
currentOutput.sampleData(data, bytesToRead);
|
currentOutput.sampleData(data, bytesToRead);
|
||||||
bytesRead += bytesToRead;
|
bytesRead += bytesToRead;
|
||||||
if (bytesRead == sampleSize) {
|
if (bytesRead == sampleSize) {
|
||||||
currentOutput.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
|
currentOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||||
timeUs += currentSampleDuration;
|
timeUs += currentSampleDuration;
|
||||||
setFindingSampleState();
|
setFindingSampleState();
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||||||
output.sampleData(data, bytesToRead);
|
output.sampleData(data, bytesToRead);
|
||||||
bytesRead += bytesToRead;
|
bytesRead += bytesToRead;
|
||||||
if (bytesRead == sampleSize) {
|
if (bytesRead == sampleSize) {
|
||||||
output.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
|
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||||
timeUs += sampleDurationUs;
|
timeUs += sampleDurationUs;
|
||||||
state = STATE_FINDING_SYNC;
|
state = STATE_FINDING_SYNC;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ import java.util.Collections;
|
|||||||
if (hasOutputFormat && (startCodeValue == START_GROUP || startCodeValue == START_PICTURE)) {
|
if (hasOutputFormat && (startCodeValue == START_GROUP || startCodeValue == START_PICTURE)) {
|
||||||
int bytesWrittenPastStartCode = limit - startCodeOffset;
|
int bytesWrittenPastStartCode = limit - startCodeOffset;
|
||||||
if (foundFirstFrameInGroup) {
|
if (foundFirstFrameInGroup) {
|
||||||
int flags = isKeyframe ? C.SAMPLE_FLAG_SYNC : 0;
|
int flags = isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
int size = (int) (totalBytesWritten - framePosition) - bytesWrittenPastStartCode;
|
int size = (int) (totalBytesWritten - framePosition) - bytesWrittenPastStartCode;
|
||||||
output.sampleMetadata(frameTimeUs, flags, size, bytesWrittenPastStartCode, null);
|
output.sampleMetadata(frameTimeUs, flags, size, bytesWrittenPastStartCode, null);
|
||||||
isKeyframe = false;
|
isKeyframe = false;
|
||||||
|
@ -431,7 +431,7 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void outputSample(int offset) {
|
private void outputSample(int offset) {
|
||||||
int flags = sampleIsKeyframe ? C.SAMPLE_FLAG_SYNC : 0;
|
int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
int size = (int) (nalUnitStartPosition - samplePosition);
|
int size = (int) (nalUnitStartPosition - samplePosition);
|
||||||
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
|
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
|
||||||
}
|
}
|
||||||
|
@ -453,7 +453,7 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void outputSample(int offset) {
|
private void outputSample(int offset) {
|
||||||
int flags = sampleIsKeyframe ? C.SAMPLE_FLAG_SYNC : 0;
|
int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||||
int size = (int) (nalUnitStartPosition - samplePosition);
|
int size = (int) (nalUnitStartPosition - samplePosition);
|
||||||
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
|
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||||||
if (!writingSample || sampleSize == 0 || sampleBytesRead != sampleSize) {
|
if (!writingSample || sampleSize == 0 || sampleBytesRead != sampleSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
output.sampleMetadata(sampleTimeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
|
output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||||
writingSample = false;
|
writingSample = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
output.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, frameSize, 0, null);
|
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, frameSize, 0, null);
|
||||||
timeUs += frameDurationUs;
|
timeUs += frameDurationUs;
|
||||||
frameBytesRead = 0;
|
frameBytesRead = 0;
|
||||||
state = STATE_FINDING_HEADER;
|
state = STATE_FINDING_HEADER;
|
||||||
|
@ -55,7 +55,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||||||
// Process the payload.
|
// Process the payload.
|
||||||
if (Eia608Parser.isSeiMessageEia608(payloadType, payloadSize, seiBuffer)) {
|
if (Eia608Parser.isSeiMessageEia608(payloadType, payloadSize, seiBuffer)) {
|
||||||
output.sampleData(seiBuffer, payloadSize);
|
output.sampleData(seiBuffer, payloadSize);
|
||||||
output.sampleMetadata(pesTimeUs, C.SAMPLE_FLAG_SYNC, payloadSize, 0, null);
|
output.sampleMetadata(pesTimeUs, C.BUFFER_FLAG_KEY_FRAME, payloadSize, 0, null);
|
||||||
} else {
|
} else {
|
||||||
seiBuffer.skipBytes(payloadSize);
|
seiBuffer.skipBytes(payloadSize);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ public final class WavExtractor implements Extractor, SeekMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trackOutput.sampleMetadata(
|
trackOutput.sampleMetadata(
|
||||||
wavHeader.getTimeUs(inputPosition), C.SAMPLE_FLAG_SYNC, bytesRead, 0, null);
|
wavHeader.getTimeUs(inputPosition), C.BUFFER_FLAG_KEY_FRAME, bytesRead, 0, null);
|
||||||
return RESULT_CONTINUE;
|
return RESULT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +449,7 @@ public final class WebmExtractor implements Extractor {
|
|||||||
}
|
}
|
||||||
// If the ReferenceBlock element was not found for this sample, then it is a keyframe.
|
// If the ReferenceBlock element was not found for this sample, then it is a keyframe.
|
||||||
if (!sampleSeenReferenceBlock) {
|
if (!sampleSeenReferenceBlock) {
|
||||||
blockFlags |= C.SAMPLE_FLAG_SYNC;
|
blockFlags |= C.BUFFER_FLAG_KEY_FRAME;
|
||||||
}
|
}
|
||||||
commitSampleToOutput(tracks.get(blockTrackNumber), blockTimeUs);
|
commitSampleToOutput(tracks.get(blockTrackNumber), blockTimeUs);
|
||||||
blockState = BLOCK_STATE_START;
|
blockState = BLOCK_STATE_START;
|
||||||
@ -766,8 +766,8 @@ public final class WebmExtractor implements Extractor {
|
|||||||
boolean isInvisible = (scratch.data[2] & 0x08) == 0x08;
|
boolean isInvisible = (scratch.data[2] & 0x08) == 0x08;
|
||||||
boolean isKeyframe = track.type == TRACK_TYPE_AUDIO
|
boolean isKeyframe = track.type == TRACK_TYPE_AUDIO
|
||||||
|| (id == ID_SIMPLE_BLOCK && (scratch.data[2] & 0x80) == 0x80);
|
|| (id == ID_SIMPLE_BLOCK && (scratch.data[2] & 0x80) == 0x80);
|
||||||
blockFlags = (isKeyframe ? C.SAMPLE_FLAG_SYNC : 0)
|
blockFlags = (isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0)
|
||||||
| (isInvisible ? C.SAMPLE_FLAG_DECODE_ONLY : 0);
|
| (isInvisible ? C.BUFFER_FLAG_DECODE_ONLY : 0);
|
||||||
blockState = BLOCK_STATE_DATA;
|
blockState = BLOCK_STATE_DATA;
|
||||||
blockLacingSampleIndex = 0;
|
blockLacingSampleIndex = 0;
|
||||||
}
|
}
|
||||||
@ -850,7 +850,7 @@ public final class WebmExtractor implements Extractor {
|
|||||||
if (track.hasContentEncryption) {
|
if (track.hasContentEncryption) {
|
||||||
// If the sample is encrypted, read its encryption signal byte and set the IV size.
|
// If the sample is encrypted, read its encryption signal byte and set the IV size.
|
||||||
// Clear the encrypted flag.
|
// Clear the encrypted flag.
|
||||||
blockFlags &= ~C.SAMPLE_FLAG_ENCRYPTED;
|
blockFlags &= ~C.BUFFER_FLAG_ENCRYPTED;
|
||||||
input.readFully(scratch.data, 0, 1);
|
input.readFully(scratch.data, 0, 1);
|
||||||
sampleBytesRead++;
|
sampleBytesRead++;
|
||||||
if ((scratch.data[0] & 0x80) == 0x80) {
|
if ((scratch.data[0] & 0x80) == 0x80) {
|
||||||
@ -861,7 +861,7 @@ public final class WebmExtractor implements Extractor {
|
|||||||
scratch.setPosition(0);
|
scratch.setPosition(0);
|
||||||
output.sampleData(scratch, 1);
|
output.sampleData(scratch, 1);
|
||||||
sampleBytesWritten++;
|
sampleBytesWritten++;
|
||||||
blockFlags |= C.SAMPLE_FLAG_ENCRYPTED;
|
blockFlags |= C.BUFFER_FLAG_ENCRYPTED;
|
||||||
}
|
}
|
||||||
} else if (track.sampleStrippedBytes != null) {
|
} else if (track.sampleStrippedBytes != null) {
|
||||||
// If the sample has header stripping, prepare to read/output the stripped bytes first.
|
// If the sample has header stripping, prepare to read/output the stripped bytes first.
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.hls;
|
package com.google.android.exoplayer.hls;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.drm.DrmInitData;
|
import com.google.android.exoplayer.drm.DrmInitData;
|
||||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||||
import com.google.android.exoplayer.extractor.Extractor;
|
import com.google.android.exoplayer.extractor.Extractor;
|
||||||
@ -182,12 +182,12 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
|
|||||||
* This method must only be called after the extractor has been prepared.
|
* This method must only be called after the extractor has been prepared.
|
||||||
*
|
*
|
||||||
* @param track The track from which to read.
|
* @param track The track from which to read.
|
||||||
* @param holder A {@link SampleHolder} into which the sample should be read.
|
* @param buffer A {@link DecoderInputBuffer} to populate with a sample.
|
||||||
* @return True if a sample was read. False otherwise.
|
* @return True if a sample was read. False otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean getSample(int track, SampleHolder holder) {
|
public boolean getSample(int track, DecoderInputBuffer buffer) {
|
||||||
Assertions.checkState(isPrepared());
|
Assertions.checkState(isPrepared());
|
||||||
return sampleQueues.valueAt(track).getSample(holder);
|
return sampleQueues.valueAt(track).getSample(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,13 +204,13 @@ public final class HlsExtractorWrapper implements ExtractorOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether samples are available for reading from {@link #getSample(int, SampleHolder)} for the
|
* Whether samples are available for reading from {@link #getSample(int, DecoderInputBuffer)} for
|
||||||
* specified track.
|
* the specified track.
|
||||||
* <p>
|
* <p>
|
||||||
* This method must only be called after the extractor has been prepared.
|
* This method must only be called after the extractor has been prepared.
|
||||||
*
|
*
|
||||||
* @return True if samples are available for reading from {@link #getSample(int, SampleHolder)}
|
* @return True if samples are available for reading from
|
||||||
* for the specified track. False otherwise.
|
* {@link #getSample(int, DecoderInputBuffer)} for the specified track. False otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean hasSamples(int track) {
|
public boolean hasSamples(int track) {
|
||||||
Assertions.checkState(isPrepared());
|
Assertions.checkState(isPrepared());
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
package com.google.android.exoplayer.hls;
|
package com.google.android.exoplayer.hls;
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.LoadControl;
|
import com.google.android.exoplayer.LoadControl;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
@ -293,7 +293,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
return TrackStream.NO_RESET;
|
return TrackStream.NO_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ int readData(int group, FormatHolder formatHolder, SampleHolder sampleHolder) {
|
/* package */ int readData(int group, FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
if (pendingResets[group] || isPendingReset()) {
|
if (pendingResets[group] || isPendingReset()) {
|
||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
@ -332,16 +332,16 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
return TrackStream.FORMAT_READ;
|
return TrackStream.FORMAT_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extractor.getSample(group, sampleHolder)) {
|
if (extractor.getSample(group, buffer)) {
|
||||||
if (sampleHolder.timeUs < lastSeekPositionUs) {
|
if (buffer.timeUs < lastSeekPositionUs) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_DECODE_ONLY);
|
buffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||||
}
|
}
|
||||||
return TrackStream.SAMPLE_READ;
|
return TrackStream.BUFFER_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadingFinished) {
|
if (loadingFinished) {
|
||||||
sampleHolder.addFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
return TrackStream.END_OF_STREAM;
|
return TrackStream.BUFFER_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
@ -836,8 +836,8 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(FormatHolder formatHolder, SampleHolder sampleHolder) {
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) {
|
||||||
return HlsSampleSource.this.readData(group, formatHolder, sampleHolder);
|
return HlsSampleSource.this.readData(group, formatHolder, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ import java.util.regex.Pattern;
|
|||||||
// Output the sample.
|
// Output the sample.
|
||||||
sampleDataWrapper.reset(sampleData, sampleSize);
|
sampleDataWrapper.reset(sampleData, sampleSize);
|
||||||
trackOutput.sampleData(sampleDataWrapper, sampleSize);
|
trackOutput.sampleData(sampleDataWrapper, sampleSize);
|
||||||
trackOutput.sampleMetadata(sampleTimeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
|
trackOutput.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrackOutput buildTrackOutput(long subsampleOffsetUs) {
|
private TrackOutput buildTrackOutput(long subsampleOffsetUs) {
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.metadata;
|
package com.google.android.exoplayer.metadata;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.ExoPlaybackException;
|
import com.google.android.exoplayer.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
@ -60,7 +60,7 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
|||||||
private final MetadataRenderer<T> metadataRenderer;
|
private final MetadataRenderer<T> metadataRenderer;
|
||||||
private final Handler metadataHandler;
|
private final Handler metadataHandler;
|
||||||
private final FormatHolder formatHolder;
|
private final FormatHolder formatHolder;
|
||||||
private final SampleHolder sampleHolder;
|
private final DecoderInputBuffer buffer;
|
||||||
|
|
||||||
private boolean inputStreamEnded;
|
private boolean inputStreamEnded;
|
||||||
private long pendingMetadataTimestamp;
|
private long pendingMetadataTimestamp;
|
||||||
@ -82,7 +82,7 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
|||||||
this.metadataHandler = metadataRendererLooper == null ? null
|
this.metadataHandler = metadataRendererLooper == null ? null
|
||||||
: new Handler(metadataRendererLooper, this);
|
: new Handler(metadataRendererLooper, this);
|
||||||
formatHolder = new FormatHolder();
|
formatHolder = new FormatHolder();
|
||||||
sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
|
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -101,17 +101,19 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
|||||||
protected void render(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
protected void render(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
if (!inputStreamEnded && pendingMetadata == null) {
|
if (!inputStreamEnded && pendingMetadata == null) {
|
||||||
sampleHolder.clear();
|
buffer.clear();
|
||||||
int result = readSource(formatHolder, sampleHolder);
|
int result = readSource(formatHolder, buffer);
|
||||||
if (result == TrackStream.SAMPLE_READ) {
|
if (result == TrackStream.BUFFER_READ) {
|
||||||
pendingMetadataTimestamp = sampleHolder.timeUs;
|
if (buffer.isEndOfStream()) {
|
||||||
try {
|
inputStreamEnded = true;
|
||||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
} else {
|
||||||
} catch (IOException e) {
|
pendingMetadataTimestamp = buffer.timeUs;
|
||||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
try {
|
||||||
|
pendingMetadata = metadataParser.parse(buffer.data.array(), buffer.size);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (result == TrackStream.END_OF_STREAM) {
|
|
||||||
inputStreamEnded = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,17 +15,17 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.text;
|
package com.google.android.exoplayer.text;
|
||||||
|
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An input buffer for {@link SubtitleParser}.
|
* An input buffer for {@link SubtitleParser}.
|
||||||
*/
|
*/
|
||||||
/* package */ final class SubtitleInputBuffer extends SampleHolder {
|
/* package */ final class SubtitleInputBuffer extends DecoderInputBuffer {
|
||||||
|
|
||||||
public long subsampleOffsetUs;
|
public long subsampleOffsetUs;
|
||||||
|
|
||||||
public SubtitleInputBuffer() {
|
public SubtitleInputBuffer() {
|
||||||
super(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
|
super(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -176,11 +176,14 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
|||||||
}
|
}
|
||||||
// Try and read the next subtitle from the source.
|
// Try and read the next subtitle from the source.
|
||||||
int result = readSource(formatHolder, nextInputBuffer);
|
int result = readSource(formatHolder, nextInputBuffer);
|
||||||
if (result == TrackStream.SAMPLE_READ) {
|
if (result == TrackStream.BUFFER_READ) {
|
||||||
nextInputBuffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
|
if (nextInputBuffer.isEndOfStream()) {
|
||||||
parser.queueInputBuffer(nextInputBuffer);
|
inputStreamEnded = true;
|
||||||
} else if (result == TrackStream.END_OF_STREAM) {
|
// TODO: Queue the end of stream buffer.
|
||||||
inputStreamEnded = true;
|
} else {
|
||||||
|
nextInputBuffer.subsampleOffsetUs = formatHolder.format.subsampleOffsetUs;
|
||||||
|
parser.queueInputBuffer(nextInputBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ParserException e) {
|
} catch (ParserException e) {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.text.eia608;
|
package com.google.android.exoplayer.text.eia608;
|
||||||
|
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.util.ParsableBitArray;
|
import com.google.android.exoplayer.util.ParsableBitArray;
|
||||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||||
@ -116,14 +116,14 @@ public final class Eia608Parser {
|
|||||||
return mimeType.equals(MimeTypes.APPLICATION_EIA608);
|
return mimeType.equals(MimeTypes.APPLICATION_EIA608);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ ClosedCaptionList parse(SampleHolder sampleHolder) {
|
/* package */ ClosedCaptionList parse(DecoderInputBuffer buffer) {
|
||||||
if (sampleHolder.size < 10) {
|
if (buffer.size < 10) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
captions.clear();
|
captions.clear();
|
||||||
stringBuilder.setLength(0);
|
stringBuilder.setLength(0);
|
||||||
seiBuffer.reset(sampleHolder.data.array());
|
seiBuffer.reset(buffer.data.array());
|
||||||
|
|
||||||
// country_code (8) + provider_code (16) + user_identifier (32) + user_data_type_code (8) +
|
// country_code (8) + provider_code (16) + user_identifier (32) + user_data_type_code (8) +
|
||||||
// reserved (1) + process_cc_data_flag (1) + zero_bit (1)
|
// reserved (1) + process_cc_data_flag (1) + zero_bit (1)
|
||||||
@ -200,7 +200,7 @@ public final class Eia608Parser {
|
|||||||
|
|
||||||
ClosedCaption[] captionArray = new ClosedCaption[captions.size()];
|
ClosedCaption[] captionArray = new ClosedCaption[captions.size()];
|
||||||
captions.toArray(captionArray);
|
captions.toArray(captionArray);
|
||||||
return new ClosedCaptionList(sampleHolder.timeUs, sampleHolder.isDecodeOnly(), captionArray);
|
return new ClosedCaptionList(buffer.timeUs, buffer.isDecodeOnly(), captionArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char getChar(byte ccData) {
|
private static char getChar(byte ccData) {
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
package com.google.android.exoplayer.text.eia608;
|
package com.google.android.exoplayer.text.eia608;
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.ExoPlaybackException;
|
import com.google.android.exoplayer.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
|
||||||
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
import com.google.android.exoplayer.SampleSourceTrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
@ -51,13 +51,13 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
// The default number of rows to display in roll-up captions mode.
|
// The default number of rows to display in roll-up captions mode.
|
||||||
private static final int DEFAULT_CAPTIONS_ROW_COUNT = 4;
|
private static final int DEFAULT_CAPTIONS_ROW_COUNT = 4;
|
||||||
// The maximum duration that captions are parsed ahead of the current position.
|
// The maximum duration that captions are parsed ahead of the current position.
|
||||||
private static final int MAX_SAMPLE_READAHEAD_US = 5000000;
|
private static final int MAX_BUFFER_READAHEAD_US = 5000000;
|
||||||
|
|
||||||
private final Eia608Parser eia608Parser;
|
private final Eia608Parser eia608Parser;
|
||||||
private final TextRenderer textRenderer;
|
private final TextRenderer textRenderer;
|
||||||
private final Handler textRendererHandler;
|
private final Handler textRendererHandler;
|
||||||
private final FormatHolder formatHolder;
|
private final FormatHolder formatHolder;
|
||||||
private final SampleHolder sampleHolder;
|
private final DecoderInputBuffer buffer;
|
||||||
private final StringBuilder captionStringBuilder;
|
private final StringBuilder captionStringBuilder;
|
||||||
private final TreeSet<ClosedCaptionList> pendingCaptionLists;
|
private final TreeSet<ClosedCaptionList> pendingCaptionLists;
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
textRendererHandler = textRendererLooper == null ? null : new Handler(textRendererLooper, this);
|
textRendererHandler = textRendererLooper == null ? null : new Handler(textRendererLooper, this);
|
||||||
eia608Parser = new Eia608Parser();
|
eia608Parser = new Eia608Parser();
|
||||||
formatHolder = new FormatHolder();
|
formatHolder = new FormatHolder();
|
||||||
sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
|
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
captionStringBuilder = new StringBuilder();
|
captionStringBuilder = new StringBuilder();
|
||||||
pendingCaptionLists = new TreeSet<>();
|
pendingCaptionLists = new TreeSet<>();
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
repeatableControl = null;
|
repeatableControl = null;
|
||||||
pendingCaptionLists.clear();
|
pendingCaptionLists.clear();
|
||||||
clearPendingSample();
|
clearPendingBuffer();
|
||||||
captionRowCount = DEFAULT_CAPTIONS_ROW_COUNT;
|
captionRowCount = DEFAULT_CAPTIONS_ROW_COUNT;
|
||||||
setCaptionMode(CC_MODE_UNKNOWN);
|
setCaptionMode(CC_MODE_UNKNOWN);
|
||||||
invokeRenderer(null);
|
invokeRenderer(null);
|
||||||
@ -106,17 +106,20 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
@Override
|
@Override
|
||||||
protected void render(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
protected void render(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
if (isSamplePending()) {
|
if (isBufferPending()) {
|
||||||
maybeParsePendingSample(positionUs);
|
maybeParsePendingBuffer(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = inputStreamEnded ? TrackStream.END_OF_STREAM : TrackStream.SAMPLE_READ;
|
while (!isBufferPending() && !inputStreamEnded) {
|
||||||
while (!isSamplePending() && result == TrackStream.SAMPLE_READ) {
|
int result = readSource(formatHolder, buffer);
|
||||||
result = readSource(formatHolder, sampleHolder);
|
if (result == TrackStream.BUFFER_READ) {
|
||||||
if (result == TrackStream.SAMPLE_READ) {
|
if (buffer.isEndOfStream()) {
|
||||||
maybeParsePendingSample(positionUs);
|
inputStreamEnded = true;
|
||||||
} else if (result == TrackStream.END_OF_STREAM) {
|
} else {
|
||||||
inputStreamEnded = true;
|
maybeParsePendingBuffer(positionUs);
|
||||||
|
}
|
||||||
|
} else if (result == TrackStream.NOTHING_READ) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,13 +180,13 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeParsePendingSample(long positionUs) {
|
private void maybeParsePendingBuffer(long positionUs) {
|
||||||
if (sampleHolder.timeUs > positionUs + MAX_SAMPLE_READAHEAD_US) {
|
if (buffer.timeUs > positionUs + MAX_BUFFER_READAHEAD_US) {
|
||||||
// We're too early to parse the sample.
|
// We're too early to parse the buffer.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ClosedCaptionList holder = eia608Parser.parse(sampleHolder);
|
ClosedCaptionList holder = eia608Parser.parse(buffer);
|
||||||
clearPendingSample();
|
clearPendingBuffer();
|
||||||
if (holder != null) {
|
if (holder != null) {
|
||||||
pendingCaptionLists.add(holder);
|
pendingCaptionLists.add(holder);
|
||||||
}
|
}
|
||||||
@ -338,13 +341,13 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
return captionStringBuilder.substring(0, endIndex - startIndex);
|
return captionStringBuilder.substring(0, endIndex - startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearPendingSample() {
|
private void clearPendingBuffer() {
|
||||||
sampleHolder.clear();
|
buffer.clear();
|
||||||
sampleHolder.timeUs = C.UNKNOWN_TIME_US;
|
buffer.timeUs = C.UNKNOWN_TIME_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSamplePending() {
|
private boolean isBufferPending() {
|
||||||
return sampleHolder.timeUs != C.UNKNOWN_TIME_US;
|
return buffer.timeUs != C.UNKNOWN_TIME_US;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,30 +32,30 @@ public abstract class Buffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the {@link C#SAMPLE_FLAG_DECODE_ONLY} flag is set.
|
* Returns whether the {@link C#BUFFER_FLAG_DECODE_ONLY} flag is set.
|
||||||
*/
|
*/
|
||||||
public final boolean isDecodeOnly() {
|
public final boolean isDecodeOnly() {
|
||||||
return getFlag(C.SAMPLE_FLAG_DECODE_ONLY);
|
return getFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the {@link C#SAMPLE_FLAG_END_OF_STREAM} flag is set.
|
* Returns whether the {@link C#BUFFER_FLAG_END_OF_STREAM} flag is set.
|
||||||
*/
|
*/
|
||||||
public final boolean isEndOfStream() {
|
public final boolean isEndOfStream() {
|
||||||
return getFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
return getFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the sample has the {@link C#SAMPLE_FLAG_SYNC} flag set.
|
* Returns whether the {@link C#BUFFER_FLAG_KEY_FRAME} flag is set.
|
||||||
*/
|
*/
|
||||||
public final boolean isSyncFrame() {
|
public final boolean isKeyFrame() {
|
||||||
return getFlag(C.SAMPLE_FLAG_SYNC);
|
return getFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces this buffer's flags with {@code flags}.
|
* Replaces this buffer's flags with {@code flags}.
|
||||||
*
|
*
|
||||||
* @param flags The flags to set, which should be a combination of the {@code C.SAMPLE_FLAG_*}
|
* @param flags The flags to set, which should be a combination of the {@code C.BUFFER_FLAG_*}
|
||||||
* constants.
|
* constants.
|
||||||
*/
|
*/
|
||||||
public final void setFlags(int flags) {
|
public final void setFlags(int flags) {
|
||||||
@ -66,7 +66,7 @@ public abstract class Buffer {
|
|||||||
* Adds the {@code flag} to this buffer's flags.
|
* Adds the {@code flag} to this buffer's flags.
|
||||||
*
|
*
|
||||||
* @param flag The flag to add to this buffer's flags, which should be one of the
|
* @param flag The flag to add to this buffer's flags, which should be one of the
|
||||||
* {@code C.SAMPLE_FLAG_*} constants.
|
* {@code C.BUFFER_FLAG_*} constants.
|
||||||
*/
|
*/
|
||||||
public final void addFlag(int flag) {
|
public final void addFlag(int flag) {
|
||||||
flags |= flag;
|
flags |= flag;
|
||||||
|
@ -16,7 +16,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.C;
|
||||||
import com.google.android.exoplayer.SampleHolder;
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -24,7 +24,7 @@ import java.util.LinkedList;
|
|||||||
/**
|
/**
|
||||||
* Base class for {@link Decoder}s that use their own decode thread.
|
* Base class for {@link Decoder}s that use their own decode thread.
|
||||||
*/
|
*/
|
||||||
public abstract class SimpleDecoder<I extends SampleHolder, O extends OutputBuffer,
|
public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends OutputBuffer,
|
||||||
E extends Exception> extends Thread implements Decoder<I, O, E> {
|
E extends Exception> extends Thread implements Decoder<I, O, E> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,10 +218,10 @@ public abstract class SimpleDecoder<I extends SampleHolder, O extends OutputBuff
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inputBuffer.isEndOfStream()) {
|
if (inputBuffer.isEndOfStream()) {
|
||||||
outputBuffer.addFlag(C.SAMPLE_FLAG_END_OF_STREAM);
|
outputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
} else {
|
} else {
|
||||||
if (inputBuffer.isDecodeOnly()) {
|
if (inputBuffer.isDecodeOnly()) {
|
||||||
outputBuffer.addFlag(C.SAMPLE_FLAG_DECODE_ONLY);
|
outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
|
||||||
}
|
}
|
||||||
exception = decode(inputBuffer, outputBuffer);
|
exception = decode(inputBuffer, outputBuffer);
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
@ -276,7 +276,7 @@ public abstract class SimpleDecoder<I extends SampleHolder, O extends OutputBuff
|
|||||||
*
|
*
|
||||||
* @param inputBuffer The buffer to decode.
|
* @param inputBuffer The buffer to decode.
|
||||||
* @param outputBuffer The output buffer to store decoded data. The flag
|
* @param outputBuffer The output buffer to store decoded data. The flag
|
||||||
* {@link C#SAMPLE_FLAG_DECODE_ONLY} will be set if the same flag is set on
|
* {@link C#BUFFER_FLAG_DECODE_ONLY} will be set if the same flag is set on
|
||||||
* {@code inputBuffer}, but the decoder may set/unset the flag if required. If the flag is set
|
* {@code inputBuffer}, but the decoder may set/unset the flag if required. If the flag is set
|
||||||
* after this method returns, any output will not be presented.
|
* after this method returns, any output will not be presented.
|
||||||
* @return A decoder exception if an error occurred, or null if decoding was successful.
|
* @return A decoder exception if an error occurred, or null if decoding was successful.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user