mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Better compatibility with MKV test streams.
1. Fix seeking in test2.mkv by handling non-default timescale after duration. 2. Fix handling of missing cues in test6.mkv by allowing playback to continue (but all seeks will reset to t=0). Issue #631
This commit is contained in:
parent
7bc1241e06
commit
eb4920bb2a
6 changed files with 277 additions and 192 deletions
|
|
@ -20,6 +20,23 @@ package com.google.android.exoplayer.extractor;
|
||||||
*/
|
*/
|
||||||
public interface SeekMap {
|
public interface SeekMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SeekMap} that does not support seeking.
|
||||||
|
*/
|
||||||
|
public static final SeekMap UNSEEKABLE = new SeekMap() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSeekable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getPosition(long timeUs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the seeking is supported.
|
* Whether or not the seeking is supported.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import java.io.IOException;
|
||||||
* Facilitates the extraction of AAC samples from elementary audio files formatted as AAC with ADTS
|
* Facilitates the extraction of AAC samples from elementary audio files formatted as AAC with ADTS
|
||||||
* headers.
|
* headers.
|
||||||
*/
|
*/
|
||||||
public class AdtsExtractor implements Extractor, SeekMap {
|
public class AdtsExtractor implements Extractor {
|
||||||
|
|
||||||
private static final int MAX_PACKET_SIZE = 200;
|
private static final int MAX_PACKET_SIZE = 200;
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ public class AdtsExtractor implements Extractor, SeekMap {
|
||||||
public void init(ExtractorOutput output) {
|
public void init(ExtractorOutput output) {
|
||||||
adtsReader = new AdtsReader(output.track(0));
|
adtsReader = new AdtsReader(output.track(0));
|
||||||
output.endTracks();
|
output.endTracks();
|
||||||
output.seekMap(this);
|
output.seekMap(SeekMap.UNSEEKABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -81,16 +81,4 @@ public class AdtsExtractor implements Extractor, SeekMap {
|
||||||
return RESULT_CONTINUE;
|
return RESULT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeekMap implementation.
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getPosition(long timeUs) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import java.io.IOException;
|
||||||
/**
|
/**
|
||||||
* Facilitates the extraction of data from the MPEG-2 TS container format.
|
* Facilitates the extraction of data from the MPEG-2 TS container format.
|
||||||
*/
|
*/
|
||||||
public final class TsExtractor implements Extractor, SeekMap {
|
public final class TsExtractor implements Extractor {
|
||||||
|
|
||||||
private static final String TAG = "TsExtractor";
|
private static final String TAG = "TsExtractor";
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ public final class TsExtractor implements Extractor, SeekMap {
|
||||||
@Override
|
@Override
|
||||||
public void init(ExtractorOutput output) {
|
public void init(ExtractorOutput output) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
output.seekMap(this);
|
output.seekMap(SeekMap.UNSEEKABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -153,18 +153,6 @@ public final class TsExtractor implements Extractor, SeekMap {
|
||||||
return RESULT_CONTINUE;
|
return RESULT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeekMap implementation.
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getPosition(long timeUs) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internals.
|
// Internals.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,14 @@ import com.google.android.exoplayer.extractor.Extractor;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorInput;
|
import com.google.android.exoplayer.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorOutput;
|
import com.google.android.exoplayer.extractor.ExtractorOutput;
|
||||||
import com.google.android.exoplayer.extractor.PositionHolder;
|
import com.google.android.exoplayer.extractor.PositionHolder;
|
||||||
|
import com.google.android.exoplayer.extractor.SeekMap;
|
||||||
import com.google.android.exoplayer.extractor.TrackOutput;
|
import com.google.android.exoplayer.extractor.TrackOutput;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
import com.google.android.exoplayer.util.LongArray;
|
import com.google.android.exoplayer.util.LongArray;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.util.NalUnitUtil;
|
import com.google.android.exoplayer.util.NalUnitUtil;
|
||||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
|
@ -39,7 +41,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An extractor to facilitate data retrieval from the WebM container format.
|
* An extractor to facilitate data retrieval from the WebM container format.
|
||||||
|
|
@ -83,6 +84,7 @@ public final class WebmExtractor implements Extractor {
|
||||||
private static final int ID_DOC_TYPE = 0x4282;
|
private static final int ID_DOC_TYPE = 0x4282;
|
||||||
private static final int ID_DOC_TYPE_READ_VERSION = 0x4285;
|
private static final int ID_DOC_TYPE_READ_VERSION = 0x4285;
|
||||||
private static final int ID_SEGMENT = 0x18538067;
|
private static final int ID_SEGMENT = 0x18538067;
|
||||||
|
private static final int ID_SEGMENT_INFO = 0x1549A966;
|
||||||
private static final int ID_SEEK_HEAD = 0x114D9B74;
|
private static final int ID_SEEK_HEAD = 0x114D9B74;
|
||||||
private static final int ID_SEEK = 0x4DBB;
|
private static final int ID_SEEK = 0x4DBB;
|
||||||
private static final int ID_SEEK_ID = 0x53AB;
|
private static final int ID_SEEK_ID = 0x53AB;
|
||||||
|
|
@ -147,7 +149,8 @@ public final class WebmExtractor implements Extractor {
|
||||||
|
|
||||||
private long segmentContentPosition = UNKNOWN;
|
private long segmentContentPosition = UNKNOWN;
|
||||||
private long segmentContentSize = UNKNOWN;
|
private long segmentContentSize = UNKNOWN;
|
||||||
private long timecodeScale = 1000000L;
|
private long timecodeScale = C.UNKNOWN_TIME_US;
|
||||||
|
private long durationTimecode = C.UNKNOWN_TIME_US;
|
||||||
private long durationUs = C.UNKNOWN_TIME_US;
|
private long durationUs = C.UNKNOWN_TIME_US;
|
||||||
|
|
||||||
private TrackFormat trackFormat; // Used to store the last seen track.
|
private TrackFormat trackFormat; // Used to store the last seen track.
|
||||||
|
|
@ -320,10 +323,17 @@ public final class WebmExtractor implements Extractor {
|
||||||
seenClusterPositionForCurrentCuePoint = false;
|
seenClusterPositionForCurrentCuePoint = false;
|
||||||
return;
|
return;
|
||||||
case ID_CLUSTER:
|
case ID_CLUSTER:
|
||||||
// If we encounter a Cluster before building Cues, then we should try to build cues first
|
if (cuesState == CUES_STATE_NOT_BUILT) {
|
||||||
// before parsing the Cluster.
|
// We need to build cues before parsing the cluster.
|
||||||
if (cuesState == CUES_STATE_NOT_BUILT && cuesContentPosition != UNKNOWN) {
|
if (cuesContentPosition != UNKNOWN) {
|
||||||
seekForCues = true;
|
// We know where the Cues element is located. Seek to request it.
|
||||||
|
seekForCues = true;
|
||||||
|
} else {
|
||||||
|
// We don't know where the Cues element is located. It's most likely omitted. Allow
|
||||||
|
// playback, but disable seeking.
|
||||||
|
extractorOutput.seekMap(SeekMap.UNSEEKABLE);
|
||||||
|
cuesState = CUES_STATE_BUILT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case ID_BLOCK_GROUP:
|
case ID_BLOCK_GROUP:
|
||||||
|
|
@ -345,6 +355,15 @@ public final class WebmExtractor implements Extractor {
|
||||||
|
|
||||||
/* package */ void endMasterElement(int id) throws ParserException {
|
/* package */ void endMasterElement(int id) throws ParserException {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case ID_SEGMENT_INFO:
|
||||||
|
if (timecodeScale == C.UNKNOWN_TIME_US) {
|
||||||
|
// timecodeScale was omitted. Use the default value.
|
||||||
|
timecodeScale = 1000000;
|
||||||
|
}
|
||||||
|
if (durationTimecode != C.UNKNOWN_TIME_US) {
|
||||||
|
durationUs = scaleTimecodeToUs(durationTimecode);
|
||||||
|
}
|
||||||
|
return;
|
||||||
case ID_SEEK:
|
case ID_SEEK:
|
||||||
if (seekEntryId == UNKNOWN || seekEntryPosition == UNKNOWN) {
|
if (seekEntryId == UNKNOWN || seekEntryPosition == UNKNOWN) {
|
||||||
throw new ParserException("Mandatory element SeekID or SeekPosition not found");
|
throw new ParserException("Mandatory element SeekID or SeekPosition not found");
|
||||||
|
|
@ -355,7 +374,7 @@ public final class WebmExtractor implements Extractor {
|
||||||
return;
|
return;
|
||||||
case ID_CUES:
|
case ID_CUES:
|
||||||
if (cuesState != CUES_STATE_BUILT) {
|
if (cuesState != CUES_STATE_BUILT) {
|
||||||
extractorOutput.seekMap(buildCues());
|
extractorOutput.seekMap(buildSeekMap());
|
||||||
cuesState = CUES_STATE_BUILT;
|
cuesState = CUES_STATE_BUILT;
|
||||||
} else {
|
} else {
|
||||||
// We have already built the cues. Ignore.
|
// We have already built the cues. Ignore.
|
||||||
|
|
@ -528,7 +547,7 @@ public final class WebmExtractor implements Extractor {
|
||||||
/* package */ void floatElement(int id, double value) {
|
/* package */ void floatElement(int id, double value) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case ID_DURATION:
|
case ID_DURATION:
|
||||||
durationUs = scaleTimecodeToUs((long) value);
|
durationTimecode = (long) value;
|
||||||
return;
|
return;
|
||||||
case ID_SAMPLING_FREQUENCY:
|
case ID_SAMPLING_FREQUENCY:
|
||||||
trackFormat.sampleRate = (int) value;
|
trackFormat.sampleRate = (int) value;
|
||||||
|
|
@ -865,19 +884,19 @@ public final class WebmExtractor implements Extractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a {@link ChunkIndex} containing recently gathered Cues information.
|
* Builds a {@link SeekMap} from the recently gathered Cues information.
|
||||||
*
|
*
|
||||||
* @return The built {@link ChunkIndex}.
|
* @return The built {@link SeekMap}. May be {@link SeekMap#UNSEEKABLE} if cues information was
|
||||||
* @throws ParserException If the index could not be built.
|
* missing or incomplete.
|
||||||
*/
|
*/
|
||||||
private ChunkIndex buildCues() throws ParserException {
|
private SeekMap buildSeekMap() {
|
||||||
if (segmentContentPosition == UNKNOWN) {
|
if (segmentContentPosition == UNKNOWN || durationUs == C.UNKNOWN_TIME_US
|
||||||
throw new ParserException("Segment start/end offsets unknown");
|
|| cueTimesUs == null || cueTimesUs.size() == 0
|
||||||
} else if (durationUs == C.UNKNOWN_TIME_US) {
|
|| cueClusterPositions == null || cueClusterPositions.size() != cueTimesUs.size()) {
|
||||||
throw new ParserException("Duration unknown");
|
// Cues information is missing or incomplete.
|
||||||
} else if (cueTimesUs == null || cueClusterPositions == null
|
cueTimesUs = null;
|
||||||
|| cueTimesUs.size() == 0 || cueTimesUs.size() != cueClusterPositions.size()) {
|
cueClusterPositions = null;
|
||||||
throw new ParserException("Invalid/missing cue points");
|
return SeekMap.UNSEEKABLE;
|
||||||
}
|
}
|
||||||
int cuePointsSize = cueTimesUs.size();
|
int cuePointsSize = cueTimesUs.size();
|
||||||
int[] sizes = new int[cuePointsSize];
|
int[] sizes = new int[cuePointsSize];
|
||||||
|
|
@ -927,8 +946,11 @@ public final class WebmExtractor implements Extractor {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long scaleTimecodeToUs(long unscaledTimecode) {
|
private long scaleTimecodeToUs(long unscaledTimecode) throws ParserException {
|
||||||
return TimeUnit.NANOSECONDS.toMicros(unscaledTimecode * timecodeScale);
|
if (timecodeScale == C.UNKNOWN_TIME_US) {
|
||||||
|
throw new ParserException("Can't scale timecode prior to timecodeScale being set.");
|
||||||
|
}
|
||||||
|
return Util.scaleLargeTimestamp(unscaledTimecode, timecodeScale, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isCodecSupported(String codecId) {
|
private static boolean isCodecSupported(String codecId) {
|
||||||
|
|
@ -984,7 +1006,7 @@ public final class WebmExtractor implements Extractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void floatElement(int id, double value) {
|
public void floatElement(int id, double value) throws ParserException {
|
||||||
WebmExtractor.this.floatElement(id, value);
|
WebmExtractor.this.floatElement(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,14 @@ import java.util.List;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamBuilder setInfo(int timecodeScale, long durationUs) {
|
public StreamBuilder setInfo(int timecodeScale, long durationTimecode) {
|
||||||
info = createInfoElement(timecodeScale, durationUs);
|
return setInfo(timecodeScale, durationTimecode, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamBuilder setInfo(int timecodeScale, long durationTimecode,
|
||||||
|
boolean omitTimecodeScaleIfDefault, boolean durationFirst) {
|
||||||
|
info = createInfoElement(timecodeScale, durationTimecode, omitTimecodeScaleIfDefault,
|
||||||
|
durationFirst);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,28 +183,38 @@ import java.util.List;
|
||||||
Assertions.checkNotNull(info);
|
Assertions.checkNotNull(info);
|
||||||
|
|
||||||
EbmlElement tracks = element(0x1654AE6B, trackEntries.toArray(new EbmlElement[0]));
|
EbmlElement tracks = element(0x1654AE6B, trackEntries.toArray(new EbmlElement[0]));
|
||||||
|
EbmlElement[] children;
|
||||||
|
|
||||||
// Get the size of the initialization segment.
|
if (cuePointCount == 0) {
|
||||||
EbmlElement[] cuePointElements = new EbmlElement[cuePointCount];
|
children = new EbmlElement[2 + mediaSegments.size()];
|
||||||
for (int i = 0; i < cuePointCount; i++) {
|
System.arraycopy(mediaSegments.toArray(new EbmlElement[0]), 0, children, 2,
|
||||||
cuePointElements[i] = createCuePointElement(10 * i, 0);
|
mediaSegments.size());
|
||||||
|
children[0] = info;
|
||||||
|
children[1] = tracks;
|
||||||
|
} else {
|
||||||
|
// Get the size of the initialization segment.
|
||||||
|
EbmlElement[] cuePointElements = new EbmlElement[cuePointCount];
|
||||||
|
for (int i = 0; i < cuePointCount; i++) {
|
||||||
|
cuePointElements[i] = createCuePointElement(10 * i, 0);
|
||||||
|
}
|
||||||
|
EbmlElement cues = element(0x1C53BB6B, cuePointElements); // Cues
|
||||||
|
long initializationSegmentSize = info.getSize() + tracks.getSize() + cues.getSize();
|
||||||
|
|
||||||
|
// Recreate the initialization segment using its size as an offset.
|
||||||
|
for (int i = 0; i < cuePointCount; i++) {
|
||||||
|
cuePointElements[i] = createCuePointElement(10 * i, (int) initializationSegmentSize);
|
||||||
|
}
|
||||||
|
cues = element(0x1C53BB6B, cuePointElements); // Cues
|
||||||
|
|
||||||
|
// Build the top-level segment element.
|
||||||
|
children = new EbmlElement[3 + mediaSegments.size()];
|
||||||
|
System.arraycopy(mediaSegments.toArray(new EbmlElement[0]), 0, children, 3,
|
||||||
|
mediaSegments.size());
|
||||||
|
children[0] = info;
|
||||||
|
children[1] = tracks;
|
||||||
|
children[2] = cues;
|
||||||
}
|
}
|
||||||
EbmlElement cues = element(0x1C53BB6B, cuePointElements); // Cues
|
|
||||||
long initializationSegmentSize = info.getSize() + tracks.getSize() + cues.getSize();
|
|
||||||
|
|
||||||
// Recreate the initialization segment using its size as an offset.
|
|
||||||
for (int i = 0; i < cuePointCount; i++) {
|
|
||||||
cuePointElements[i] = createCuePointElement(10 * i, (int) initializationSegmentSize);
|
|
||||||
}
|
|
||||||
cues = element(0x1C53BB6B, cuePointElements); // Cues
|
|
||||||
|
|
||||||
// Build the top-level segment element.
|
|
||||||
EbmlElement[] children = new EbmlElement[3 + mediaSegments.size()];
|
|
||||||
System.arraycopy(mediaSegments.toArray(new EbmlElement[0]), 0, children, 3,
|
|
||||||
mediaSegments.size());
|
|
||||||
children[0] = info;
|
|
||||||
children[1] = tracks;
|
|
||||||
children[2] = cues;
|
|
||||||
EbmlElement segmentElement = element(0x18538067, children); // Segment
|
EbmlElement segmentElement = element(0x18538067, children); // Segment
|
||||||
|
|
||||||
// Serialize the EBML header and the top-level segment element.
|
// Serialize the EBML header and the top-level segment element.
|
||||||
|
|
@ -221,12 +237,19 @@ import java.util.List;
|
||||||
element(0x4285, (byte) (docTypeReadVersion & 0xFF))); // DocTypeReadVersion
|
element(0x4285, (byte) (docTypeReadVersion & 0xFF))); // DocTypeReadVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
private EbmlElement createInfoElement(int timecodeScale, long durationUs) {
|
private EbmlElement createInfoElement(int timecodeScale, long durationTimecode,
|
||||||
|
boolean durationFirst, boolean omitDefaultTimecodeScale) {
|
||||||
byte[] timecodeScaleBytes = getIntegerBytes(timecodeScale);
|
byte[] timecodeScaleBytes = getIntegerBytes(timecodeScale);
|
||||||
byte[] durationBytes = getLongBytes(Double.doubleToLongBits(durationUs / 1000.0));
|
byte[] durationBytes = getLongBytes(Double.doubleToLongBits(durationTimecode));
|
||||||
|
EbmlElement durationElement = element(0x4489, durationBytes);
|
||||||
|
EbmlElement timescaleElement = element(0x2AD7B1, timecodeScaleBytes);
|
||||||
|
if (omitDefaultTimecodeScale && timecodeScale == 1000000) {
|
||||||
|
return element(0x1549A966, // Info
|
||||||
|
durationElement);
|
||||||
|
}
|
||||||
return element(0x1549A966, // Info
|
return element(0x1549A966, // Info
|
||||||
element(0x2AD7B1, timecodeScaleBytes), // TimecodeScale
|
durationFirst ? durationElement : timescaleElement,
|
||||||
element(0x4489, durationBytes)); // Duration
|
durationFirst ? timescaleElement : durationElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static EbmlElement createVideoTrackEntry(String codecId, int pixelWidth, int pixelHeight,
|
private static EbmlElement createVideoTrackEntry(String codecId, int pixelWidth, int pixelHeight,
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,13 @@ import com.google.android.exoplayer.MediaFormat;
|
||||||
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;
|
||||||
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.webm.StreamBuilder.ContentEncodingSettings;
|
import com.google.android.exoplayer.extractor.webm.StreamBuilder.ContentEncodingSettings;
|
||||||
import com.google.android.exoplayer.testutil.FakeExtractorOutput;
|
import com.google.android.exoplayer.testutil.FakeExtractorOutput;
|
||||||
import com.google.android.exoplayer.testutil.FakeTrackOutput;
|
import com.google.android.exoplayer.testutil.FakeTrackOutput;
|
||||||
import com.google.android.exoplayer.testutil.TestUtil;
|
import com.google.android.exoplayer.testutil.TestUtil;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import android.test.InstrumentationTestCase;
|
import android.test.InstrumentationTestCase;
|
||||||
|
|
||||||
|
|
@ -41,7 +43,7 @@ import java.util.UUID;
|
||||||
public final class WebmExtractorTest extends InstrumentationTestCase {
|
public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
private static final int DEFAULT_TIMECODE_SCALE = 1000000;
|
private static final int DEFAULT_TIMECODE_SCALE = 1000000;
|
||||||
private static final long TEST_DURATION_US = 9920000L;
|
private static final long TEST_DURATION_TIMECODE = 9920L;
|
||||||
private static final int TEST_WIDTH = 1280;
|
private static final int TEST_WIDTH = 1280;
|
||||||
private static final int TEST_HEIGHT = 720;
|
private static final int TEST_HEIGHT = 720;
|
||||||
private static final int TEST_CHANNEL_COUNT = 1;
|
private static final int TEST_CHANNEL_COUNT = 1;
|
||||||
|
|
@ -82,20 +84,21 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testReadInitializationSegment() throws IOException, InterruptedException {
|
public void testReadInitializationSegment() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSegmentTwice() throws IOException, InterruptedException {
|
public void testReadSegmentTwice() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
|
|
@ -103,54 +106,58 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
extractor.seek();
|
extractor.seek();
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareOpus() throws IOException, InterruptedException {
|
public void testPrepareOpus() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
||||||
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertTracksEnded();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareVorbis() throws IOException, InterruptedException {
|
public void testPrepareVorbis() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVorbisTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, getVorbisCodecPrivate())
|
.addVorbisTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, getVorbisCodecPrivate())
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertAudioFormat(MimeTypes.AUDIO_VORBIS);
|
assertTracksEnded();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_VORBIS);
|
||||||
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareH264() throws IOException, InterruptedException {
|
public void testPrepareH264() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(MATROSKA_DOC_TYPE)
|
.setHeader(MATROSKA_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addH264Track(TEST_WIDTH, TEST_HEIGHT, TEST_H264_CODEC_PRIVATE)
|
.addH264Track(TEST_WIDTH, TEST_HEIGHT, TEST_H264_CODEC_PRIVATE)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertH264VideoFormat();
|
assertTracksEnded();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertH264VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareTwoTracks() throws IOException, InterruptedException {
|
public void testPrepareTwoTracks() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
||||||
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
||||||
|
|
@ -158,16 +165,17 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
assertEquals(2, extractorOutput.numberOfTracks);
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
assertVp9VideoFormat();
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareThreeTracks() throws IOException, InterruptedException {
|
public void testPrepareThreeTracks() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addUnsupportedTrack()
|
.addUnsupportedTrack()
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
||||||
|
|
@ -176,17 +184,18 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
// Even though the input stream has 3 tracks, only 2 of them are supported and will be reported.
|
// Even though the input stream has 3 tracks, only 2 of them are supported and will be reported.
|
||||||
assertEquals(2, extractorOutput.numberOfTracks);
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
assertVp9VideoFormat();
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareFourTracks() throws IOException, InterruptedException {
|
public void testPrepareFourTracks() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addVorbisTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, getVorbisCodecPrivate())
|
.addVorbisTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, getVorbisCodecPrivate())
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
|
|
@ -196,26 +205,28 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
// Even though the input stream has 4 supported tracks, only the first video and audio track
|
// Even though the input stream has 4 supported tracks, only the first video and audio track
|
||||||
// will be reported.
|
// will be reported.
|
||||||
assertEquals(2, extractorOutput.numberOfTracks);
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
assertVp9VideoFormat();
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertAudioFormat(MimeTypes.AUDIO_VORBIS);
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_VORBIS);
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareContentEncodingEncryption() throws IOException, InterruptedException {
|
public void testPrepareContentEncodingEncryption() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new StreamBuilder.ContentEncodingSettings(0, 1, 5, 1);
|
ContentEncodingSettings settings = new StreamBuilder.ContentEncodingSettings(0, 1, 5, 1);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
|
assertIndex(DEFAULT_TIMECODE_SCALE, 1);
|
||||||
DrmInitData drmInitData = extractorOutput.drmInitData;
|
DrmInitData drmInitData = extractorOutput.drmInitData;
|
||||||
assertNotNull(drmInitData);
|
assertNotNull(drmInitData);
|
||||||
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, drmInitData.get(WIDEVINE_UUID));
|
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, drmInitData.get(WIDEVINE_UUID));
|
||||||
|
|
@ -225,75 +236,91 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testPrepareThreeCuePoints() throws IOException, InterruptedException {
|
public void testPrepareThreeCuePoints() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(3);
|
.build(3);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
assertIndex(
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
new IndexPoint(0, 0, 10000),
|
assertIndex(DEFAULT_TIMECODE_SCALE, 3);
|
||||||
new IndexPoint(10000, 0, 10000),
|
|
||||||
new IndexPoint(20000, 0, TEST_DURATION_US - 20000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareCustomTimecodeScale() throws IOException, InterruptedException {
|
public void testPrepareCustomTimecodeScaleBeforeDuration()
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
testPrepareTimecodeScale(1000, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrepareCustomTimecodeScaleAfterDuration()
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
testPrepareTimecodeScale(1000, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrepareImplicitDefaultTimecode()
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
testPrepareTimecodeScale(1000, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testPrepareTimecodeScale(int timecodeScale, boolean omitTimecodeScaleIfDefault,
|
||||||
|
boolean afterDuration) throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(1000, TEST_DURATION_US)
|
.setInfo(timecodeScale, TEST_DURATION_TIMECODE, omitTimecodeScaleIfDefault, afterDuration)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(3);
|
.build(3);
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
assertIndex(
|
assertVp9VideoFormat(timecodeScale);
|
||||||
new IndexPoint(0, 0, 10),
|
assertIndex(timecodeScale, 3);
|
||||||
new IndexPoint(10, 0, 10),
|
|
||||||
new IndexPoint(20, 0, (TEST_DURATION_US / 1000) - 20));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareNoCuePoints() throws IOException, InterruptedException {
|
public void testPrepareNoCuesElement() throws IOException, InterruptedException {
|
||||||
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
|
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
||||||
|
true /* keyframe */, false /* invisible */, media)
|
||||||
.build(0);
|
.build(0);
|
||||||
try {
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
fail();
|
|
||||||
} catch (ParserException exception) {
|
assertTracksEnded();
|
||||||
assertEquals("Invalid/missing cue points", exception.getMessage());
|
assertIndexUnseekable();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAcceptsWebmDocType() throws IOException, InterruptedException {
|
public void testAcceptsWebmDocType() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
// No exception is thrown.
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAcceptsMatroskaDocType() throws IOException, InterruptedException {
|
public void testAcceptsMatroskaDocType() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(MATROSKA_DOC_TYPE)
|
.setHeader(MATROSKA_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(1);
|
.build(1);
|
||||||
|
|
||||||
// No exception is thrown.
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareInvalidDocType() throws IOException, InterruptedException {
|
public void testPrepareInvalidDocType() throws IOException, InterruptedException {
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader("webB")
|
.setHeader("webB")
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.build(1);
|
.build(1);
|
||||||
try {
|
try {
|
||||||
|
|
@ -308,7 +335,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(1, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(1, 1, 5, 1);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.build(1);
|
.build(1);
|
||||||
try {
|
try {
|
||||||
|
|
@ -323,7 +350,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 0, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 0, 5, 1);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.build(1);
|
.build(1);
|
||||||
try {
|
try {
|
||||||
|
|
@ -339,7 +366,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 0, new byte[0]);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 0, new byte[0]);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.build(1);
|
.build(1);
|
||||||
try {
|
try {
|
||||||
|
|
@ -354,7 +381,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 4, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 4, 1);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.build(1);
|
.build(1);
|
||||||
try {
|
try {
|
||||||
|
|
@ -369,7 +396,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 0);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 0);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.build(1);
|
.build(1);
|
||||||
try {
|
try {
|
||||||
|
|
@ -384,7 +411,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
||||||
true /* keyframe */, false /* invisible */, media)
|
true /* keyframe */, false /* invisible */, media)
|
||||||
|
|
@ -392,7 +419,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, media, 0, true, false, null, getVideoOutput());
|
assertSample(0, media, 0, true, false, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -403,7 +431,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] unstrippedSampleBytes = TestUtil.joinByteArrays(strippedBytes, sampleBytes);
|
byte[] unstrippedSampleBytes = TestUtil.joinByteArrays(strippedBytes, sampleBytes);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
||||||
true /* keyframe */, false /* invisible */, sampleBytes)
|
true /* keyframe */, false /* invisible */, sampleBytes)
|
||||||
|
|
@ -411,7 +439,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, unstrippedSampleBytes, 0, true, false, null, getVideoOutput());
|
assertSample(0, unstrippedSampleBytes, 0, true, false, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,7 +451,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] unstrippedSampleBytes = TestUtil.joinByteArrays(strippedBytes, sampleBytes);
|
byte[] unstrippedSampleBytes = TestUtil.joinByteArrays(strippedBytes, sampleBytes);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
.addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
||||||
true /* keyframe */, false /* invisible */, sampleBytes)
|
true /* keyframe */, false /* invisible */, sampleBytes)
|
||||||
|
|
@ -430,7 +459,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, unstrippedSampleBytes, 0, true, false, null, getVideoOutput());
|
assertSample(0, unstrippedSampleBytes, 0, true, false, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,7 +468,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
||||||
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
||||||
|
|
@ -450,9 +480,10 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
assertEquals(2, extractorOutput.numberOfTracks);
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
assertVp9VideoFormat();
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
assertSample(0, media, 0, true, false, null, getVideoOutput());
|
assertSample(0, media, 0, true, false, null, getVideoOutput());
|
||||||
assertSample(0, media, 0, true, false, null, getAudioOutput());
|
assertSample(0, media, 0, true, false, null, getAudioOutput());
|
||||||
}
|
}
|
||||||
|
|
@ -461,7 +492,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addUnsupportedTrack()
|
.addUnsupportedTrack()
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
||||||
|
|
@ -476,9 +507,10 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
|
assertTracksEnded();
|
||||||
assertEquals(2, extractorOutput.numberOfTracks);
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
assertVp9VideoFormat();
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
assertSample(0, media, 0, true, false, null, getVideoOutput());
|
assertSample(0, media, 0, true, false, null, getVideoOutput());
|
||||||
assertSample(0, media, 0, true, false, null, getAudioOutput());
|
assertSample(0, media, 0, true, false, null, getAudioOutput());
|
||||||
}
|
}
|
||||||
|
|
@ -487,7 +519,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY,
|
||||||
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE)
|
||||||
.addBlockMedia(2 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
.addBlockMedia(2 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
||||||
|
|
@ -496,7 +528,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertTracksEnded();
|
||||||
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
assertSample(0, media, 0, true, false, null, getAudioOutput());
|
assertSample(0, media, 0, true, false, null, getAudioOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,7 +537,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
.addBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */,
|
||||||
false /* keyframe */, false /* invisible */, media)
|
false /* keyframe */, false /* invisible */, media)
|
||||||
|
|
@ -512,7 +545,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, media, 0, false, false, null, getVideoOutput());
|
assertSample(0, media, 0, false, false, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -521,7 +555,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 1);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */,
|
.addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */,
|
||||||
0 /* blockTimecode */, true /* keyframe */, false /* invisible */,
|
0 /* blockTimecode */, true /* keyframe */, false /* invisible */,
|
||||||
|
|
@ -530,7 +564,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, media, 0, true, false, TEST_ENCRYPTION_KEY_ID, getVideoOutput());
|
assertSample(0, media, 0, true, false, TEST_ENCRYPTION_KEY_ID, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -540,7 +575,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 1);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings)
|
||||||
.addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */,
|
.addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */,
|
||||||
0 /* blockTimecode */, true /* keyframe */, false /* invisible */,
|
0 /* blockTimecode */, true /* keyframe */, false /* invisible */,
|
||||||
|
|
@ -551,6 +586,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
|
assertTracksEnded();
|
||||||
assertEquals("Extension bit is set in signal byte", exception.getMessage());
|
assertEquals("Extension bit is set in signal byte", exception.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -559,7 +595,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */,
|
.addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */,
|
||||||
false /* keyframe */, true /* invisible */, media)
|
false /* keyframe */, true /* invisible */, media)
|
||||||
|
|
@ -567,15 +603,17 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, media, 25000, false, true, null, getVideoOutput());
|
assertSample(0, media, 25000, false, true, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSampleCustomTimescale() throws IOException, InterruptedException {
|
public void testReadSampleCustomTimecodeScale() throws IOException, InterruptedException {
|
||||||
|
int timecodeScale = 1000;
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(1000, TEST_DURATION_US)
|
.setInfo(timecodeScale, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */,
|
.addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */,
|
||||||
false /* keyframe */, false /* invisible */, media)
|
false /* keyframe */, false /* invisible */, media)
|
||||||
|
|
@ -583,7 +621,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(timecodeScale);
|
||||||
assertSample(0, media, 25, false, false, null, getVideoOutput());
|
assertSample(0, media, 25, false, false, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,7 +630,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
.addVp9Track(TEST_WIDTH, TEST_HEIGHT, null)
|
||||||
.addSimpleBlockMedia(1 /* trackNumber */, 13 /* clusterTimecode */, -12 /* blockTimecode */,
|
.addSimpleBlockMedia(1 /* trackNumber */, 13 /* clusterTimecode */, -12 /* blockTimecode */,
|
||||||
true /* keyframe */, true /* invisible */, media)
|
true /* keyframe */, true /* invisible */, media)
|
||||||
|
|
@ -599,7 +638,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertVp9VideoFormat();
|
assertTracksEnded();
|
||||||
|
assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE);
|
||||||
assertSample(0, media, 1000, true, true, null, getVideoOutput());
|
assertSample(0, media, 1000, true, true, null, getVideoOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -607,7 +647,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(100);
|
byte[] media = createFrameData(100);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL,
|
||||||
TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS)
|
TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS)
|
||||||
.addSimpleBlockMediaWithFixedSizeLacing(2 /* trackNumber */, 0 /* clusterTimecode */,
|
.addSimpleBlockMediaWithFixedSizeLacing(2 /* trackNumber */, 0 /* clusterTimecode */,
|
||||||
|
|
@ -616,7 +656,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertTracksEnded();
|
||||||
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
long expectedTimeUs = i * TEST_DEFAULT_DURATION_NS / 1000;
|
long expectedTimeUs = i * TEST_DEFAULT_DURATION_NS / 1000;
|
||||||
assertSample(i, Arrays.copyOfRange(media, i * 5, i * 5 + 5), expectedTimeUs, true, false,
|
assertSample(i, Arrays.copyOfRange(media, i * 5, i * 5 + 5), expectedTimeUs, true, false,
|
||||||
|
|
@ -628,7 +669,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] media = createFrameData(300);
|
byte[] media = createFrameData(300);
|
||||||
byte[] data = new StreamBuilder()
|
byte[] data = new StreamBuilder()
|
||||||
.setHeader(WEBM_DOC_TYPE)
|
.setHeader(WEBM_DOC_TYPE)
|
||||||
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_US)
|
.setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE)
|
||||||
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL,
|
.addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL,
|
||||||
TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS)
|
TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS)
|
||||||
.addSimpleBlockMediaWithXiphLacing(2 /* trackNumber */, 0 /* clusterTimecode */,
|
.addSimpleBlockMediaWithXiphLacing(2 /* trackNumber */, 0 /* clusterTimecode */,
|
||||||
|
|
@ -637,7 +678,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
TestUtil.consumeTestData(extractor, data);
|
TestUtil.consumeTestData(extractor, data);
|
||||||
|
|
||||||
assertAudioFormat(MimeTypes.AUDIO_OPUS);
|
assertTracksEnded();
|
||||||
|
assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS);
|
||||||
assertSample(0, Arrays.copyOfRange(media, 0, 256), 0 * TEST_DEFAULT_DURATION_NS / 1000, true,
|
assertSample(0, Arrays.copyOfRange(media, 0, 256), 0 * TEST_DEFAULT_DURATION_NS / 1000, true,
|
||||||
false, null, getAudioOutput());
|
false, null, getAudioOutput());
|
||||||
assertSample(1, Arrays.copyOfRange(media, 256, 257), 1 * TEST_DEFAULT_DURATION_NS / 1000, true,
|
assertSample(1, Arrays.copyOfRange(media, 256, 257), 1 * TEST_DEFAULT_DURATION_NS / 1000, true,
|
||||||
|
|
@ -656,22 +698,32 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
return extractorOutput.trackOutputs.get(2);
|
return extractorOutput.trackOutputs.get(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertVp9VideoFormat() {
|
private void assertTracksEnded() {
|
||||||
|
assertTrue(extractorOutput.tracksEnded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertVp9VideoFormat(int timecodeScale) {
|
||||||
MediaFormat format = getVideoOutput().format;
|
MediaFormat format = getVideoOutput().format;
|
||||||
|
assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000),
|
||||||
|
format.durationUs);
|
||||||
assertEquals(TEST_WIDTH, format.width);
|
assertEquals(TEST_WIDTH, format.width);
|
||||||
assertEquals(TEST_HEIGHT, format.height);
|
assertEquals(TEST_HEIGHT, format.height);
|
||||||
assertEquals(MimeTypes.VIDEO_VP9, format.mimeType);
|
assertEquals(MimeTypes.VIDEO_VP9, format.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertH264VideoFormat() {
|
private void assertH264VideoFormat(int timecodeScale) {
|
||||||
MediaFormat format = getVideoOutput().format;
|
MediaFormat format = getVideoOutput().format;
|
||||||
|
assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000),
|
||||||
|
format.durationUs);
|
||||||
assertEquals(TEST_WIDTH, format.width);
|
assertEquals(TEST_WIDTH, format.width);
|
||||||
assertEquals(TEST_HEIGHT, format.height);
|
assertEquals(TEST_HEIGHT, format.height);
|
||||||
assertEquals(MimeTypes.VIDEO_H264, format.mimeType);
|
assertEquals(MimeTypes.VIDEO_H264, format.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertAudioFormat(String expectedMimeType) {
|
private void assertAudioFormat(int timecodeScale, String expectedMimeType) {
|
||||||
MediaFormat format = getAudioOutput().format;
|
MediaFormat format = getAudioOutput().format;
|
||||||
|
assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000),
|
||||||
|
format.durationUs);
|
||||||
assertEquals(TEST_CHANNEL_COUNT, format.channelCount);
|
assertEquals(TEST_CHANNEL_COUNT, format.channelCount);
|
||||||
assertEquals(TEST_SAMPLE_RATE, format.sampleRate);
|
assertEquals(TEST_SAMPLE_RATE, format.sampleRate);
|
||||||
assertEquals(expectedMimeType, format.mimeType);
|
assertEquals(expectedMimeType, format.mimeType);
|
||||||
|
|
@ -688,15 +740,25 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertIndex(IndexPoint... indexPoints) {
|
private void assertIndex(int timecodeScale, int cuePointCount) {
|
||||||
ChunkIndex index = (ChunkIndex) extractorOutput.seekMap;
|
ChunkIndex index = (ChunkIndex) extractorOutput.seekMap;
|
||||||
assertEquals(indexPoints.length, index.length);
|
assertEquals(cuePointCount, index.length);
|
||||||
for (int i = 0; i < indexPoints.length; i++) {
|
for (int i = 0; i < cuePointCount - 1; i++) {
|
||||||
IndexPoint indexPoint = indexPoints[i];
|
assertEquals(Util.scaleLargeTimestamp(10 * i, timecodeScale, 1000), index.timesUs[i]);
|
||||||
assertEquals(indexPoint.timeUs, index.timesUs[i]);
|
assertEquals(Util.scaleLargeTimestamp(10, timecodeScale, 1000), index.durationsUs[i]);
|
||||||
assertEquals(indexPoint.size, index.sizes[i]);
|
assertEquals(0, index.sizes[i]);
|
||||||
assertEquals(indexPoint.durationUs, index.durationsUs[i]);
|
|
||||||
}
|
}
|
||||||
|
int lastIndex = cuePointCount - 1;
|
||||||
|
long lastTimecode = 10 * lastIndex;
|
||||||
|
long lastDurationTimecode = TEST_DURATION_TIMECODE - lastTimecode;
|
||||||
|
assertEquals(Util.scaleLargeTimestamp(lastTimecode, timecodeScale, 1000),
|
||||||
|
index.timesUs[lastIndex]);
|
||||||
|
assertEquals(Util.scaleLargeTimestamp(lastDurationTimecode, timecodeScale, 1000),
|
||||||
|
index.durationsUs[lastIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertIndexUnseekable() {
|
||||||
|
assertEquals(SeekMap.UNSEEKABLE, extractorOutput.seekMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSample(int index, byte[] expectedMedia, long timeUs, boolean keyframe,
|
private void assertSample(int index, byte[] expectedMedia, long timeUs, boolean keyframe,
|
||||||
|
|
@ -732,19 +794,4 @@ public final class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used by {@link #assertIndex(IndexPoint...)} to validate index elements. */
|
|
||||||
private static final class IndexPoint {
|
|
||||||
|
|
||||||
private final long timeUs;
|
|
||||||
private final int size;
|
|
||||||
private final long durationUs;
|
|
||||||
|
|
||||||
private IndexPoint(long timeUs, int size, long durationUs) {
|
|
||||||
this.timeUs = timeUs;
|
|
||||||
this.size = size;
|
|
||||||
this.durationUs = durationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue