Commit 9f2707cf by olly Committed by Oliver Woodman

Push DrmInitData into Format.

- This means DrmInitData is propagated through sample queues (i.e.
  is effectively attached to every sample, so we can see when it
  changes when reading from the queue).
- It also allows different DrmInitData per track, which is possible
  in muxed MKV/WebM, and per Representation for DASH, although we
  wont be able to seamlessly adapt in the latter case.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121821928
parent e284d616
Showing with 194 additions and 357 deletions
...@@ -105,8 +105,8 @@ public final class FlacExtractor implements Extractor { ...@@ -105,8 +105,8 @@ public final class FlacExtractor implements Extractor {
}); });
Format mediaFormat = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, Format mediaFormat = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW,
streamInfo.bitRate(), Format.NO_VALUE, streamInfo.bitRate(), Format.NO_VALUE, streamInfo.channels, streamInfo.sampleRate, null,
streamInfo.channels, streamInfo.sampleRate, null, null); null, null);
trackOutput.format(mediaFormat); trackOutput.format(mediaFormat);
outputBuffer = new ParsableByteArray(streamInfo.maxDecodedFrameSize()); outputBuffer = new ParsableByteArray(streamInfo.maxDecodedFrameSize());
......
...@@ -46,17 +46,17 @@ public final class FormatTest extends TestCase { ...@@ -46,17 +46,17 @@ public final class FormatTest extends TestCase {
initData.add(initData2); initData.add(initData2);
testConversionToFrameworkMediaFormatV16(Format.createVideoSampleFormat( testConversionToFrameworkMediaFormatV16(Format.createVideoSampleFormat(
null, "video/xyz", 5000, 102400, 1280, 720, 30, initData)); null, "video/xyz", 5000, 102400, 1280, 720, 30, initData, null));
testConversionToFrameworkMediaFormatV16(Format.createVideoSampleFormat( testConversionToFrameworkMediaFormatV16(Format.createVideoSampleFormat(
null, "video/xyz", 5000, Format.NO_VALUE, 1280, 720, 30, null)); null, "video/xyz", 5000, Format.NO_VALUE, 1280, 720, 30, null, null));
testConversionToFrameworkMediaFormatV16(Format.createAudioSampleFormat( testConversionToFrameworkMediaFormatV16(Format.createAudioSampleFormat(
null, "audio/xyz", 500, 128, 5, 44100, initData, null)); null, "audio/xyz", 500, 128, 5, 44100, initData, null, null));
testConversionToFrameworkMediaFormatV16(Format.createAudioSampleFormat( testConversionToFrameworkMediaFormatV16(Format.createAudioSampleFormat(
null, "audio/xyz", 500, Format.NO_VALUE, 5, 44100, null, null)); null, "audio/xyz", 500, Format.NO_VALUE, 5, 44100, null, null, null));
testConversionToFrameworkMediaFormatV16( testConversionToFrameworkMediaFormatV16(
Format.createTextSampleFormat(null, "text/xyz", Format.NO_VALUE, "eng")); Format.createTextSampleFormat(null, "text/xyz", Format.NO_VALUE, "eng", null));
testConversionToFrameworkMediaFormatV16( testConversionToFrameworkMediaFormatV16(
Format.createTextSampleFormat(null, "text/xyz", Format.NO_VALUE, null)); Format.createTextSampleFormat(null, "text/xyz", Format.NO_VALUE, null, null));
} }
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
......
...@@ -67,7 +67,6 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { ...@@ -67,7 +67,6 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase {
private static final byte SECOND_AUDIO_TRACK_NUMBER = 0x05; private static final byte SECOND_AUDIO_TRACK_NUMBER = 0x05;
private static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL); private static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
private static final UUID ZERO_UUID = new UUID(0, 0);
private static final String MATROSKA_DOC_TYPE = "matroska"; private static final String MATROSKA_DOC_TYPE = "matroska";
private static final String WEBM_DOC_TYPE = "webm"; private static final String WEBM_DOC_TYPE = "webm";
...@@ -234,15 +233,8 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { ...@@ -234,15 +233,8 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase {
assertTracksEnded(); assertTracksEnded();
assertVp9VideoFormat(VIDEO_TRACK_NUMBER); assertVp9VideoFormat(VIDEO_TRACK_NUMBER);
assertDrmInitData(VIDEO_TRACK_NUMBER);
assertSeekMap(DEFAULT_TIMECODE_SCALE, 1); assertSeekMap(DEFAULT_TIMECODE_SCALE, 1);
DrmInitData drmInitData = extractorOutput.drmInitData;
assertNotNull(drmInitData);
SchemeData widevineInitData = drmInitData.get(WIDEVINE_UUID);
assertEquals(MimeTypes.VIDEO_WEBM, widevineInitData.mimeType);
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, widevineInitData.data);
SchemeData zeroInitData = drmInitData.get(ZERO_UUID);
assertEquals(MimeTypes.VIDEO_WEBM, zeroInitData.mimeType);
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, zeroInitData.data);
} }
public void testPrepareThreeCuePoints() throws IOException, InterruptedException { public void testPrepareThreeCuePoints() throws IOException, InterruptedException {
...@@ -755,6 +747,17 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { ...@@ -755,6 +747,17 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase {
} }
} }
private void assertDrmInitData(int trackNumber) {
DrmInitData drmInitData = getTrackOutput(trackNumber).format.drmInitData;
assertNotNull(drmInitData);
SchemeData widevineInitData = drmInitData.get(WIDEVINE_UUID);
assertEquals(MimeTypes.VIDEO_WEBM, widevineInitData.mimeType);
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, widevineInitData.data);
SchemeData zeroInitData = drmInitData.get(C.UUID_NIL);
assertEquals(MimeTypes.VIDEO_WEBM, zeroInitData.mimeType);
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, zeroInitData.data);
}
private void assertSeekMap(int timecodeScale, int cuePointCount) { private void assertSeekMap(int timecodeScale, int cuePointCount) {
ChunkIndex index = (ChunkIndex) extractorOutput.seekMap; ChunkIndex index = (ChunkIndex) extractorOutput.seekMap;
assertEquals(cuePointCount, index.length); assertEquals(cuePointCount, index.length);
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer.testutil; package com.google.android.exoplayer.testutil;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.ExtractorOutput; import com.google.android.exoplayer.extractor.ExtractorOutput;
import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.SeekMap;
...@@ -36,7 +35,6 @@ public final class FakeExtractorOutput implements ExtractorOutput { ...@@ -36,7 +35,6 @@ public final class FakeExtractorOutput implements ExtractorOutput {
public int numberOfTracks; public int numberOfTracks;
public boolean tracksEnded; public boolean tracksEnded;
public SeekMap seekMap; public SeekMap seekMap;
public DrmInitData drmInitData;
public FakeExtractorOutput() { public FakeExtractorOutput() {
this(false); this(false);
...@@ -70,11 +68,6 @@ public final class FakeExtractorOutput implements ExtractorOutput { ...@@ -70,11 +68,6 @@ public final class FakeExtractorOutput implements ExtractorOutput {
this.seekMap = seekMap; this.seekMap = seekMap;
} }
@Override
public void drmInitData(DrmInitData drmInitData) {
this.drmInitData = drmInitData;
}
public void assertEquals(FakeExtractorOutput expected) { public void assertEquals(FakeExtractorOutput expected) {
Assert.assertEquals(expected.numberOfTracks, numberOfTracks); Assert.assertEquals(expected.numberOfTracks, numberOfTracks);
Assert.assertEquals(expected.tracksEnded, tracksEnded); Assert.assertEquals(expected.tracksEnded, tracksEnded);
...@@ -87,13 +80,6 @@ public final class FakeExtractorOutput implements ExtractorOutput { ...@@ -87,13 +80,6 @@ public final class FakeExtractorOutput implements ExtractorOutput {
Assert.assertEquals(expected.seekMap.isSeekable(), seekMap.isSeekable()); Assert.assertEquals(expected.seekMap.isSeekable(), seekMap.isSeekable());
Assert.assertEquals(expected.seekMap.getPosition(0), seekMap.getPosition(0)); Assert.assertEquals(expected.seekMap.getPosition(0), seekMap.getPosition(0));
} }
if (expected.drmInitData == null) {
Assert.assertNull(drmInitData);
} else {
// TODO: Bulk up this check if possible.
Assert.assertNotNull(drmInitData);
Assert.assertEquals(expected.drmInitData.getClass(), drmInitData.getClass());
}
for (int i = 0; i < numberOfTracks; i++) { for (int i = 0; i < numberOfTracks; i++) {
Assert.assertEquals(expected.trackOutputs.keyAt(i), trackOutputs.keyAt(i)); Assert.assertEquals(expected.trackOutputs.keyAt(i), trackOutputs.keyAt(i));
trackOutputs.valueAt(i).assertEquals(expected.trackOutputs.valueAt(i)); trackOutputs.valueAt(i).assertEquals(expected.trackOutputs.valueAt(i));
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
*/ */
package com.google.android.exoplayer; package com.google.android.exoplayer;
import com.google.android.exoplayer.drm.DrmInitData;
/** /**
* Holds a {@link Format} and corresponding drm scheme initialization data. * Holds a {@link Format} and corresponding drm scheme initialization data.
*/ */
...@@ -26,9 +24,5 @@ public final class FormatHolder { ...@@ -26,9 +24,5 @@ public final class FormatHolder {
* The format of the media. * The format of the media.
*/ */
public Format format; public Format format;
/**
* Initialization data for drm schemes supported by the media. Null if the media is not encrypted.
*/
public DrmInitData drmInitData;
} }
...@@ -136,12 +136,13 @@ public final class FrameworkSampleSource implements SampleSource { ...@@ -136,12 +136,13 @@ public final class FrameworkSampleSource implements SampleSource {
} }
trackStates = new int[extractor.getTrackCount()]; trackStates = new int[extractor.getTrackCount()];
TrackGroup[] trackArray = new TrackGroup[trackStates.length]; TrackGroup[] trackArray = new TrackGroup[trackStates.length];
DrmInitData drmInitData = Util.SDK_INT >= 18 ? getDrmInitDataV18() : null;
for (int i = 0; i < trackStates.length; i++) { for (int i = 0; i < trackStates.length; i++) {
MediaFormat format = extractor.getTrackFormat(i); MediaFormat format = extractor.getTrackFormat(i);
if (format.containsKey(MediaFormat.KEY_DURATION)) { if (format.containsKey(MediaFormat.KEY_DURATION)) {
durationUs = Math.max(durationUs, format.getLong(MediaFormat.KEY_DURATION)); durationUs = Math.max(durationUs, format.getLong(MediaFormat.KEY_DURATION));
} }
trackArray[i] = new TrackGroup(createFormat(i, format)); trackArray[i] = new TrackGroup(createFormat(i, format, drmInitData));
} }
tracks = new TrackGroupArray(trackArray); tracks = new TrackGroupArray(trackArray);
prepared = true; prepared = true;
...@@ -244,7 +245,6 @@ public final class FrameworkSampleSource implements SampleSource { ...@@ -244,7 +245,6 @@ public final class FrameworkSampleSource implements SampleSource {
} }
if (trackStates[track] != TRACK_STATE_FORMAT_SENT) { if (trackStates[track] != TRACK_STATE_FORMAT_SENT) {
formatHolder.format = tracks.get(track).getFormat(0); formatHolder.format = tracks.get(track).getFormat(0);
formatHolder.drmInitData = Util.SDK_INT >= 18 ? getDrmInitDataV18() : null;
trackStates[track] = TRACK_STATE_FORMAT_SENT; trackStates[track] = TRACK_STATE_FORMAT_SENT;
return TrackStream.FORMAT_READ; return TrackStream.FORMAT_READ;
} }
...@@ -307,7 +307,7 @@ public final class FrameworkSampleSource implements SampleSource { ...@@ -307,7 +307,7 @@ public final class FrameworkSampleSource implements SampleSource {
} }
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
private static Format createFormat(int index, MediaFormat mediaFormat) { private static Format createFormat(int index, MediaFormat mediaFormat, DrmInitData drmInitData) {
String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME); String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
String language = getOptionalStringV16(mediaFormat, MediaFormat.KEY_LANGUAGE); String language = getOptionalStringV16(mediaFormat, MediaFormat.KEY_LANGUAGE);
int maxInputSize = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE); int maxInputSize = getOptionalIntegerV16(mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE);
...@@ -336,7 +336,7 @@ public final class FrameworkSampleSource implements SampleSource { ...@@ -336,7 +336,7 @@ public final class FrameworkSampleSource implements SampleSource {
Format format = new Format(Integer.toString(index), null, mimeType, Format.NO_VALUE, Format format = new Format(Integer.toString(index), null, mimeType, Format.NO_VALUE,
maxInputSize, width, height, frameRate, rotationDegrees, Format.NO_VALUE, channelCount, maxInputSize, width, height, frameRate, rotationDegrees, Format.NO_VALUE, channelCount,
sampleRate, encoderDelay, encoderPadding, language, Format.OFFSET_SAMPLE_RELATIVE, sampleRate, encoderDelay, encoderPadding, language, Format.OFFSET_SAMPLE_RELATIVE,
initializationData, false); initializationData, drmInitData, false);
format.setFrameworkMediaFormatV16(mediaFormat); format.setFrameworkMediaFormatV16(mediaFormat);
return format; return format;
} }
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package com.google.android.exoplayer; package com.google.android.exoplayer;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.drm.DrmSessionManager; import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.NalUnitUtil; import com.google.android.exoplayer.util.NalUnitUtil;
...@@ -171,7 +170,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -171,7 +170,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
protected final Handler eventHandler; protected final Handler eventHandler;
private Format format; private Format format;
private DrmInitData drmInitData;
private MediaCodec codec; private MediaCodec codec;
private boolean codecIsAdaptive; private boolean codecIsAdaptive;
private boolean codecNeedsDiscardToSpsWorkaround; private boolean codecNeedsDiscardToSpsWorkaround;
...@@ -286,13 +284,13 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -286,13 +284,13 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
String mimeType = format.sampleMimeType; String mimeType = format.sampleMimeType;
MediaCrypto mediaCrypto = null; MediaCrypto mediaCrypto = null;
boolean requiresSecureDecoder = false; boolean requiresSecureDecoder = false;
if (drmInitData != null) { if (format.drmInitData != null) {
if (drmSessionManager == null) { if (drmSessionManager == null) {
throw ExoPlaybackException.createForRenderer( throw ExoPlaybackException.createForRenderer(
new IllegalStateException("Media requires a DrmSessionManager"), getIndex()); new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
} }
if (!openedDrmSession) { if (!openedDrmSession) {
drmSessionManager.open(drmInitData); drmSessionManager.open(format.drmInitData);
openedDrmSession = true; openedDrmSession = true;
} }
int drmSessionState = drmSessionManager.getState(); int drmSessionState = drmSessionManager.getState();
...@@ -376,7 +374,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -376,7 +374,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
@Override @Override
protected void onDisabled() { protected void onDisabled() {
format = null; format = null;
drmInitData = null;
try { try {
releaseCodec(); releaseCodec();
} finally { } finally {
...@@ -665,7 +662,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer { ...@@ -665,7 +662,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
Format oldFormat = format; Format oldFormat = format;
format = formatHolder.format; format = formatHolder.format;
drmInitData = formatHolder.drmInitData;
if (codec != null && canReconfigureCodec(codec, codecIsAdaptive, oldFormat, format)) { if (codec != null && canReconfigureCodec(codec, codecIsAdaptive, oldFormat, format)) {
codecReconfigured = true; codecReconfigured = true;
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING; codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package com.google.android.exoplayer.chunk; package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
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.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
...@@ -65,13 +64,6 @@ public abstract class BaseMediaChunk extends MediaChunk { ...@@ -65,13 +64,6 @@ public abstract class BaseMediaChunk extends MediaChunk {
} }
/** /**
* Gets the {@link DrmInitData} corresponding to the chunk.
*
* @return The {@link DrmInitData} corresponding to this chunk.
*/
public abstract DrmInitData getDrmInitData();
/**
* Returns the track output most recently passed to {@link #init(DefaultTrackOutput)}. * Returns the track output most recently passed to {@link #init(DefaultTrackOutput)}.
*/ */
protected final DefaultTrackOutput getTrackOutput() { protected final DefaultTrackOutput getTrackOutput() {
......
...@@ -45,14 +45,11 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput ...@@ -45,14 +45,11 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
*/ */
void seekMap(SeekMap seekMap); void seekMap(SeekMap seekMap);
/**
* @see ExtractorOutput#drmInitData(DrmInitData)
*/
void drmInitData(DrmInitData drmInitData);
} }
private final Extractor extractor; private final Extractor extractor;
private final DrmInitData drmInitData;
private boolean extractorInitialized; private boolean extractorInitialized;
private SingleTrackMetadataOutput metadataOutput; private SingleTrackMetadataOutput metadataOutput;
private TrackOutput trackOutput; private TrackOutput trackOutput;
...@@ -62,9 +59,12 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput ...@@ -62,9 +59,12 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
/** /**
* @param extractor The extractor to wrap. * @param extractor The extractor to wrap.
* @param drmInitData {@link DrmInitData} that should be added to any format extracted from the
* stream. If set, overrides any {@link DrmInitData} extracted from the stream.
*/ */
public ChunkExtractorWrapper(Extractor extractor) { public ChunkExtractorWrapper(Extractor extractor, DrmInitData drmInitData) {
this.extractor = extractor; this.extractor = extractor;
this.drmInitData = drmInitData;
} }
/** /**
...@@ -118,15 +118,13 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput ...@@ -118,15 +118,13 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
metadataOutput.seekMap(seekMap); metadataOutput.seekMap(seekMap);
} }
@Override
public void drmInitData(DrmInitData drmInitData) {
metadataOutput.drmInitData(drmInitData);
}
// TrackOutput implementation. // TrackOutput implementation.
@Override @Override
public void format(Format format) { public void format(Format format) {
if (drmInitData != null) {
format = format.copyWithDrmInitData(drmInitData);
}
trackOutput.format(format); trackOutput.format(format);
} }
......
...@@ -226,11 +226,7 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback { ...@@ -226,11 +226,7 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback {
} }
downstreamFormat = format; downstreamFormat = format;
int result = sampleQueue.readData(formatHolder, buffer, loadingFinished, lastSeekPositionUs); return sampleQueue.readData(formatHolder, buffer, loadingFinished, lastSeekPositionUs);
if (result == FORMAT_READ) {
formatHolder.drmInitData = currentChunk.getDrmInitData();
}
return result;
} }
// Loader.Callback implementation. // Loader.Callback implementation.
......
...@@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk; ...@@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackMetadataOutput; import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackMetadataOutput;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.DefaultExtractorInput; import com.google.android.exoplayer.extractor.DefaultExtractorInput;
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;
...@@ -38,7 +37,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe ...@@ -38,7 +37,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe
private final long sampleOffsetUs; private final long sampleOffsetUs;
private final Format sampleFormat; private final Format sampleFormat;
private volatile DrmInitData drmInitData;
private volatile int bytesLoaded; private volatile int bytesLoaded;
private volatile boolean loadCanceled; private volatile boolean loadCanceled;
...@@ -54,17 +52,14 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe ...@@ -54,17 +52,14 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe
* @param extractorWrapper A wrapped extractor to use for parsing the data. * @param extractorWrapper A wrapped extractor to use for parsing the data.
* @param sampleFormat The {@link Format} of the samples in the chunk, if known. May be null if * @param sampleFormat The {@link Format} of the samples in the chunk, if known. May be null if
* the data is known to define its own sample format. * the data is known to define its own sample format.
* @param drmInitData The {@link DrmInitData} for the chunk. Null if the media is not drm
* protected. May also be null if the data is known to define its own initialization data.
*/ */
public ContainerMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger, Format format, public ContainerMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger, Format format,
long startTimeUs, long endTimeUs, int chunkIndex, long sampleOffsetUs, long startTimeUs, long endTimeUs, int chunkIndex, long sampleOffsetUs,
ChunkExtractorWrapper extractorWrapper, Format sampleFormat, DrmInitData drmInitData) { ChunkExtractorWrapper extractorWrapper, Format sampleFormat) {
super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex); super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex);
this.extractorWrapper = extractorWrapper; this.extractorWrapper = extractorWrapper;
this.sampleOffsetUs = sampleOffsetUs; this.sampleOffsetUs = sampleOffsetUs;
this.sampleFormat = sampleFormat; this.sampleFormat = sampleFormat;
this.drmInitData = drmInitData;
} }
@Override @Override
...@@ -72,11 +67,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe ...@@ -72,11 +67,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe
return bytesLoaded; return bytesLoaded;
} }
@Override
public final DrmInitData getDrmInitData() {
return drmInitData;
}
// SingleTrackMetadataOutput implementation. // SingleTrackMetadataOutput implementation.
@Override @Override
...@@ -84,11 +74,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe ...@@ -84,11 +74,6 @@ public class ContainerMediaChunk extends BaseMediaChunk implements SingleTrackMe
// Do nothing. // Do nothing.
} }
@Override
public final void drmInitData(DrmInitData drmInitData) {
this.drmInitData = drmInitData;
}
// Loadable implementation. // Loadable implementation.
@Override @Override
......
...@@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk; ...@@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackMetadataOutput; import com.google.android.exoplayer.chunk.ChunkExtractorWrapper.SingleTrackMetadataOutput;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.DefaultExtractorInput; import com.google.android.exoplayer.extractor.DefaultExtractorInput;
import com.google.android.exoplayer.extractor.Extractor; import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.extractor.ExtractorInput;
...@@ -42,7 +41,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad ...@@ -42,7 +41,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
// has completed. These variables do not need to be volatile, since a memory barrier must occur // has completed. These variables do not need to be volatile, since a memory barrier must occur
// for the reading thread to know that loading has completed. // for the reading thread to know that loading has completed.
private Format sampleFormat; private Format sampleFormat;
private DrmInitData drmInitData;
private SeekMap seekMap; private SeekMap seekMap;
private volatile int bytesLoaded; private volatile int bytesLoaded;
...@@ -78,15 +76,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad ...@@ -78,15 +76,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
} }
/** /**
* Returns a {@link DrmInitData} parsed from the chunk, or null.
* <p>
* Should be called after loading has completed.
*/
public DrmInitData getDrmInitData() {
return drmInitData;
}
/**
* Returns a {@link SeekMap} parsed from the chunk, or null. * Returns a {@link SeekMap} parsed from the chunk, or null.
* <p> * <p>
* Should be called after loading has completed. * Should be called after loading has completed.
...@@ -102,11 +91,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad ...@@ -102,11 +91,6 @@ public final class InitializationChunk extends Chunk implements SingleTrackMetad
this.seekMap = seekMap; this.seekMap = seekMap;
} }
@Override
public void drmInitData(DrmInitData drmInitData) {
this.drmInitData = drmInitData;
}
// TrackOutput implementation. // TrackOutput implementation.
@Override @Override
......
...@@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk; ...@@ -17,7 +17,6 @@ package com.google.android.exoplayer.chunk;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.DefaultExtractorInput; import com.google.android.exoplayer.extractor.DefaultExtractorInput;
import com.google.android.exoplayer.extractor.DefaultTrackOutput; import com.google.android.exoplayer.extractor.DefaultTrackOutput;
import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.extractor.ExtractorInput;
...@@ -33,7 +32,6 @@ import java.io.IOException; ...@@ -33,7 +32,6 @@ import java.io.IOException;
public final class SingleSampleMediaChunk extends BaseMediaChunk { public final class SingleSampleMediaChunk extends BaseMediaChunk {
private final Format sampleFormat; private final Format sampleFormat;
private final DrmInitData sampleDrmInitData;
private volatile int bytesLoaded; private volatile int bytesLoaded;
private volatile boolean loadCanceled; private volatile boolean loadCanceled;
...@@ -47,15 +45,11 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { ...@@ -47,15 +45,11 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
* @param endTimeUs The end time of the media contained by the chunk, in microseconds. * @param endTimeUs The end time of the media contained by the chunk, in microseconds.
* @param chunkIndex The index of the chunk. * @param chunkIndex The index of the chunk.
* @param sampleFormat The format of the sample. * @param sampleFormat The format of the sample.
* @param sampleDrmInitData The {@link DrmInitData} for the sample. Null if the sample is not drm
* protected.
*/ */
public SingleSampleMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger, public SingleSampleMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger,
Format format, long startTimeUs, long endTimeUs, int chunkIndex, Format sampleFormat, Format format, long startTimeUs, long endTimeUs, int chunkIndex, Format sampleFormat) {
DrmInitData sampleDrmInitData) {
super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex); super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex);
this.sampleFormat = sampleFormat; this.sampleFormat = sampleFormat;
this.sampleDrmInitData = sampleDrmInitData;
} }
@Override @Override
...@@ -63,11 +57,6 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk { ...@@ -63,11 +57,6 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
return bytesLoaded; return bytesLoaded;
} }
@Override
public DrmInitData getDrmInitData() {
return sampleDrmInitData;
}
// Loadable implementation. // Loadable implementation.
@Override @Override
......
...@@ -31,13 +31,11 @@ import com.google.android.exoplayer.chunk.InitializationChunk; ...@@ -31,13 +31,11 @@ import com.google.android.exoplayer.chunk.InitializationChunk;
import com.google.android.exoplayer.chunk.MediaChunk; import com.google.android.exoplayer.chunk.MediaChunk;
import com.google.android.exoplayer.chunk.SingleSampleMediaChunk; import com.google.android.exoplayer.chunk.SingleSampleMediaChunk;
import com.google.android.exoplayer.dash.mpd.AdaptationSet; import com.google.android.exoplayer.dash.mpd.AdaptationSet;
import com.google.android.exoplayer.dash.mpd.ContentProtection;
import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription; import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;
import com.google.android.exoplayer.dash.mpd.Period; import com.google.android.exoplayer.dash.mpd.Period;
import com.google.android.exoplayer.dash.mpd.RangedUri; import com.google.android.exoplayer.dash.mpd.RangedUri;
import com.google.android.exoplayer.dash.mpd.Representation; import com.google.android.exoplayer.dash.mpd.Representation;
import com.google.android.exoplayer.drm.DrmInitData; import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.ChunkIndex; import com.google.android.exoplayer.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.SeekMap;
import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
...@@ -50,7 +48,6 @@ import com.google.android.exoplayer.util.Util; ...@@ -50,7 +48,6 @@ import com.google.android.exoplayer.util.Util;
import android.os.SystemClock; import android.os.SystemClock;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -70,7 +67,6 @@ public class DashChunkSource implements ChunkSource { ...@@ -70,7 +67,6 @@ public class DashChunkSource implements ChunkSource {
private final Evaluation evaluation; private final Evaluation evaluation;
private MediaPresentationDescription manifest; private MediaPresentationDescription manifest;
private DrmInitData drmInitData;
private boolean lastChunkWasInitialization; private boolean lastChunkWasInitialization;
private IOException fatalError; private IOException fatalError;
...@@ -100,7 +96,6 @@ public class DashChunkSource implements ChunkSource { ...@@ -100,7 +96,6 @@ public class DashChunkSource implements ChunkSource {
Period period = manifest.getPeriod(0); Period period = manifest.getPeriod(0);
long periodDurationUs = getPeriodDurationUs(manifest, 0); long periodDurationUs = getPeriodDurationUs(manifest, 0);
AdaptationSet adaptationSet = period.adaptationSets.get(adaptationSetIndex); AdaptationSet adaptationSet = period.adaptationSets.get(adaptationSetIndex);
drmInitData = getDrmInitData(adaptationSet);
List<Representation> representations = adaptationSet.representations; List<Representation> representations = adaptationSet.representations;
representationHolders = new RepresentationHolder[representations.size()]; representationHolders = new RepresentationHolder[representations.size()];
...@@ -257,7 +252,7 @@ public class DashChunkSource implements ChunkSource { ...@@ -257,7 +252,7 @@ public class DashChunkSource implements ChunkSource {
representationHolders[getTrackIndex(initializationChunk.format)]; representationHolders[getTrackIndex(initializationChunk.format)];
Format sampleFormat = initializationChunk.getSampleFormat(); Format sampleFormat = initializationChunk.getSampleFormat();
if (sampleFormat != null) { if (sampleFormat != null) {
representationHolder.sampleFormat = sampleFormat; representationHolder.setSampleFormat(sampleFormat);
} }
// The null check avoids overwriting an index obtained from the manifest with one obtained // The null check avoids overwriting an index obtained from the manifest with one obtained
// from the stream. If the manifest defines an index then the stream shouldn't, but in cases // from the stream. If the manifest defines an index then the stream shouldn't, but in cases
...@@ -269,11 +264,6 @@ public class DashChunkSource implements ChunkSource { ...@@ -269,11 +264,6 @@ public class DashChunkSource implements ChunkSource {
initializationChunk.dataSpec.uri.toString()); initializationChunk.dataSpec.uri.toString());
} }
} }
// The null check avoids overwriting drmInitData obtained from the manifest with drmInitData
// obtained from the stream, as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
if (drmInitData == null) {
drmInitData = initializationChunk.getDrmInitData();
}
} }
} }
...@@ -324,12 +314,12 @@ public class DashChunkSource implements ChunkSource { ...@@ -324,12 +314,12 @@ public class DashChunkSource implements ChunkSource {
if (representationHolder.extractorWrapper == null) { if (representationHolder.extractorWrapper == null) {
return new SingleSampleMediaChunk(dataSource, dataSpec, Chunk.TRIGGER_INITIAL, trackFormat, return new SingleSampleMediaChunk(dataSource, dataSpec, Chunk.TRIGGER_INITIAL, trackFormat,
startTimeUs, endTimeUs, segmentNum, trackFormat, null); startTimeUs, endTimeUs, segmentNum, trackFormat);
} else { } else {
long sampleOffsetUs = -representation.presentationTimeOffsetUs; long sampleOffsetUs = -representation.presentationTimeOffsetUs;
return new ContainerMediaChunk(dataSource, dataSpec, trigger, trackFormat, startTimeUs, return new ContainerMediaChunk(dataSource, dataSpec, trigger, trackFormat, startTimeUs,
endTimeUs, segmentNum, sampleOffsetUs, representationHolder.extractorWrapper, endTimeUs, segmentNum, sampleOffsetUs, representationHolder.extractorWrapper,
sampleFormat, drmInitData); sampleFormat);
} }
} }
...@@ -343,20 +333,6 @@ public class DashChunkSource implements ChunkSource { ...@@ -343,20 +333,6 @@ public class DashChunkSource implements ChunkSource {
throw new IllegalStateException("Invalid format: " + format); throw new IllegalStateException("Invalid format: " + format);
} }
private static DrmInitData getDrmInitData(AdaptationSet adaptationSet) {
ArrayList<SchemeData> schemeDatas = null;
for (int i = 0; i < adaptationSet.contentProtections.size(); i++) {
ContentProtection contentProtection = adaptationSet.contentProtections.get(i);
if (contentProtection.schemeData != null) {
if (schemeDatas == null) {
schemeDatas = new ArrayList<SchemeData>();
}
schemeDatas.add(contentProtection.schemeData);
}
}
return schemeDatas == null ? null : new DrmInitData(schemeDatas);
}
private static long getPeriodDurationUs(MediaPresentationDescription manifest, int index) { private static long getPeriodDurationUs(MediaPresentationDescription manifest, int index) {
long durationMs = manifest.getPeriodDuration(index); long durationMs = manifest.getPeriodDuration(index);
if (durationMs == -1) { if (durationMs == -1) {
...@@ -385,10 +361,20 @@ public class DashChunkSource implements ChunkSource { ...@@ -385,10 +361,20 @@ public class DashChunkSource implements ChunkSource {
String containerMimeType = representation.format.containerMimeType; String containerMimeType = representation.format.containerMimeType;
extractorWrapper = mimeTypeIsRawText(containerMimeType) ? null : new ChunkExtractorWrapper( extractorWrapper = mimeTypeIsRawText(containerMimeType) ? null : new ChunkExtractorWrapper(
mimeTypeIsWebm(containerMimeType) ? new MatroskaExtractor() mimeTypeIsWebm(containerMimeType) ? new MatroskaExtractor()
: new FragmentedMp4Extractor()); : new FragmentedMp4Extractor(), representation.format.drmInitData);
segmentIndex = representation.getIndex(); segmentIndex = representation.getIndex();
} }
public void setSampleFormat(Format sampleFormat) {
DrmInitData manifestDrmInitData = representation.format.drmInitData;
if (manifestDrmInitData != null) {
// Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream,
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
sampleFormat = sampleFormat.copyWithDrmInitData(manifestDrmInitData);
}
this.sampleFormat = sampleFormat;
}
public void updateRepresentation(long newPeriodDurationUs, Representation newRepresentation) public void updateRepresentation(long newPeriodDurationUs, Representation newRepresentation)
throws BehindLiveWindowException{ throws BehindLiveWindowException{
DashSegmentIndex oldIndex = representation.getIndex(); DashSegmentIndex oldIndex = representation.getIndex();
......
...@@ -28,26 +28,11 @@ public class AdaptationSet { ...@@ -28,26 +28,11 @@ public class AdaptationSet {
public final int type; public final int type;
public final List<Representation> representations; public final List<Representation> representations;
public final List<ContentProtection> contentProtections;
public AdaptationSet(int id, int type, List<Representation> representations, public AdaptationSet(int id, int type, List<Representation> representations) {
List<ContentProtection> contentProtections) {
this.id = id; this.id = id;
this.type = type; this.type = type;
this.representations = Collections.unmodifiableList(representations); this.representations = Collections.unmodifiableList(representations);
if (contentProtections == null) {
this.contentProtections = Collections.emptyList();
} else {
this.contentProtections = Collections.unmodifiableList(contentProtections);
}
}
public AdaptationSet(int id, int type, List<Representation> representations) {
this(id, type, representations, null);
}
public boolean hasContentProtection() {
return !contentProtections.isEmpty();
} }
} }
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.dash.mpd;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
/**
* Represents a ContentProtection tag in an AdaptationSet.
*/
public class ContentProtection {
/**
* Identifies the content protection scheme.
*/
public final String schemeUriId;
/**
* Protection scheme specific initialization data. May be null.
*/
public final SchemeData schemeData;
/**
* @param schemeUriId Identifies the content protection scheme.
* @param schemeData Protection scheme specific initialization data. May be null.
*/
public ContentProtection(String schemeUriId, SchemeData schemeData) {
this.schemeUriId = Assertions.checkNotNull(schemeUriId);
this.schemeData = schemeData;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ContentProtection)) {
return false;
}
if (obj == this) {
return true;
}
ContentProtection other = (ContentProtection) obj;
return schemeUriId.equals(other.schemeUriId) && Util.areEqual(schemeData, other.schemeData);
}
@Override
public int hashCode() {
return (31 * schemeUriId.hashCode()) + (schemeData != null ? schemeData.hashCode() : 0);
}
}
...@@ -637,6 +637,8 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -637,6 +637,8 @@ public final class DefaultTrackOutput implements TrackOutput {
* buffer is stored in {@code extrasHolder}, along with an encryption id if present and the * buffer is stored in {@code extrasHolder}, along with an encryption id if present and the
* absolute position of the first byte that may still be required after the current sample * absolute position of the first byte that may still be required after the current sample
* has been read. * has been read.
* @param downstreamFormat The current downstream {@link Format}. If the format of the next
* sample is different to the current downstream format then a format will be read.
* @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 The result, which can be {@link TrackStream#NOTHING_READ}, * @return The result, which can be {@link TrackStream#NOTHING_READ},
* {@link TrackStream#FORMAT_READ} or {@link TrackStream#BUFFER_READ}. * {@link TrackStream#FORMAT_READ} or {@link TrackStream#BUFFER_READ}.
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
*/ */
package com.google.android.exoplayer.extractor; package com.google.android.exoplayer.extractor;
import com.google.android.exoplayer.drm.DrmInitData;
/** /**
* Receives stream level data extracted by an {@link Extractor}. * Receives stream level data extracted by an {@link Extractor}.
*/ */
...@@ -45,11 +43,4 @@ public interface ExtractorOutput { ...@@ -45,11 +43,4 @@ public interface ExtractorOutput {
*/ */
void seekMap(SeekMap seekMap); void seekMap(SeekMap seekMap);
/**
* Invoked when {@link DrmInitData} has been extracted from the stream.
*
* @param drmInitData The extracted {@link DrmInitData}.
*/
void drmInitData(DrmInitData drmInitData);
} }
...@@ -24,7 +24,6 @@ import com.google.android.exoplayer.TrackGroup; ...@@ -24,7 +24,6 @@ import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray; import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackSelection; import com.google.android.exoplayer.TrackSelection;
import com.google.android.exoplayer.TrackStream; import com.google.android.exoplayer.TrackStream;
import com.google.android.exoplayer.drm.DrmInitData;
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;
import com.google.android.exoplayer.upstream.DataSpec; import com.google.android.exoplayer.upstream.DataSpec;
...@@ -211,7 +210,6 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -211,7 +210,6 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
private volatile boolean tracksBuilt; private volatile boolean tracksBuilt;
private volatile SeekMap seekMap; private volatile SeekMap seekMap;
private volatile DrmInitData drmInitData;
private boolean prepared; private boolean prepared;
private boolean seenFirstTrackSelection; private boolean seenFirstTrackSelection;
...@@ -471,12 +469,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -471,12 +469,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
return TrackStream.NOTHING_READ; return TrackStream.NOTHING_READ;
} }
int result = sampleQueues[track].readData(formatHolder, buffer, loadingFinished, return sampleQueues[track].readData(formatHolder, buffer, loadingFinished, lastSeekPositionUs);
lastSeekPositionUs);
if (result == TrackStream.FORMAT_READ) {
formatHolder.drmInitData = drmInitData;
}
return result;
} }
// Loader.Callback implementation. // Loader.Callback implementation.
...@@ -530,11 +523,6 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu ...@@ -530,11 +523,6 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
this.seekMap = seekMap; this.seekMap = seekMap;
} }
@Override
public void drmInitData(DrmInitData drmInitData) {
this.drmInitData = drmInitData;
}
// Internal methods. // Internal methods.
private void seekToInternal(long positionUs) { private void seekToInternal(long positionUs) {
......
...@@ -88,7 +88,7 @@ import java.util.Collections; ...@@ -88,7 +88,7 @@ import java.util.Collections;
audioSpecifiConfig); audioSpecifiConfig);
Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_AAC, Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_AAC,
Format.NO_VALUE, Format.NO_VALUE, audioParams.second, audioParams.first, Format.NO_VALUE, Format.NO_VALUE, audioParams.second, audioParams.first,
Collections.singletonList(audioSpecifiConfig), null); Collections.singletonList(audioSpecifiConfig), null, null);
output.format(format); output.format(format);
hasOutputFormat = true; hasOutputFormat = true;
} else if (packetType == AAC_PACKET_TYPE_AAC_RAW) { } else if (packetType == AAC_PACKET_TYPE_AAC_RAW) {
......
...@@ -96,7 +96,7 @@ import java.util.List; ...@@ -96,7 +96,7 @@ import java.util.List;
Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264,
Format.NO_VALUE, Format.NO_VALUE, avcData.width, avcData.height, Format.NO_VALUE, Format.NO_VALUE, avcData.width, avcData.height,
Format.NO_VALUE, avcData.initializationData, Format.NO_VALUE, Format.NO_VALUE, avcData.initializationData, Format.NO_VALUE,
avcData.pixelWidthAspectRatio); avcData.pixelWidthAspectRatio, null);
output.format(format); output.format(format);
hasOutputFormat = true; hasOutputFormat = true;
} else if (packetType == AVC_PACKET_TYPE_AVC_NALU) { } else if (packetType == AVC_PACKET_TYPE_AVC_NALU) {
......
...@@ -220,8 +220,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -220,8 +220,7 @@ public final class MatroskaExtractor implements Extractor {
// The track corresponding to the current TrackEntry element, or null. // The track corresponding to the current TrackEntry element, or null.
private Track currentTrack; private Track currentTrack;
// Whether drm init data has been sent to the output. // Whether a seek map has been sent to the output.
private boolean sentDrmInitData;
private boolean sentSeekMap; private boolean sentSeekMap;
// Master seek entry related elements. // Master seek entry related elements.
...@@ -483,11 +482,8 @@ public final class MatroskaExtractor implements Extractor { ...@@ -483,11 +482,8 @@ public final class MatroskaExtractor implements Extractor {
if (currentTrack.encryptionKeyId == null) { if (currentTrack.encryptionKeyId == null) {
throw new ParserException("Encrypted Track found but ContentEncKeyID was not found"); throw new ParserException("Encrypted Track found but ContentEncKeyID was not found");
} }
if (!sentDrmInitData) { currentTrack.drmInitData = new DrmInitData(
extractorOutput.drmInitData(new DrmInitData( new SchemeData(C.UUID_NIL, MimeTypes.VIDEO_WEBM, currentTrack.encryptionKeyId));
new SchemeData(C.UUID_NIL, MimeTypes.VIDEO_WEBM, currentTrack.encryptionKeyId)));
sentDrmInitData = true;
}
} }
return; return;
case ID_CONTENT_ENCODINGS: case ID_CONTENT_ENCODINGS:
...@@ -1182,6 +1178,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1182,6 +1178,7 @@ public final class MatroskaExtractor implements Extractor {
public byte[] sampleStrippedBytes; public byte[] sampleStrippedBytes;
public byte[] encryptionKeyId; public byte[] encryptionKeyId;
public byte[] codecPrivate; public byte[] codecPrivate;
public DrmInitData drmInitData;
// Video elements. // Video elements.
public int width = Format.NO_VALUE; public int width = Format.NO_VALUE;
...@@ -1323,7 +1320,8 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1323,7 +1320,8 @@ public final class MatroskaExtractor implements Extractor {
// into the trackId passed when creating the formats. // into the trackId passed when creating the formats.
if (MimeTypes.isAudio(mimeType)) { if (MimeTypes.isAudio(mimeType)) {
format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType, format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
Format.NO_VALUE, maxInputSize, channelCount, sampleRate, initializationData, language); Format.NO_VALUE, maxInputSize, channelCount, sampleRate, initializationData, language,
drmInitData);
} else if (MimeTypes.isVideo(mimeType)) { } else if (MimeTypes.isVideo(mimeType)) {
if (displayUnit == Track.DISPLAY_UNIT_PIXELS) { if (displayUnit == Track.DISPLAY_UNIT_PIXELS) {
displayWidth = displayWidth == Format.NO_VALUE ? width : displayWidth; displayWidth = displayWidth == Format.NO_VALUE ? width : displayWidth;
...@@ -1335,14 +1333,14 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1335,14 +1333,14 @@ public final class MatroskaExtractor implements Extractor {
} }
format = Format.createVideoSampleFormat(Integer.toString(trackId), mimeType, format = Format.createVideoSampleFormat(Integer.toString(trackId), mimeType,
Format.NO_VALUE, maxInputSize, width, height, Format.NO_VALUE, initializationData, Format.NO_VALUE, maxInputSize, width, height, Format.NO_VALUE, initializationData,
Format.NO_VALUE, pixelWidthHeightRatio); Format.NO_VALUE, pixelWidthHeightRatio, drmInitData);
} else if (MimeTypes.APPLICATION_SUBRIP.equals(mimeType)) { } else if (MimeTypes.APPLICATION_SUBRIP.equals(mimeType)) {
format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, Format.NO_VALUE, format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, Format.NO_VALUE,
language); language, drmInitData);
} else if (MimeTypes.APPLICATION_VOBSUB.equals(mimeType) } else if (MimeTypes.APPLICATION_VOBSUB.equals(mimeType)
|| MimeTypes.APPLICATION_PGS.equals(mimeType)) { || MimeTypes.APPLICATION_PGS.equals(mimeType)) {
format = Format.createImageSampleFormat(Integer.toString(trackId), mimeType, format = Format.createImageSampleFormat(Integer.toString(trackId), mimeType,
Format.NO_VALUE, initializationData, language); Format.NO_VALUE, initializationData, language, drmInitData);
} else { } else {
throw new ParserException("Unexpected MIME type."); throw new ParserException("Unexpected MIME type.");
} }
......
...@@ -128,7 +128,7 @@ public final class Mp3Extractor implements Extractor { ...@@ -128,7 +128,7 @@ public final class Mp3Extractor implements Extractor {
trackOutput.format(Format.createAudioSampleFormat(null, synchronizedHeader.mimeType, trackOutput.format(Format.createAudioSampleFormat(null, synchronizedHeader.mimeType,
Format.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, synchronizedHeader.channels, Format.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, synchronizedHeader.channels,
synchronizedHeader.sampleRate, gaplessInfoHolder.encoderDelay, synchronizedHeader.sampleRate, gaplessInfoHolder.encoderDelay,
gaplessInfoHolder.encoderPadding, null, null)); gaplessInfoHolder.encoderPadding, null, null, null));
} }
return readSample(input); return readSample(input);
} }
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.extractor.mp4; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.extractor.mp4;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.GaplessInfoHolder; import com.google.android.exoplayer.extractor.GaplessInfoHolder;
import com.google.android.exoplayer.util.Ac3Util; import com.google.android.exoplayer.util.Ac3Util;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
...@@ -49,10 +50,12 @@ import java.util.List; ...@@ -49,10 +50,12 @@ import java.util.List;
* *
* @param trak Atom to parse. * @param trak Atom to parse.
* @param mvhd Movie header atom, used to get the timescale. * @param mvhd Movie header atom, used to get the timescale.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param isQuickTime True for QuickTime media. False otherwise. * @param isQuickTime True for QuickTime media. False otherwise.
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported. * @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
*/ */
public static Track parseTrak(Atom.ContainerAtom trak, Atom.LeafAtom mvhd, boolean isQuickTime) { public static Track parseTrak(Atom.ContainerAtom trak, Atom.LeafAtom mvhd,
DrmInitData drmInitData, boolean isQuickTime) {
Atom.ContainerAtom mdia = trak.getContainerAtomOfType(Atom.TYPE_mdia); Atom.ContainerAtom mdia = trak.getContainerAtomOfType(Atom.TYPE_mdia);
int trackType = parseHdlr(mdia.getLeafAtomOfType(Atom.TYPE_hdlr).data); int trackType = parseHdlr(mdia.getLeafAtomOfType(Atom.TYPE_hdlr).data);
if (trackType == C.TRACK_TYPE_UNKNOWN) { if (trackType == C.TRACK_TYPE_UNKNOWN) {
...@@ -73,7 +76,7 @@ import java.util.List; ...@@ -73,7 +76,7 @@ import java.util.List;
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data); Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id, StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id,
tkhdData.rotationDegrees, mdhdData.second, isQuickTime); tkhdData.rotationDegrees, mdhdData.second, drmInitData, isQuickTime);
Pair<long[], long[]> edtsData = parseEdts(trak.getContainerAtomOfType(Atom.TYPE_edts)); Pair<long[], long[]> edtsData = parseEdts(trak.getContainerAtomOfType(Atom.TYPE_edts));
return stsdData.format == null ? null return stsdData.format == null ? null
: new Track(tkhdData.id, trackType, mdhdData.first, movieTimescale, durationUs, : new Track(tkhdData.id, trackType, mdhdData.first, movieTimescale, durationUs,
...@@ -560,11 +563,12 @@ import java.util.List; ...@@ -560,11 +563,12 @@ import java.util.List;
* @param trackId The track's identifier in its container. * @param trackId The track's identifier in its container.
* @param rotationDegrees The rotation of the track in degrees. * @param rotationDegrees The rotation of the track in degrees.
* @param language The language of the track. * @param language The language of the track.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param isQuickTime True for QuickTime media. False otherwise. * @param isQuickTime True for QuickTime media. False otherwise.
* @return An object containing the parsed data. * @return An object containing the parsed data.
*/ */
private static StsdData parseStsd(ParsableByteArray stsd, int trackId, int rotationDegrees, private static StsdData parseStsd(ParsableByteArray stsd, int trackId, int rotationDegrees,
String language, boolean isQuickTime) { String language, DrmInitData drmInitData, boolean isQuickTime) {
stsd.setPosition(Atom.FULL_HEADER_SIZE); stsd.setPosition(Atom.FULL_HEADER_SIZE);
int numberOfEntries = stsd.readInt(); int numberOfEntries = stsd.readInt();
StsdData out = new StsdData(numberOfEntries); StsdData out = new StsdData(numberOfEntries);
...@@ -578,7 +582,7 @@ import java.util.List; ...@@ -578,7 +582,7 @@ import java.util.List;
|| childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1 || childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1
|| childAtomType == Atom.TYPE_s263) { || childAtomType == Atom.TYPE_s263) {
parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, trackId, rotationDegrees, parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, trackId, rotationDegrees,
out, i); drmInitData, out, i);
} else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca } else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca
|| childAtomType == Atom.TYPE_ac_3 || childAtomType == Atom.TYPE_ec_3 || childAtomType == Atom.TYPE_ac_3 || childAtomType == Atom.TYPE_ec_3
|| childAtomType == Atom.TYPE_dtsc || childAtomType == Atom.TYPE_dtse || childAtomType == Atom.TYPE_dtsc || childAtomType == Atom.TYPE_dtse
...@@ -586,19 +590,19 @@ import java.util.List; ...@@ -586,19 +590,19 @@ import java.util.List;
|| childAtomType == Atom.TYPE_samr || childAtomType == Atom.TYPE_sawb || childAtomType == Atom.TYPE_samr || childAtomType == Atom.TYPE_sawb
|| childAtomType == Atom.TYPE_lpcm || childAtomType == Atom.TYPE_sowt) { || childAtomType == Atom.TYPE_lpcm || childAtomType == Atom.TYPE_sowt) {
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId, parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId,
language, isQuickTime, out, i); language, isQuickTime, drmInitData, out, i);
} else if (childAtomType == Atom.TYPE_TTML) { } else if (childAtomType == Atom.TYPE_TTML) {
out.format = Format.createTextSampleFormat(Integer.toString(trackId), out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_TTML, Format.NO_VALUE, language); MimeTypes.APPLICATION_TTML, Format.NO_VALUE, language, drmInitData);
} else if (childAtomType == Atom.TYPE_tx3g) { } else if (childAtomType == Atom.TYPE_tx3g) {
out.format = Format.createTextSampleFormat(Integer.toString(trackId), out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_TX3G, Format.NO_VALUE, language); MimeTypes.APPLICATION_TX3G, Format.NO_VALUE, language, drmInitData);
} else if (childAtomType == Atom.TYPE_wvtt) { } else if (childAtomType == Atom.TYPE_wvtt) {
out.format = Format.createTextSampleFormat(Integer.toString(trackId), out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_MP4VTT, Format.NO_VALUE, language); MimeTypes.APPLICATION_MP4VTT, Format.NO_VALUE, language, drmInitData);
} else if (childAtomType == Atom.TYPE_stpp) { } else if (childAtomType == Atom.TYPE_stpp) {
out.format = Format.createTextSampleFormat(Integer.toString(trackId), out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_TTML, Format.NO_VALUE, language, MimeTypes.APPLICATION_TTML, Format.NO_VALUE, language, drmInitData,
0 /* subsample timing is absolute */); 0 /* subsample timing is absolute */);
} }
stsd.setPosition(childStartPosition + childAtomSize); stsd.setPosition(childStartPosition + childAtomSize);
...@@ -607,7 +611,7 @@ import java.util.List; ...@@ -607,7 +611,7 @@ import java.util.List;
} }
private static void parseVideoSampleEntry(ParsableByteArray parent, int position, int size, private static void parseVideoSampleEntry(ParsableByteArray parent, int position, int size,
int trackId, int rotationDegrees, StsdData out, int entryIndex) { int trackId, int rotationDegrees, DrmInitData drmInitData, StsdData out, int entryIndex) {
parent.setPosition(position + Atom.HEADER_SIZE); parent.setPosition(position + Atom.HEADER_SIZE);
parent.skipBytes(24); parent.skipBytes(24);
...@@ -671,7 +675,7 @@ import java.util.List; ...@@ -671,7 +675,7 @@ import java.util.List;
out.format = Format.createVideoSampleFormat(Integer.toString(trackId), mimeType, out.format = Format.createVideoSampleFormat(Integer.toString(trackId), mimeType,
Format.NO_VALUE, Format.NO_VALUE, width, height, Format.NO_VALUE, initializationData, Format.NO_VALUE, Format.NO_VALUE, width, height, Format.NO_VALUE, initializationData,
rotationDegrees, pixelWidthHeightRatio); rotationDegrees, pixelWidthHeightRatio, drmInitData);
} }
private static AvcCData parseAvcCFromParent(ParsableByteArray parent, int position) { private static AvcCData parseAvcCFromParent(ParsableByteArray parent, int position) {
...@@ -830,7 +834,8 @@ import java.util.List; ...@@ -830,7 +834,8 @@ import java.util.List;
} }
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position, private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
int size, int trackId, String language, boolean isQuickTime, StsdData out, int entryIndex) { int size, int trackId, String language, boolean isQuickTime, DrmInitData drmInitData,
StsdData out, int entryIndex) {
parent.setPosition(position + Atom.HEADER_SIZE); parent.setPosition(position + Atom.HEADER_SIZE);
int quickTimeSoundDescriptionVersion = 0; int quickTimeSoundDescriptionVersion = 0;
...@@ -922,17 +927,20 @@ import java.util.List; ...@@ -922,17 +927,20 @@ import java.util.List;
// TODO: Choose the right AC-3 track based on the contents of dac3/dec3. // TODO: Choose the right AC-3 track based on the contents of dac3/dec3.
// TODO: Add support for encryption (by setting out.trackEncryptionBoxes). // TODO: Add support for encryption (by setting out.trackEncryptionBoxes).
parent.setPosition(Atom.HEADER_SIZE + childAtomPosition); parent.setPosition(Atom.HEADER_SIZE + childAtomPosition);
out.format = Ac3Util.parseAc3AnnexFFormat(parent, Integer.toString(trackId), language); out.format = Ac3Util.parseAc3AnnexFFormat(parent, Integer.toString(trackId), language,
drmInitData);
return; return;
} else if (atomType == Atom.TYPE_ec_3 && childAtomType == Atom.TYPE_dec3) { } else if (atomType == Atom.TYPE_ec_3 && childAtomType == Atom.TYPE_dec3) {
parent.setPosition(Atom.HEADER_SIZE + childAtomPosition); parent.setPosition(Atom.HEADER_SIZE + childAtomPosition);
out.format = Ac3Util.parseEAc3AnnexFFormat(parent, Integer.toString(trackId), language); out.format = Ac3Util.parseEAc3AnnexFFormat(parent, Integer.toString(trackId), language,
drmInitData);
return; return;
} else if ((atomType == Atom.TYPE_dtsc || atomType == Atom.TYPE_dtse } else if ((atomType == Atom.TYPE_dtsc || atomType == Atom.TYPE_dtse
|| atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl) || atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl)
&& childAtomType == Atom.TYPE_ddts) { && childAtomType == Atom.TYPE_ddts) {
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType, out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, language); Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, language,
drmInitData);
return; return;
} }
childAtomPosition += childAtomSize; childAtomPosition += childAtomSize;
...@@ -946,7 +954,7 @@ import java.util.List; ...@@ -946,7 +954,7 @@ import java.util.List;
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType, out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate,
initializationData == null ? null : Collections.singletonList(initializationData), initializationData == null ? null : Collections.singletonList(initializationData),
language); language, drmInitData);
} }
/** Returns the position of the esds box within a parent, or -1 if no esds box is found */ /** Returns the position of the esds box within a parent, or -1 if no esds box is found */
......
...@@ -335,9 +335,7 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -335,9 +335,7 @@ public final class FragmentedMp4Extractor implements Extractor {
} }
} }
} }
if (schemeDatas != null) { DrmInitData drmInitData = schemeDatas == null ? null : new DrmInitData(schemeDatas);
extractorOutput.drmInitData(new DrmInitData(schemeDatas));
}
// Read declaration of track fragments in the Moov box. // Read declaration of track fragments in the Moov box.
ContainerAtom mvex = moov.getContainerAtomOfType(Atom.TYPE_mvex); ContainerAtom mvex = moov.getContainerAtomOfType(Atom.TYPE_mvex);
...@@ -357,7 +355,8 @@ public final class FragmentedMp4Extractor implements Extractor { ...@@ -357,7 +355,8 @@ public final class FragmentedMp4Extractor implements Extractor {
for (int i = 0; i < moovContainerChildrenSize; i++) { for (int i = 0; i < moovContainerChildrenSize; i++) {
Atom.ContainerAtom atom = moov.containerChildren.get(i); Atom.ContainerAtom atom = moov.containerChildren.get(i);
if (atom.type == Atom.TYPE_trak) { if (atom.type == Atom.TYPE_trak) {
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), false); Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd),
drmInitData, false);
if (track != null) { if (track != null) {
tracks.put(track.id, track); tracks.put(track.id, track);
} }
......
...@@ -310,7 +310,7 @@ public final class Mp4Extractor implements Extractor, SeekMap { ...@@ -310,7 +310,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
continue; continue;
} }
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), null,
isQuickTime); isQuickTime);
if (track == null) { if (track == null) {
continue; continue;
......
...@@ -68,7 +68,7 @@ import java.util.List; ...@@ -68,7 +68,7 @@ import java.util.List;
List<byte[]> initializationData = Collections.singletonList(metadata); List<byte[]> initializationData = Collections.singletonList(metadata);
trackOutput.format(Format.createAudioSampleFormat(null, MimeTypes.AUDIO_FLAC, trackOutput.format(Format.createAudioSampleFormat(null, MimeTypes.AUDIO_FLAC,
streamInfo.bitRate(), Format.NO_VALUE, streamInfo.channels, streamInfo.sampleRate, streamInfo.bitRate(), Format.NO_VALUE, streamInfo.channels, streamInfo.sampleRate,
initializationData, null)); initializationData, null, null));
} else if (data[0] == AUDIO_PACKET_TYPE) { } else if (data[0] == AUDIO_PACKET_TYPE) {
if (!firstAudioPacketProcessed) { if (!firstAudioPacketProcessed) {
if (seekTable != null) { if (seekTable != null) {
......
...@@ -94,7 +94,7 @@ import java.util.ArrayList; ...@@ -94,7 +94,7 @@ import java.util.ArrayList;
trackOutput.format(Format.createAudioSampleFormat(null, MimeTypes.AUDIO_VORBIS, trackOutput.format(Format.createAudioSampleFormat(null, MimeTypes.AUDIO_VORBIS,
this.vorbisSetup.idHeader.bitrateNominal, OggParser.OGG_MAX_SEGMENT_SIZE * 255, this.vorbisSetup.idHeader.bitrateNominal, OggParser.OGG_MAX_SEGMENT_SIZE * 255,
this.vorbisSetup.idHeader.channels, (int) this.vorbisSetup.idHeader.sampleRate, this.vorbisSetup.idHeader.channels, (int) this.vorbisSetup.idHeader.sampleRate,
codecInitialisationData, null)); codecInitialisationData, null, null));
if (inputLength != C.LENGTH_UNBOUNDED) { if (inputLength != C.LENGTH_UNBOUNDED) {
oggSeeker.setup(inputLength - audioStartPosition, totalSamples); oggSeeker.setup(inputLength - audioStartPosition, totalSamples);
......
...@@ -162,9 +162,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -162,9 +162,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
*/ */
private void parseHeader() { private void parseHeader() {
if (format == null) { if (format == null) {
format = isEac3 format = isEac3 ? Ac3Util.parseEac3SyncframeFormat(headerScratchBits, null, null, null)
? Ac3Util.parseEac3SyncframeFormat(headerScratchBits, null, null) : Ac3Util.parseAc3SyncframeFormat(headerScratchBits, null, null, null);
: Ac3Util.parseAc3SyncframeFormat(headerScratchBits, null, null);
output.format(format); output.format(format);
} }
sampleSize = isEac3 ? Ac3Util.parseEAc3SyncframeSize(headerScratchBits.data) sampleSize = isEac3 ? Ac3Util.parseEAc3SyncframeSize(headerScratchBits.data)
......
...@@ -84,7 +84,8 @@ import java.util.Collections; ...@@ -84,7 +84,8 @@ import java.util.Collections;
public AdtsReader(TrackOutput output, TrackOutput id3Output) { public AdtsReader(TrackOutput output, TrackOutput id3Output) {
super(output); super(output);
this.id3Output = id3Output; this.id3Output = id3Output;
id3Output.format(Format.createSampleFormat(null, MimeTypes.APPLICATION_ID3, Format.NO_VALUE)); id3Output.format(Format.createSampleFormat(null, MimeTypes.APPLICATION_ID3, Format.NO_VALUE,
null));
adtsScratch = new ParsableBitArray(new byte[HEADER_SIZE + CRC_SIZE]); adtsScratch = new ParsableBitArray(new byte[HEADER_SIZE + CRC_SIZE]);
id3HeaderBuffer = new ParsableByteArray(Arrays.copyOf(ID3_IDENTIFIER, ID3_HEADER_SIZE)); id3HeaderBuffer = new ParsableByteArray(Arrays.copyOf(ID3_IDENTIFIER, ID3_HEADER_SIZE));
setFindingSampleState(); setFindingSampleState();
...@@ -275,7 +276,7 @@ import java.util.Collections; ...@@ -275,7 +276,7 @@ import java.util.Collections;
Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_AAC, Format.NO_VALUE, Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_AAC, Format.NO_VALUE,
Format.NO_VALUE, audioParams.second, audioParams.first, Format.NO_VALUE, audioParams.second, audioParams.first,
Collections.singletonList(audioSpecificConfig), null); Collections.singletonList(audioSpecificConfig), null, null);
// In this class a sample is an access unit, but the MediaFormat sample rate specifies the // In this class a sample is an access unit, but the MediaFormat sample rate specifies the
// number of PCM audio samples per second. // number of PCM audio samples per second.
sampleDurationUs = (C.MICROS_PER_SECOND * 1024) / format.sampleRate; sampleDurationUs = (C.MICROS_PER_SECOND * 1024) / format.sampleRate;
......
...@@ -155,7 +155,7 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -155,7 +155,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
private void parseHeader() { private void parseHeader() {
byte[] frameData = headerScratchBytes.data; byte[] frameData = headerScratchBytes.data;
if (format == null) { if (format == null) {
format = DtsUtil.parseDtsFormat(frameData, null, null); format = DtsUtil.parseDtsFormat(frameData, null, null, null);
output.format(format); output.format(format);
} }
sampleSize = DtsUtil.getDtsFrameSize(frameData); sampleSize = DtsUtil.getDtsFrameSize(frameData);
......
...@@ -191,7 +191,7 @@ import java.util.Collections; ...@@ -191,7 +191,7 @@ import java.util.Collections;
Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_MPEG2, Format.NO_VALUE, Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_MPEG2, Format.NO_VALUE,
Format.NO_VALUE, width, height, Format.NO_VALUE, Collections.singletonList(csdData), Format.NO_VALUE, width, height, Format.NO_VALUE, Collections.singletonList(csdData),
Format.NO_VALUE, pixelWidthHeightRatio); Format.NO_VALUE, pixelWidthHeightRatio, null);
long frameDurationUs = 0; long frameDurationUs = 0;
int frameRateCodeMinusOne = (csdData[7] & 0x0F) - 1; int frameRateCodeMinusOne = (csdData[7] & 0x0F) - 1;
......
...@@ -171,7 +171,7 @@ import java.util.List; ...@@ -171,7 +171,7 @@ import java.util.List;
NalUnitUtil.PpsData ppsData = NalUnitUtil.parsePpsNalUnit(pps.nalData, 3, pps.nalLength); NalUnitUtil.PpsData ppsData = NalUnitUtil.parsePpsNalUnit(pps.nalData, 3, pps.nalLength);
output.format(Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, Format.NO_VALUE, output.format(Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, Format.NO_VALUE,
Format.NO_VALUE, spsData.width, spsData.height, Format.NO_VALUE, initializationData, Format.NO_VALUE, spsData.width, spsData.height, Format.NO_VALUE, initializationData,
Format.NO_VALUE, spsData.pixelWidthAspectRatio)); Format.NO_VALUE, spsData.pixelWidthAspectRatio, null));
hasOutputFormat = true; hasOutputFormat = true;
sampleReader.putSps(spsData); sampleReader.putSps(spsData);
sampleReader.putPps(ppsData); sampleReader.putPps(ppsData);
......
...@@ -309,7 +309,7 @@ import java.util.Collections; ...@@ -309,7 +309,7 @@ import java.util.Collections;
return Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H265, Format.NO_VALUE, return Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H265, Format.NO_VALUE,
Format.NO_VALUE, picWidthInLumaSamples, picHeightInLumaSamples, Format.NO_VALUE, Format.NO_VALUE, picWidthInLumaSamples, picHeightInLumaSamples, Format.NO_VALUE,
Collections.singletonList(csd), Format.NO_VALUE, pixelWidthHeightRatio); Collections.singletonList(csd), Format.NO_VALUE, pixelWidthHeightRatio, null);
} }
/** /**
......
...@@ -40,7 +40,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -40,7 +40,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public Id3Reader(TrackOutput output) { public Id3Reader(TrackOutput output) {
super(output); super(output);
output.format(Format.createSampleFormat(null, MimeTypes.APPLICATION_ID3, Format.NO_VALUE)); output.format(Format.createSampleFormat(null, MimeTypes.APPLICATION_ID3, Format.NO_VALUE,
null));
id3Header = new ParsableByteArray(ID3_HEADER_SIZE); id3Header = new ParsableByteArray(ID3_HEADER_SIZE);
} }
......
...@@ -163,7 +163,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -163,7 +163,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
if (!hasOutputFormat) { if (!hasOutputFormat) {
frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate; frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate;
Format format = Format.createAudioSampleFormat(null, header.mimeType, Format.NO_VALUE, Format format = Format.createAudioSampleFormat(null, header.mimeType, Format.NO_VALUE,
MpegAudioHeader.MAX_FRAME_SIZE_BYTES, header.channels, header.sampleRate, null, null); MpegAudioHeader.MAX_FRAME_SIZE_BYTES, header.channels, header.sampleRate, null, null,
null);
output.format(format); output.format(format);
hasOutputFormat = true; hasOutputFormat = true;
} }
......
...@@ -34,7 +34,7 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -34,7 +34,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public SeiReader(TrackOutput output) { public SeiReader(TrackOutput output) {
this.output = output; this.output = output;
output.format(Format.createTextSampleFormat(null, MimeTypes.APPLICATION_EIA608, Format.NO_VALUE, output.format(Format.createTextSampleFormat(null, MimeTypes.APPLICATION_EIA608, Format.NO_VALUE,
null)); null, null));
} }
public void consume(long pesTimeUs, ParsableByteArray seiBuffer) { public void consume(long pesTimeUs, ParsableByteArray seiBuffer) {
......
...@@ -74,7 +74,7 @@ public final class WavExtractor implements Extractor, SeekMap { ...@@ -74,7 +74,7 @@ public final class WavExtractor implements Extractor, SeekMap {
} }
Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, Format format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW,
wavHeader.getBitrate(), MAX_INPUT_SIZE, wavHeader.getNumChannels(), wavHeader.getBitrate(), MAX_INPUT_SIZE, wavHeader.getNumChannels(),
wavHeader.getSampleRateHz(), null, null); wavHeader.getSampleRateHz(), null, null, null);
trackOutput.format(format); trackOutput.format(format);
bytesPerFrame = wavHeader.getBytesPerFrame(); bytesPerFrame = wavHeader.getBytesPerFrame();
} }
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer.hls; package com.google.android.exoplayer.hls;
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.ExtractorOutput; import com.google.android.exoplayer.extractor.ExtractorOutput;
import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.SeekMap;
...@@ -117,9 +116,4 @@ import android.util.SparseArray; ...@@ -117,9 +116,4 @@ import android.util.SparseArray;
// Do nothing. // Do nothing.
} }
@Override
public void drmInitData(DrmInitData drmInitData) {
// Do nothing.
}
} }
...@@ -166,7 +166,7 @@ import java.util.regex.Pattern; ...@@ -166,7 +166,7 @@ import java.util.regex.Pattern;
private TrackOutput buildTrackOutput(long subsampleOffsetUs) { private TrackOutput buildTrackOutput(long subsampleOffsetUs) {
TrackOutput trackOutput = output.track(0); TrackOutput trackOutput = output.track(0);
trackOutput.format(Format.createTextSampleFormat(null, MimeTypes.TEXT_VTT, Format.NO_VALUE, trackOutput.format(Format.createTextSampleFormat(null, MimeTypes.TEXT_VTT, Format.NO_VALUE,
language, subsampleOffsetUs)); language, null, subsampleOffsetUs));
output.endTracks(); output.endTracks();
return trackOutput; return trackOutput;
} }
......
...@@ -28,7 +28,6 @@ import com.google.android.exoplayer.chunk.ContainerMediaChunk; ...@@ -28,7 +28,6 @@ import com.google.android.exoplayer.chunk.ContainerMediaChunk;
import com.google.android.exoplayer.chunk.FormatEvaluator; import com.google.android.exoplayer.chunk.FormatEvaluator;
import com.google.android.exoplayer.chunk.FormatEvaluator.Evaluation; import com.google.android.exoplayer.chunk.FormatEvaluator.Evaluation;
import com.google.android.exoplayer.chunk.MediaChunk; import com.google.android.exoplayer.chunk.MediaChunk;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.mp4.FragmentedMp4Extractor; import com.google.android.exoplayer.extractor.mp4.FragmentedMp4Extractor;
import com.google.android.exoplayer.extractor.mp4.Track; import com.google.android.exoplayer.extractor.mp4.Track;
import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox; import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox;
...@@ -58,7 +57,6 @@ public class SmoothStreamingChunkSource implements ChunkSource { ...@@ -58,7 +57,6 @@ public class SmoothStreamingChunkSource implements ChunkSource {
private final FormatEvaluator adaptiveFormatEvaluator; private final FormatEvaluator adaptiveFormatEvaluator;
private SmoothStreamingManifest manifest; private SmoothStreamingManifest manifest;
private DrmInitData drmInitData;
private int currentManifestChunkOffset; private int currentManifestChunkOffset;
private boolean needManifestRefresh; private boolean needManifestRefresh;
...@@ -72,18 +70,15 @@ public class SmoothStreamingChunkSource implements ChunkSource { ...@@ -72,18 +70,15 @@ public class SmoothStreamingChunkSource implements ChunkSource {
* @param dataSource A {@link DataSource} suitable for loading the media data. * @param dataSource A {@link DataSource} suitable for loading the media data.
* @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats. * @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats.
* @param trackEncryptionBoxes Track encryption boxes for the stream. * @param trackEncryptionBoxes Track encryption boxes for the stream.
* @param drmInitData Drm initialization data for the stream.
*/ */
public SmoothStreamingChunkSource(SmoothStreamingManifest manifest, int elementIndex, public SmoothStreamingChunkSource(SmoothStreamingManifest manifest, int elementIndex,
TrackGroup trackGroup, int[] tracks, DataSource dataSource, TrackGroup trackGroup, int[] tracks, DataSource dataSource,
FormatEvaluator adaptiveFormatEvaluator, TrackEncryptionBox[] trackEncryptionBoxes, FormatEvaluator adaptiveFormatEvaluator, TrackEncryptionBox[] trackEncryptionBoxes) {
DrmInitData drmInitData) {
this.manifest = manifest; this.manifest = manifest;
this.elementIndex = elementIndex; this.elementIndex = elementIndex;
this.trackGroup = trackGroup; this.trackGroup = trackGroup;
this.dataSource = dataSource; this.dataSource = dataSource;
this.adaptiveFormatEvaluator = adaptiveFormatEvaluator; this.adaptiveFormatEvaluator = adaptiveFormatEvaluator;
this.drmInitData = drmInitData;
this.evaluation = new Evaluation(); this.evaluation = new Evaluation();
StreamElement streamElement = manifest.streamElements[elementIndex]; StreamElement streamElement = manifest.streamElements[elementIndex];
...@@ -97,7 +92,7 @@ public class SmoothStreamingChunkSource implements ChunkSource { ...@@ -97,7 +92,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, track); | FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, track);
extractorWrappers[j] = new ChunkExtractorWrapper(extractor); extractorWrappers[j] = new ChunkExtractorWrapper(extractor, formats[j].drmInitData);
} }
enabledFormats = new Format[tracks.length]; enabledFormats = new Format[tracks.length];
...@@ -224,8 +219,7 @@ public class SmoothStreamingChunkSource implements ChunkSource { ...@@ -224,8 +219,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex); Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex);
out.chunk = newMediaChunk(selectedFormat, dataSource, uri, null, currentAbsoluteChunkIndex, out.chunk = newMediaChunk(selectedFormat, dataSource, uri, null, currentAbsoluteChunkIndex,
chunkStartTimeUs, chunkEndTimeUs, evaluation.trigger, extractorWrapper, drmInitData, chunkStartTimeUs, chunkEndTimeUs, evaluation.trigger, extractorWrapper);
selectedFormat);
} }
@Override @Override
...@@ -274,13 +268,13 @@ public class SmoothStreamingChunkSource implements ChunkSource { ...@@ -274,13 +268,13 @@ public class SmoothStreamingChunkSource implements ChunkSource {
private static MediaChunk newMediaChunk(Format format, DataSource dataSource, Uri uri, private static MediaChunk newMediaChunk(Format format, DataSource dataSource, Uri uri,
String cacheKey, int chunkIndex, long chunkStartTimeUs, long chunkEndTimeUs, int trigger, String cacheKey, int chunkIndex, long chunkStartTimeUs, long chunkEndTimeUs, int trigger,
ChunkExtractorWrapper extractorWrapper, DrmInitData drmInitData, Format sampleFormat) { ChunkExtractorWrapper extractorWrapper) {
DataSpec dataSpec = new DataSpec(uri, 0, -1, cacheKey); DataSpec dataSpec = new DataSpec(uri, 0, -1, cacheKey);
// In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk.
// To convert them the absolute timestamps, we need to set sampleOffsetUs to chunkStartTimeUs. // To convert them the absolute timestamps, we need to set sampleOffsetUs to chunkStartTimeUs.
long sampleOffsetUs = chunkStartTimeUs; long sampleOffsetUs = chunkStartTimeUs;
return new ContainerMediaChunk(dataSource, dataSpec, trigger, format, chunkStartTimeUs, return new ContainerMediaChunk(dataSource, dataSpec, trigger, format, chunkStartTimeUs,
chunkEndTimeUs, chunkIndex, sampleOffsetUs, extractorWrapper, sampleFormat, drmInitData); chunkEndTimeUs, chunkIndex, sampleOffsetUs, extractorWrapper, format);
} }
} }
...@@ -18,6 +18,8 @@ package com.google.android.exoplayer.smoothstreaming; ...@@ -18,6 +18,8 @@ package com.google.android.exoplayer.smoothstreaming;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.mp4.PsshAtomUtil; import com.google.android.exoplayer.extractor.mp4.PsshAtomUtil;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
...@@ -375,6 +377,15 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS ...@@ -375,6 +377,15 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
public Object build() { public Object build() {
StreamElement[] streamElementArray = new StreamElement[streamElements.size()]; StreamElement[] streamElementArray = new StreamElement[streamElements.size()];
streamElements.toArray(streamElementArray); streamElements.toArray(streamElementArray);
if (protectionElement != null) {
DrmInitData drmInitData = new DrmInitData(new SchemeData(protectionElement.uuid,
MimeTypes.VIDEO_MP4, protectionElement.data));
for (StreamElement streamElement : streamElementArray) {
for (int i = 0; i < streamElement.formats.length; i++) {
streamElement.formats[i] = streamElement.formats[i].copyWithDrmInitData(drmInitData);
}
}
}
return new SmoothStreamingManifest(majorVersion, minorVersion, timescale, duration, return new SmoothStreamingManifest(majorVersion, minorVersion, timescale, duration,
dvrWindowLength, lookAheadCount, isLive, protectionElement, streamElementArray); dvrWindowLength, lookAheadCount, isLive, protectionElement, streamElementArray);
} }
......
...@@ -28,8 +28,6 @@ import com.google.android.exoplayer.chunk.ChunkTrackStream; ...@@ -28,8 +28,6 @@ import com.google.android.exoplayer.chunk.ChunkTrackStream;
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener; import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
import com.google.android.exoplayer.chunk.FormatEvaluator; import com.google.android.exoplayer.chunk.FormatEvaluator;
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator; import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox; import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.ProtectionElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
...@@ -38,7 +36,6 @@ import com.google.android.exoplayer.upstream.DataSource; ...@@ -38,7 +36,6 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory; import com.google.android.exoplayer.upstream.DataSourceFactory;
import com.google.android.exoplayer.upstream.DefaultAllocator; import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.net.Uri; import android.net.Uri;
...@@ -69,7 +66,6 @@ public final class SmoothStreamingSampleSource implements SampleSource { ...@@ -69,7 +66,6 @@ public final class SmoothStreamingSampleSource implements SampleSource {
private long durationUs; private long durationUs;
private SmoothStreamingManifest currentManifest; private SmoothStreamingManifest currentManifest;
private TrackEncryptionBox[] trackEncryptionBoxes; private TrackEncryptionBox[] trackEncryptionBoxes;
private DrmInitData drmInitData;
private TrackGroupArray trackGroups; private TrackGroupArray trackGroups;
private int[] trackGroupElementIndices; private int[] trackGroupElementIndices;
private boolean pendingReset; private boolean pendingReset;
...@@ -117,10 +113,8 @@ public final class SmoothStreamingSampleSource implements SampleSource { ...@@ -117,10 +113,8 @@ public final class SmoothStreamingSampleSource implements SampleSource {
ProtectionElement protectionElement = currentManifest.protectionElement; ProtectionElement protectionElement = currentManifest.protectionElement;
if (protectionElement != null) { if (protectionElement != null) {
byte[] keyId = getProtectionElementKeyId(protectionElement.data); byte[] keyId = getProtectionElementKeyId(protectionElement.data);
trackEncryptionBoxes = new TrackEncryptionBox[1]; trackEncryptionBoxes = new TrackEncryptionBox[] {
trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId); new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId)};
drmInitData = new DrmInitData(
new SchemeData(protectionElement.uuid, MimeTypes.VIDEO_MP4, protectionElement.data));
} }
return true; return true;
} }
...@@ -279,7 +273,7 @@ public final class SmoothStreamingSampleSource implements SampleSource { ...@@ -279,7 +273,7 @@ public final class SmoothStreamingSampleSource implements SampleSource {
DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter); DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter);
SmoothStreamingChunkSource chunkSource = new SmoothStreamingChunkSource(currentManifest, SmoothStreamingChunkSource chunkSource = new SmoothStreamingChunkSource(currentManifest,
streamElementIndex, trackGroups.get(selection.group), selectedTracks, dataSource, streamElementIndex, trackGroups.get(selection.group), selectedTracks, dataSource,
adaptiveEvaluator, trackEncryptionBoxes, drmInitData); adaptiveEvaluator, trackEncryptionBoxes);
ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize, ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize,
positionUs, eventHandler, eventListener, streamElementType); positionUs, eventHandler, eventListener, streamElementType);
return Pair.create(chunkSource, trackStream); return Pair.create(chunkSource, trackStream);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer.util; package com.google.android.exoplayer.util;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.drm.DrmInitData;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
...@@ -66,10 +67,11 @@ public final class Ac3Util { ...@@ -66,10 +67,11 @@ public final class Ac3Util {
* @param data The AC3SpecificBox to parse. * @param data The AC3SpecificBox to parse.
* @param trackId The track identifier to set on the format, or null. * @param trackId The track identifier to set on the format, or null.
* @param language The language to set on the format. * @param language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The AC-3 format parsed from data in the header. * @return The AC-3 format parsed from data in the header.
*/ */
public static Format parseAc3AnnexFFormat(ParsableByteArray data, String trackId, public static Format parseAc3AnnexFFormat(ParsableByteArray data, String trackId,
String language) { String language, DrmInitData drmInitData) {
int fscod = (data.readUnsignedByte() & 0xC0) >> 6; int fscod = (data.readUnsignedByte() & 0xC0) >> 6;
int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod]; int sampleRate = SAMPLE_RATE_BY_FSCOD[fscod];
int nextByte = data.readUnsignedByte(); int nextByte = data.readUnsignedByte();
...@@ -78,7 +80,7 @@ public final class Ac3Util { ...@@ -78,7 +80,7 @@ public final class Ac3Util {
channelCount++; channelCount++;
} }
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE, return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE,
Format.NO_VALUE, channelCount, sampleRate, null, language); Format.NO_VALUE, channelCount, sampleRate, null, language, drmInitData);
} }
/** /**
...@@ -88,10 +90,11 @@ public final class Ac3Util { ...@@ -88,10 +90,11 @@ public final class Ac3Util {
* @param data The EC3SpecificBox to parse. * @param data The EC3SpecificBox to parse.
* @param trackId The track identifier to set on the format, or null. * @param trackId The track identifier to set on the format, or null.
* @param language The language to set on the format. * @param language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The E-AC-3 format parsed from data in the header. * @return The E-AC-3 format parsed from data in the header.
*/ */
public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackId, public static Format parseEAc3AnnexFFormat(ParsableByteArray data, String trackId,
String language) { String language, DrmInitData drmInitData) {
data.skipBytes(2); // data_rate, num_ind_sub data.skipBytes(2); // data_rate, num_ind_sub
// Read only the first substream. // Read only the first substream.
...@@ -104,7 +107,7 @@ public final class Ac3Util { ...@@ -104,7 +107,7 @@ public final class Ac3Util {
channelCount++; channelCount++;
} }
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE, return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE,
Format.NO_VALUE, channelCount, sampleRate, null, language); Format.NO_VALUE, channelCount, sampleRate, null, language, drmInitData);
} }
/** /**
...@@ -114,10 +117,11 @@ public final class Ac3Util { ...@@ -114,10 +117,11 @@ public final class Ac3Util {
* @param data The data to parse, positioned at the start of the syncframe. * @param data The data to parse, positioned at the start of the syncframe.
* @param trackId The track identifier to set on the format, or null. * @param trackId The track identifier to set on the format, or null.
* @param language The language to set on the format. * @param language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The AC-3 format parsed from data in the header. * @return The AC-3 format parsed from data in the header.
*/ */
public static Format parseAc3SyncframeFormat(ParsableBitArray data, String trackId, public static Format parseAc3SyncframeFormat(ParsableBitArray data, String trackId,
String language) { String language, DrmInitData drmInitData) {
data.skipBits(16 + 16); // syncword, crc1 data.skipBits(16 + 16); // syncword, crc1
int fscod = data.readBits(2); int fscod = data.readBits(2);
data.skipBits(6 + 5 + 3); // frmsizecod, bsid, bsmod data.skipBits(6 + 5 + 3); // frmsizecod, bsid, bsmod
...@@ -134,7 +138,7 @@ public final class Ac3Util { ...@@ -134,7 +138,7 @@ public final class Ac3Util {
boolean lfeon = data.readBit(); boolean lfeon = data.readBit();
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE, return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_AC3, Format.NO_VALUE,
Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0), Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0),
SAMPLE_RATE_BY_FSCOD[fscod], null, language); SAMPLE_RATE_BY_FSCOD[fscod], null, language, drmInitData);
} }
/** /**
...@@ -144,10 +148,11 @@ public final class Ac3Util { ...@@ -144,10 +148,11 @@ public final class Ac3Util {
* @param data The data to parse, positioned at the start of the syncframe. * @param data The data to parse, positioned at the start of the syncframe.
* @param trackId The track identifier to set on the format, or null. * @param trackId The track identifier to set on the format, or null.
* @param language The language to set on the format. * @param language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The E-AC-3 format parsed from data in the header. * @return The E-AC-3 format parsed from data in the header.
*/ */
public static Format parseEac3SyncframeFormat(ParsableBitArray data, String trackId, public static Format parseEac3SyncframeFormat(ParsableBitArray data, String trackId,
String language) { String language, DrmInitData drmInitData) {
data.skipBits(16 + 2 + 3 + 11); // syncword, strmtype, substreamid, frmsiz data.skipBits(16 + 2 + 3 + 11); // syncword, strmtype, substreamid, frmsiz
int sampleRate; int sampleRate;
int fscod = data.readBits(2); int fscod = data.readBits(2);
...@@ -161,7 +166,7 @@ public final class Ac3Util { ...@@ -161,7 +166,7 @@ public final class Ac3Util {
boolean lfeon = data.readBit(); boolean lfeon = data.readBit();
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE, return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_E_AC3, Format.NO_VALUE,
Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0), sampleRate, null, Format.NO_VALUE, CHANNEL_COUNT_BY_ACMOD[acmod] + (lfeon ? 1 : 0), sampleRate, null,
language); language, drmInitData);
} }
/** /**
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer.util; package com.google.android.exoplayer.util;
import com.google.android.exoplayer.Format; import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.drm.DrmInitData;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
...@@ -54,9 +55,11 @@ public final class DtsUtil { ...@@ -54,9 +55,11 @@ public final class DtsUtil {
* @param frame The DTS frame to parse. * @param frame The DTS frame to parse.
* @param trackId The track identifier to set on the format, or null. * @param trackId The track identifier to set on the format, or null.
* @param language The language to set on the format. * @param language The language to set on the format.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @return The DTS format parsed from data in the header. * @return The DTS format parsed from data in the header.
*/ */
public static Format parseDtsFormat(byte[] frame, String trackId, String language) { public static Format parseDtsFormat(byte[] frame, String trackId, String language,
DrmInitData drmInitData) {
ParsableBitArray frameBits = SCRATCH_BITS; ParsableBitArray frameBits = SCRATCH_BITS;
frameBits.reset(frame); frameBits.reset(frame);
frameBits.skipBits(4 * 8 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE frameBits.skipBits(4 * 8 + 1 + 5 + 1 + 7 + 14); // SYNC, FTYPE, SHORT, CPF, NBLKS, FSIZE
...@@ -70,7 +73,7 @@ public final class DtsUtil { ...@@ -70,7 +73,7 @@ public final class DtsUtil {
frameBits.skipBits(10); // MIX, DYNF, TIMEF, AUXF, HDCD, EXT_AUDIO_ID, EXT_AUDIO, ASPF frameBits.skipBits(10); // MIX, DYNF, TIMEF, AUXF, HDCD, EXT_AUDIO_ID, EXT_AUDIO, ASPF
channelCount += frameBits.readBits(2) > 0 ? 1 : 0; // LFF channelCount += frameBits.readBits(2) > 0 ? 1 : 0; // LFF
return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_DTS, bitrate, Format.NO_VALUE, return Format.createAudioSampleFormat(trackId, MimeTypes.AUDIO_DTS, bitrate, Format.NO_VALUE,
channelCount, sampleRate, null, language); channelCount, sampleRate, null, language, drmInitData);
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment