mirror of
https://github.com/samsonjs/media.git
synced 2026-04-07 11:35:46 +00:00
Add support for partially fragmented MP4s
ISSUE: #7308 PiperOrigin-RevId: 319541273
This commit is contained in:
parent
0ee3a35ade
commit
6872910d5a
7 changed files with 770 additions and 46 deletions
|
|
@ -203,6 +203,7 @@
|
|||
([#6410](https://github.com/google/ExoPlayer/issues/6410)).
|
||||
* Select first extractors based on the filename extension and the response
|
||||
headers mime type in `DefaultExtractorsFactory`.
|
||||
* Add support for partially fragmented MP4s.
|
||||
* Testing
|
||||
* Add `TestExoPlayer`, a utility class with APIs to create
|
||||
`SimpleExoPlayer` instances with fake components for testing.
|
||||
|
|
|
|||
|
|
@ -280,7 +280,17 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
extractorOutput = output;
|
||||
if (sideloadedTrack != null) {
|
||||
TrackBundle bundle = new TrackBundle(output.track(0, sideloadedTrack.type));
|
||||
bundle.init(sideloadedTrack, new DefaultSampleValues(0, 0, 0, 0));
|
||||
bundle.init(
|
||||
new TrackSampleTable(
|
||||
sideloadedTrack,
|
||||
/* offsets= */ new long[0],
|
||||
/* sizes= */ new int[0],
|
||||
/* maximumSize= */ 0,
|
||||
/* timestampsUs= */ new long[0],
|
||||
/* flags= */ new int[0],
|
||||
/* durationUs= */ C.TIME_UNSET),
|
||||
new DefaultSampleValues(
|
||||
/* sampleDescriptionIndex= */ 0, /* duration= */ 0, /* size= */ 0, /* flags= */ 0));
|
||||
trackBundles.put(0, bundle);
|
||||
maybeInitExtraTracks();
|
||||
extractorOutput.endTracks();
|
||||
|
|
@ -368,6 +378,14 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
}
|
||||
|
||||
long atomPosition = input.getPosition() - atomHeaderBytesRead;
|
||||
if (atomType == Atom.TYPE_moof || atomType == Atom.TYPE_mdat) {
|
||||
if (!haveOutputSeekMap) {
|
||||
// This must be the first moof or mdat in the stream.
|
||||
extractorOutput.seekMap(new SeekMap.Unseekable(durationUs, atomPosition));
|
||||
haveOutputSeekMap = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (atomType == Atom.TYPE_moof) {
|
||||
// The data positions may be updated when parsing the tfhd/trun.
|
||||
int trackCount = trackBundles.size();
|
||||
|
|
@ -377,11 +395,6 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
fragment.auxiliaryDataPosition = atomPosition;
|
||||
fragment.dataPosition = atomPosition;
|
||||
}
|
||||
if (!haveOutputSeekMap) {
|
||||
// This must be the first moof in the stream.
|
||||
extractorOutput.seekMap(new SeekMap.Unseekable(durationUs, atomPosition));
|
||||
haveOutputSeekMap = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (atomType == Atom.TYPE_mdat) {
|
||||
|
|
@ -483,7 +496,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
}
|
||||
|
||||
// Construction of tracks and sample tables.
|
||||
List<TrackSampleTable> trackSampleTables =
|
||||
List<TrackSampleTable> sampleTables =
|
||||
parseTraks(
|
||||
moov,
|
||||
new GaplessInfoHolder(),
|
||||
|
|
@ -493,13 +506,14 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
/* isQuickTime= */ false,
|
||||
this::modifyTrack);
|
||||
|
||||
int trackCount = trackSampleTables.size();
|
||||
int trackCount = sampleTables.size();
|
||||
if (trackBundles.size() == 0) {
|
||||
// We need to create the track bundles.
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
Track track = trackSampleTables.get(i).track;
|
||||
TrackSampleTable sampleTable = sampleTables.get(i);
|
||||
Track track = sampleTable.track;
|
||||
TrackBundle trackBundle = new TrackBundle(extractorOutput.track(i, track.type));
|
||||
trackBundle.init(track, getDefaultSampleValues(defaultSampleValuesArray, track.id));
|
||||
trackBundle.init(sampleTable, getDefaultSampleValues(defaultSampleValuesArray, track.id));
|
||||
trackBundles.put(track.id, trackBundle);
|
||||
durationUs = Math.max(durationUs, track.durationUs);
|
||||
}
|
||||
|
|
@ -508,10 +522,11 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
} else {
|
||||
Assertions.checkState(trackBundles.size() == trackCount);
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
Track track = trackSampleTables.get(i).track;
|
||||
TrackSampleTable sampleTable = sampleTables.get(i);
|
||||
Track track = sampleTable.track;
|
||||
trackBundles
|
||||
.get(track.id)
|
||||
.init(track, getDefaultSampleValues(defaultSampleValuesArray, track.id));
|
||||
.init(sampleTable, getDefaultSampleValues(defaultSampleValuesArray, track.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -702,6 +717,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
TrackFragment fragment = trackBundle.fragment;
|
||||
long decodeTime = fragment.nextFragmentDecodeTime;
|
||||
trackBundle.reset();
|
||||
trackBundle.currentlyInFragment = true;
|
||||
|
||||
@Nullable LeafAtom tfdtAtom = traf.getLeafAtomOfType(Atom.TYPE_tfdt);
|
||||
if (tfdtAtom != null && (flags & FLAG_WORKAROUND_IGNORE_TFDT_BOX) == 0) {
|
||||
|
|
@ -712,7 +728,8 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
|
||||
@Nullable
|
||||
TrackEncryptionBox encryptionBox =
|
||||
trackBundle.track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex);
|
||||
trackBundle.moovSampleTable.track.getSampleDescriptionEncryptionBox(
|
||||
fragment.header.sampleDescriptionIndex);
|
||||
|
||||
@Nullable LeafAtom saiz = traf.getLeafAtomOfType(Atom.TYPE_saiz);
|
||||
if (saiz != null) {
|
||||
|
|
@ -933,7 +950,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
int fullAtom = trun.readInt();
|
||||
int atomFlags = Atom.parseFullAtomFlags(fullAtom);
|
||||
|
||||
Track track = trackBundle.track;
|
||||
Track track = trackBundle.moovSampleTable.track;
|
||||
TrackFragment fragment = trackBundle.fragment;
|
||||
DefaultSampleValues defaultSampleValues = fragment.header;
|
||||
|
||||
|
|
@ -1001,6 +1018,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
}
|
||||
sampleDecodingTimeUsTable[i] =
|
||||
Util.scaleLargeTimestamp(cumulativeTime, C.MICROS_PER_SECOND, timescale) - edtsOffsetUs;
|
||||
sampleDecodingTimeUsTable[i] += trackBundle.moovSampleTable.durationUs;
|
||||
sampleSizeTable[i] = sampleSize;
|
||||
sampleIsSyncFrameTable[i] = ((sampleFlags >> 16) & 0x1) == 0
|
||||
&& (!workaroundEveryVideoFrameIsSyncFrame || i == 0);
|
||||
|
|
@ -1225,7 +1243,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
private boolean readSample(ExtractorInput input) throws IOException {
|
||||
if (parserState == STATE_READING_SAMPLE_START) {
|
||||
if (currentTrackBundle == null) {
|
||||
@Nullable TrackBundle currentTrackBundle = getNextFragmentRun(trackBundles);
|
||||
@Nullable TrackBundle currentTrackBundle = getNextTrackBundle(trackBundles);
|
||||
if (currentTrackBundle == null) {
|
||||
// We've run out of samples in the current mdat. Discard any trailing data and prepare to
|
||||
// read the header of the next atom.
|
||||
|
|
@ -1262,12 +1280,14 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (currentTrackBundle.track.sampleTransformation == Track.TRANSFORMATION_CEA608_CDAT) {
|
||||
if (currentTrackBundle.moovSampleTable.track.sampleTransformation
|
||||
== Track.TRANSFORMATION_CEA608_CDAT) {
|
||||
sampleSize -= Atom.HEADER_SIZE;
|
||||
input.skipFully(Atom.HEADER_SIZE);
|
||||
}
|
||||
|
||||
if (MimeTypes.AUDIO_AC4.equals(currentTrackBundle.track.format.sampleMimeType)) {
|
||||
if (MimeTypes.AUDIO_AC4.equals(
|
||||
currentTrackBundle.moovSampleTable.track.format.sampleMimeType)) {
|
||||
// AC4 samples need to be prefixed with a clear sample header.
|
||||
sampleBytesWritten =
|
||||
currentTrackBundle.outputSampleEncryptionData(sampleSize, Ac4Util.SAMPLE_HEADER_SIZE);
|
||||
|
|
@ -1283,7 +1303,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
sampleCurrentNalBytesRemaining = 0;
|
||||
}
|
||||
|
||||
Track track = currentTrackBundle.track;
|
||||
Track track = currentTrackBundle.moovSampleTable.track;
|
||||
TrackOutput output = currentTrackBundle.output;
|
||||
long sampleTimeUs = currentTrackBundle.getCurrentSamplePresentationTimeUs();
|
||||
if (timestampAdjuster != null) {
|
||||
|
|
@ -1390,24 +1410,27 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TrackBundle} whose fragment run has the earliest file position out of those
|
||||
* yet to be consumed, or null if all have been consumed.
|
||||
* Returns the {@link TrackBundle} whose sample has the earliest file position out of those yet to
|
||||
* be consumed, or null if all have been consumed.
|
||||
*/
|
||||
@Nullable
|
||||
private static TrackBundle getNextFragmentRun(SparseArray<TrackBundle> trackBundles) {
|
||||
private static TrackBundle getNextTrackBundle(SparseArray<TrackBundle> trackBundles) {
|
||||
TrackBundle nextTrackBundle = null;
|
||||
long nextTrackRunOffset = Long.MAX_VALUE;
|
||||
long nextSampleOffset = Long.MAX_VALUE;
|
||||
|
||||
int trackBundlesSize = trackBundles.size();
|
||||
for (int i = 0; i < trackBundlesSize; i++) {
|
||||
TrackBundle trackBundle = trackBundles.valueAt(i);
|
||||
if (trackBundle.currentTrackRunIndex == trackBundle.fragment.trunCount) {
|
||||
// This track fragment contains no more runs in the next mdat box.
|
||||
if ((!trackBundle.currentlyInFragment
|
||||
&& trackBundle.currentSampleIndex == trackBundle.moovSampleTable.sampleCount)
|
||||
|| (trackBundle.currentlyInFragment
|
||||
&& trackBundle.currentTrackRunIndex == trackBundle.fragment.trunCount)) {
|
||||
// This track sample table or fragment contains no more runs in the next mdat box.
|
||||
} else {
|
||||
long trunOffset = trackBundle.getCurrentSampleOffset();
|
||||
if (trunOffset < nextTrackRunOffset) {
|
||||
long sampleOffset = trackBundle.getCurrentSampleOffset();
|
||||
if (sampleOffset < nextSampleOffset) {
|
||||
nextTrackBundle = trackBundle;
|
||||
nextTrackRunOffset = trunOffset;
|
||||
nextSampleOffset = sampleOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1502,7 +1525,7 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
public final TrackFragment fragment;
|
||||
public final ParsableByteArray scratch;
|
||||
|
||||
public Track track;
|
||||
public TrackSampleTable moovSampleTable;
|
||||
public DefaultSampleValues defaultSampleValues;
|
||||
public int currentSampleIndex;
|
||||
public int currentSampleInTrackRun;
|
||||
|
|
@ -1512,6 +1535,8 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
private final ParsableByteArray encryptionSignalByte;
|
||||
private final ParsableByteArray defaultInitializationVector;
|
||||
|
||||
private boolean currentlyInFragment;
|
||||
|
||||
public TrackBundle(TrackOutput output) {
|
||||
this.output = output;
|
||||
fragment = new TrackFragment();
|
||||
|
|
@ -1520,30 +1545,34 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
defaultInitializationVector = new ParsableByteArray();
|
||||
}
|
||||
|
||||
public void init(Track track, DefaultSampleValues defaultSampleValues) {
|
||||
this.track = Assertions.checkNotNull(track);
|
||||
public void init(TrackSampleTable moovSampleTable, DefaultSampleValues defaultSampleValues) {
|
||||
Assertions.checkNotNull(moovSampleTable.track);
|
||||
this.moovSampleTable = moovSampleTable;
|
||||
this.defaultSampleValues = Assertions.checkNotNull(defaultSampleValues);
|
||||
output.format(track.format);
|
||||
output.format(moovSampleTable.track.format);
|
||||
reset();
|
||||
}
|
||||
|
||||
public void updateDrmInitData(DrmInitData drmInitData) {
|
||||
@Nullable
|
||||
TrackEncryptionBox encryptionBox =
|
||||
track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex);
|
||||
moovSampleTable.track.getSampleDescriptionEncryptionBox(
|
||||
fragment.header.sampleDescriptionIndex);
|
||||
@Nullable String schemeType = encryptionBox != null ? encryptionBox.schemeType : null;
|
||||
DrmInitData updatedDrmInitData = drmInitData.copyWithSchemeType(schemeType);
|
||||
Format format = track.format.buildUpon().setDrmInitData(updatedDrmInitData).build();
|
||||
Format format =
|
||||
moovSampleTable.track.format.buildUpon().setDrmInitData(updatedDrmInitData).build();
|
||||
output.format(format);
|
||||
}
|
||||
|
||||
/** Resets the current fragment and sample indices. */
|
||||
/** Resets the current fragment, sample indices and {@code isInFragment} boolean. */
|
||||
public void reset() {
|
||||
fragment.reset();
|
||||
currentSampleIndex = 0;
|
||||
currentTrackRunIndex = 0;
|
||||
currentSampleInTrackRun = 0;
|
||||
firstSampleToOutputIndex = 0;
|
||||
currentlyInFragment = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1565,23 +1594,32 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
|
||||
/** Returns the presentation time of the current sample in microseconds. */
|
||||
public long getCurrentSamplePresentationTimeUs() {
|
||||
return fragment.getSamplePresentationTimeUs(currentSampleIndex);
|
||||
return !currentlyInFragment
|
||||
? moovSampleTable.timestampsUs[currentSampleIndex]
|
||||
: fragment.getSamplePresentationTimeUs(currentSampleIndex);
|
||||
}
|
||||
|
||||
/** Returns the byte offset of the current sample. */
|
||||
public long getCurrentSampleOffset() {
|
||||
return fragment.trunDataPosition[currentTrackRunIndex];
|
||||
return !currentlyInFragment
|
||||
? moovSampleTable.offsets[currentSampleIndex]
|
||||
: fragment.trunDataPosition[currentTrackRunIndex];
|
||||
}
|
||||
|
||||
/** Returns the size of the current sample in bytes. */
|
||||
public int getCurrentSampleSize() {
|
||||
return fragment.sampleSizeTable[currentSampleIndex];
|
||||
return !currentlyInFragment
|
||||
? moovSampleTable.sizes[currentSampleIndex]
|
||||
: fragment.sampleSizeTable[currentSampleIndex];
|
||||
}
|
||||
|
||||
/** Returns the {@link C.BufferFlags} corresponding to the the current sample. */
|
||||
@C.BufferFlags
|
||||
public int getCurrentSampleFlags() {
|
||||
int flags = fragment.sampleIsSyncFrameTable[currentSampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
int flags =
|
||||
!currentlyInFragment
|
||||
? moovSampleTable.flags[currentSampleIndex]
|
||||
: (fragment.sampleIsSyncFrameTable[currentSampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0);
|
||||
if (getEncryptionBoxIfEncrypted() != null) {
|
||||
flags |= C.BUFFER_FLAG_ENCRYPTED;
|
||||
}
|
||||
|
|
@ -1589,15 +1627,23 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Advances the indices in the bundle to point to the next sample in the current fragment. If
|
||||
* the current sample is the last one in the current fragment, then the advanced state will be
|
||||
* {@code currentSampleIndex == fragment.sampleCount}, {@code currentTrackRunIndex ==
|
||||
* fragment.trunCount} and {@code #currentSampleInTrackRun == 0}.
|
||||
* Advances the indices in the bundle to point to the next sample in the sample table (if it has
|
||||
* not reached the fragments yet) or in the current fragment.
|
||||
*
|
||||
* @return Whether the next sample is in the same track run as the previous one.
|
||||
* <p>If the current sample is the last one in the sample table, then the advanced state will be
|
||||
* {@code currentSampleIndex == moovSampleTable.sampleCount}. If the current sample is the last
|
||||
* one in the current fragment, then the advanced state will be {@code currentSampleIndex ==
|
||||
* fragment.sampleCount}, {@code currentTrackRunIndex == fragment.trunCount} and {@code
|
||||
* #currentSampleInTrackRun == 0}.
|
||||
*
|
||||
* @return Whether this {@link TrackBundle} can be used to read the next sample without
|
||||
* recomputing the next {@link TrackBundle}.
|
||||
*/
|
||||
public boolean next() {
|
||||
currentSampleIndex++;
|
||||
if (!currentlyInFragment) {
|
||||
return false;
|
||||
}
|
||||
currentSampleInTrackRun++;
|
||||
if (currentSampleInTrackRun == fragment.trunLength[currentTrackRunIndex]) {
|
||||
currentTrackRunIndex++;
|
||||
|
|
@ -1610,6 +1656,8 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
/**
|
||||
* Outputs the encryption data for the current sample.
|
||||
*
|
||||
* <p>This is not supported yet for samples specified in the sample table.
|
||||
*
|
||||
* @param sampleSize The size of the current sample in bytes, excluding any additional clear
|
||||
* header that will be prefixed to the sample by the extractor.
|
||||
* @param clearHeaderSize The size of a clear header that will be prefixed to the sample by the
|
||||
|
|
@ -1699,7 +1747,11 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
return 1 + vectorSize + subsampleDataLength;
|
||||
}
|
||||
|
||||
/** Skips the encryption data for the current sample. */
|
||||
/**
|
||||
* Skips the encryption data for the current sample.
|
||||
*
|
||||
* <p>This is not supported yet for samples specified in the sample table.
|
||||
*/
|
||||
public void skipSampleEncryptionData() {
|
||||
@Nullable TrackEncryptionBox encryptionBox = getEncryptionBoxIfEncrypted();
|
||||
if (encryptionBox == null) {
|
||||
|
|
@ -1717,12 +1769,16 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||
|
||||
@Nullable
|
||||
public TrackEncryptionBox getEncryptionBoxIfEncrypted() {
|
||||
if (!currentlyInFragment) {
|
||||
// Encryption is not supported yet for samples specified in the sample table.
|
||||
return null;
|
||||
}
|
||||
int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex;
|
||||
@Nullable
|
||||
TrackEncryptionBox encryptionBox =
|
||||
fragment.trackEncryptionBox != null
|
||||
? fragment.trackEncryptionBox
|
||||
: track.getSampleDescriptionEncryptionBox(sampleDescriptionIndex);
|
||||
: moovSampleTable.track.getSampleDescriptionEncryptionBox(sampleDescriptionIndex);
|
||||
return encryptionBox != null && encryptionBox.isEncrypted ? encryptionBox : null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
*/
|
||||
public boolean sampleEncryptionDataNeedsFill;
|
||||
/**
|
||||
* The absolute decode time of the start of the next fragment.
|
||||
* The absolute decode time of the start of the next fragment, excluding the samples outside
|
||||
* fragments.
|
||||
*/
|
||||
public long nextFragmentDecodeTime;
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,14 @@ public final class FragmentedMp4ExtractorTest {
|
|||
simulationConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void samplePartiallyFragmented() throws Exception {
|
||||
ExtractorAsserts.assertBehavior(
|
||||
getExtractorFactory(ImmutableList.of()),
|
||||
"mp4/sample_partially_fragmented.mp4",
|
||||
simulationConfig);
|
||||
}
|
||||
|
||||
private static ExtractorFactory getExtractorFactory(final List<Format> closedCaptionFormats) {
|
||||
return () ->
|
||||
new FragmentedMp4Extractor(
|
||||
|
|
|
|||
BIN
testdata/src/test/assets/mp4/sample_partially_fragmented.mp4
vendored
Normal file
BIN
testdata/src/test/assets/mp4/sample_partially_fragmented.mp4
vendored
Normal file
Binary file not shown.
329
testdata/src/test/assets/mp4/sample_partially_fragmented.mp4.0.dump
vendored
Normal file
329
testdata/src/test/assets/mp4/sample_partially_fragmented.mp4.0.dump
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
seekMap:
|
||||
isSeekable = false
|
||||
duration = 134000
|
||||
getPosition(0) = [[timeUs=0, position=1428]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 87715
|
||||
sample count = 30
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
width = 1080
|
||||
height = 720
|
||||
initializationData:
|
||||
data = length 29, hash 4746B5D9
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample 0:
|
||||
time = 66733
|
||||
flags = 1
|
||||
data = length 37655, hash 265F7BA7
|
||||
sample 1:
|
||||
time = 133466
|
||||
flags = 0
|
||||
data = length 5023, hash 30768D40
|
||||
sample 2:
|
||||
time = 100100
|
||||
flags = 0
|
||||
data = length 497, hash 9E536CA2
|
||||
sample 3:
|
||||
time = 200200
|
||||
flags = 536870912
|
||||
data = length 5867, hash 56F9EE87
|
||||
sample 4:
|
||||
time = 400398
|
||||
flags = 0
|
||||
data = length 570, hash 984421BD
|
||||
sample 5:
|
||||
time = 500499
|
||||
flags = 0
|
||||
data = length 3406, hash 9A33201E
|
||||
sample 6:
|
||||
time = 467132
|
||||
flags = 0
|
||||
data = length 476, hash C59620F3
|
||||
sample 7:
|
||||
time = 567232
|
||||
flags = 0
|
||||
data = length 4310, hash 291E6161
|
||||
sample 8:
|
||||
time = 533865
|
||||
flags = 0
|
||||
data = length 497, hash 398CBFAA
|
||||
sample 9:
|
||||
time = 700699
|
||||
flags = 0
|
||||
data = length 4449, hash 322CAA2B
|
||||
sample 10:
|
||||
time = 633965
|
||||
flags = 0
|
||||
data = length 1076, hash B479B634
|
||||
sample 11:
|
||||
time = 600599
|
||||
flags = 0
|
||||
data = length 365, hash 68C7D4C2
|
||||
sample 12:
|
||||
time = 667332
|
||||
flags = 0
|
||||
data = length 463, hash A85F9769
|
||||
sample 13:
|
||||
time = 834165
|
||||
flags = 0
|
||||
data = length 5339, hash F232195D
|
||||
sample 14:
|
||||
time = 767432
|
||||
flags = 0
|
||||
data = length 1085, hash 47AFB6FE
|
||||
sample 15:
|
||||
time = 734066
|
||||
flags = 0
|
||||
data = length 689, hash 3EB753A3
|
||||
sample 16:
|
||||
time = 800798
|
||||
flags = 0
|
||||
data = length 516, hash E6DF9C1C
|
||||
sample 17:
|
||||
time = 967632
|
||||
flags = 0
|
||||
data = length 4899, hash A9A8F4B7
|
||||
sample 18:
|
||||
time = 900899
|
||||
flags = 0
|
||||
data = length 963, hash 684782FB
|
||||
sample 19:
|
||||
time = 867532
|
||||
flags = 0
|
||||
data = length 625, hash ED1C8EF1
|
||||
sample 20:
|
||||
time = 934265
|
||||
flags = 0
|
||||
data = length 492, hash E6E066EA
|
||||
sample 21:
|
||||
time = 1101099
|
||||
flags = 0
|
||||
data = length 2973, hash A3C54C3B
|
||||
sample 22:
|
||||
time = 1034365
|
||||
flags = 0
|
||||
data = length 833, hash 41CA807D
|
||||
sample 23:
|
||||
time = 1000999
|
||||
flags = 0
|
||||
data = length 516, hash 5B21BB11
|
||||
sample 24:
|
||||
time = 1067732
|
||||
flags = 0
|
||||
data = length 384, hash A0E8FA50
|
||||
sample 25:
|
||||
time = 1234565
|
||||
flags = 0
|
||||
data = length 1450, hash 92741C3B
|
||||
sample 26:
|
||||
time = 1167832
|
||||
flags = 0
|
||||
data = length 831, hash DDA0685B
|
||||
sample 27:
|
||||
time = 1134466
|
||||
flags = 0
|
||||
data = length 413, hash 886904C
|
||||
sample 28:
|
||||
time = 1201198
|
||||
flags = 0
|
||||
data = length 427, hash FC2FA8CC
|
||||
sample 29:
|
||||
time = 1267932
|
||||
flags = 0
|
||||
data = length 626, hash DCE82342
|
||||
track 1:
|
||||
total output bytes = 10107
|
||||
sample count = 45
|
||||
format 0:
|
||||
id = 2
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
codecs = mp4a.40.2
|
||||
channelCount = 1
|
||||
sampleRate = 44100
|
||||
language = und
|
||||
initializationData:
|
||||
data = length 5, hash 2B7623A
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 21, hash D57A2CCC
|
||||
sample 1:
|
||||
time = 267890
|
||||
flags = 1
|
||||
data = length 6, hash 336D5819
|
||||
sample 2:
|
||||
time = 291110
|
||||
flags = 1
|
||||
data = length 279, hash 6E3E48B0
|
||||
sample 3:
|
||||
time = 314330
|
||||
flags = 1
|
||||
data = length 286, hash 5AABFF
|
||||
sample 4:
|
||||
time = 337550
|
||||
flags = 1
|
||||
data = length 275, hash D3109764
|
||||
sample 5:
|
||||
time = 360770
|
||||
flags = 1
|
||||
data = length 284, hash 154B6E9
|
||||
sample 6:
|
||||
time = 383990
|
||||
flags = 1
|
||||
data = length 273, hash 40C8A066
|
||||
sample 7:
|
||||
time = 407210
|
||||
flags = 1
|
||||
data = length 272, hash 4211880F
|
||||
sample 8:
|
||||
time = 430430
|
||||
flags = 1
|
||||
data = length 281, hash 1F534130
|
||||
sample 9:
|
||||
time = 453650
|
||||
flags = 1
|
||||
data = length 279, hash F5B3EE5F
|
||||
sample 10:
|
||||
time = 476870
|
||||
flags = 1
|
||||
data = length 282, hash 6CDF1B54
|
||||
sample 11:
|
||||
time = 500090
|
||||
flags = 1
|
||||
data = length 291, hash 6EC03046
|
||||
sample 12:
|
||||
time = 523310
|
||||
flags = 1
|
||||
data = length 296, hash 9C7F2E6A
|
||||
sample 13:
|
||||
time = 546530
|
||||
flags = 1
|
||||
data = length 282, hash 584ABD5E
|
||||
sample 14:
|
||||
time = 569749
|
||||
flags = 1
|
||||
data = length 283, hash 38CB1734
|
||||
sample 15:
|
||||
time = 592969
|
||||
flags = 1
|
||||
data = length 274, hash 648EC8BD
|
||||
sample 16:
|
||||
time = 616189
|
||||
flags = 1
|
||||
data = length 274, hash E8FE0F68
|
||||
sample 17:
|
||||
time = 639409
|
||||
flags = 1
|
||||
data = length 277, hash 2E1B8A11
|
||||
sample 18:
|
||||
time = 662629
|
||||
flags = 1
|
||||
data = length 282, hash FB6ACCED
|
||||
sample 19:
|
||||
time = 685849
|
||||
flags = 1
|
||||
data = length 283, hash 152D69D
|
||||
sample 20:
|
||||
time = 709069
|
||||
flags = 1
|
||||
data = length 274, hash 45F44C4B
|
||||
sample 21:
|
||||
time = 732289
|
||||
flags = 1
|
||||
data = length 242, hash F9225BB7
|
||||
sample 22:
|
||||
time = 755509
|
||||
flags = 1
|
||||
data = length 207, hash F5DFB6B2
|
||||
sample 23:
|
||||
time = 778729
|
||||
flags = 1
|
||||
data = length 226, hash 41DC63E1
|
||||
sample 24:
|
||||
time = 801949
|
||||
flags = 1
|
||||
data = length 218, hash A82772CF
|
||||
sample 25:
|
||||
time = 825169
|
||||
flags = 1
|
||||
data = length 223, hash 861AB80
|
||||
sample 26:
|
||||
time = 848389
|
||||
flags = 1
|
||||
data = length 220, hash F1CBA15E
|
||||
sample 27:
|
||||
time = 871609
|
||||
flags = 1
|
||||
data = length 203, hash CB57EEF7
|
||||
sample 28:
|
||||
time = 894829
|
||||
flags = 1
|
||||
data = length 206, hash 766F4D9E
|
||||
sample 29:
|
||||
time = 918049
|
||||
flags = 1
|
||||
data = length 210, hash FE2A2935
|
||||
sample 30:
|
||||
time = 941269
|
||||
flags = 1
|
||||
data = length 207, hash A06A178D
|
||||
sample 31:
|
||||
time = 964489
|
||||
flags = 1
|
||||
data = length 206, hash 1ABD9A5F
|
||||
sample 32:
|
||||
time = 987709
|
||||
flags = 1
|
||||
data = length 209, hash 69D7E5F3
|
||||
sample 33:
|
||||
time = 1010929
|
||||
flags = 1
|
||||
data = length 173, hash 7CE0FDCA
|
||||
sample 34:
|
||||
time = 1034149
|
||||
flags = 1
|
||||
data = length 208, hash 21D67E09
|
||||
sample 35:
|
||||
time = 1057369
|
||||
flags = 1
|
||||
data = length 207, hash C7187D46
|
||||
sample 36:
|
||||
time = 1080588
|
||||
flags = 1
|
||||
data = length 180, hash D17CFAF8
|
||||
sample 37:
|
||||
time = 1103808
|
||||
flags = 1
|
||||
data = length 206, hash C58FD669
|
||||
sample 38:
|
||||
time = 1127028
|
||||
flags = 1
|
||||
data = length 212, hash 27E2F2C4
|
||||
sample 39:
|
||||
time = 1150248
|
||||
flags = 1
|
||||
data = length 190, hash 534CC89E
|
||||
sample 40:
|
||||
time = 1173468
|
||||
flags = 1
|
||||
data = length 180, hash 1C58DF95
|
||||
sample 41:
|
||||
time = 1196688
|
||||
flags = 1
|
||||
data = length 213, hash 24FBF10A
|
||||
sample 42:
|
||||
time = 1219908
|
||||
flags = 1
|
||||
data = length 186, hash EFC31805
|
||||
sample 43:
|
||||
time = 1243128
|
||||
flags = 1
|
||||
data = length 208, hash 4A050A0D
|
||||
sample 44:
|
||||
time = 1266348
|
||||
flags = 1
|
||||
data = length 13, hash 2555A7DC
|
||||
tracksEnded = true
|
||||
329
testdata/src/test/assets/mp4/sample_partially_fragmented.mp4.unknown_length.dump
vendored
Normal file
329
testdata/src/test/assets/mp4/sample_partially_fragmented.mp4.unknown_length.dump
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
seekMap:
|
||||
isSeekable = false
|
||||
duration = 134000
|
||||
getPosition(0) = [[timeUs=0, position=1428]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 87715
|
||||
sample count = 30
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
width = 1080
|
||||
height = 720
|
||||
initializationData:
|
||||
data = length 29, hash 4746B5D9
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample 0:
|
||||
time = 66733
|
||||
flags = 1
|
||||
data = length 37655, hash 265F7BA7
|
||||
sample 1:
|
||||
time = 133466
|
||||
flags = 0
|
||||
data = length 5023, hash 30768D40
|
||||
sample 2:
|
||||
time = 100100
|
||||
flags = 0
|
||||
data = length 497, hash 9E536CA2
|
||||
sample 3:
|
||||
time = 200200
|
||||
flags = 536870912
|
||||
data = length 5867, hash 56F9EE87
|
||||
sample 4:
|
||||
time = 400398
|
||||
flags = 0
|
||||
data = length 570, hash 984421BD
|
||||
sample 5:
|
||||
time = 500499
|
||||
flags = 0
|
||||
data = length 3406, hash 9A33201E
|
||||
sample 6:
|
||||
time = 467132
|
||||
flags = 0
|
||||
data = length 476, hash C59620F3
|
||||
sample 7:
|
||||
time = 567232
|
||||
flags = 0
|
||||
data = length 4310, hash 291E6161
|
||||
sample 8:
|
||||
time = 533865
|
||||
flags = 0
|
||||
data = length 497, hash 398CBFAA
|
||||
sample 9:
|
||||
time = 700699
|
||||
flags = 0
|
||||
data = length 4449, hash 322CAA2B
|
||||
sample 10:
|
||||
time = 633965
|
||||
flags = 0
|
||||
data = length 1076, hash B479B634
|
||||
sample 11:
|
||||
time = 600599
|
||||
flags = 0
|
||||
data = length 365, hash 68C7D4C2
|
||||
sample 12:
|
||||
time = 667332
|
||||
flags = 0
|
||||
data = length 463, hash A85F9769
|
||||
sample 13:
|
||||
time = 834165
|
||||
flags = 0
|
||||
data = length 5339, hash F232195D
|
||||
sample 14:
|
||||
time = 767432
|
||||
flags = 0
|
||||
data = length 1085, hash 47AFB6FE
|
||||
sample 15:
|
||||
time = 734066
|
||||
flags = 0
|
||||
data = length 689, hash 3EB753A3
|
||||
sample 16:
|
||||
time = 800798
|
||||
flags = 0
|
||||
data = length 516, hash E6DF9C1C
|
||||
sample 17:
|
||||
time = 967632
|
||||
flags = 0
|
||||
data = length 4899, hash A9A8F4B7
|
||||
sample 18:
|
||||
time = 900899
|
||||
flags = 0
|
||||
data = length 963, hash 684782FB
|
||||
sample 19:
|
||||
time = 867532
|
||||
flags = 0
|
||||
data = length 625, hash ED1C8EF1
|
||||
sample 20:
|
||||
time = 934265
|
||||
flags = 0
|
||||
data = length 492, hash E6E066EA
|
||||
sample 21:
|
||||
time = 1101099
|
||||
flags = 0
|
||||
data = length 2973, hash A3C54C3B
|
||||
sample 22:
|
||||
time = 1034365
|
||||
flags = 0
|
||||
data = length 833, hash 41CA807D
|
||||
sample 23:
|
||||
time = 1000999
|
||||
flags = 0
|
||||
data = length 516, hash 5B21BB11
|
||||
sample 24:
|
||||
time = 1067732
|
||||
flags = 0
|
||||
data = length 384, hash A0E8FA50
|
||||
sample 25:
|
||||
time = 1234565
|
||||
flags = 0
|
||||
data = length 1450, hash 92741C3B
|
||||
sample 26:
|
||||
time = 1167832
|
||||
flags = 0
|
||||
data = length 831, hash DDA0685B
|
||||
sample 27:
|
||||
time = 1134466
|
||||
flags = 0
|
||||
data = length 413, hash 886904C
|
||||
sample 28:
|
||||
time = 1201198
|
||||
flags = 0
|
||||
data = length 427, hash FC2FA8CC
|
||||
sample 29:
|
||||
time = 1267932
|
||||
flags = 0
|
||||
data = length 626, hash DCE82342
|
||||
track 1:
|
||||
total output bytes = 10107
|
||||
sample count = 45
|
||||
format 0:
|
||||
id = 2
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
codecs = mp4a.40.2
|
||||
channelCount = 1
|
||||
sampleRate = 44100
|
||||
language = und
|
||||
initializationData:
|
||||
data = length 5, hash 2B7623A
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 21, hash D57A2CCC
|
||||
sample 1:
|
||||
time = 267890
|
||||
flags = 1
|
||||
data = length 6, hash 336D5819
|
||||
sample 2:
|
||||
time = 291110
|
||||
flags = 1
|
||||
data = length 279, hash 6E3E48B0
|
||||
sample 3:
|
||||
time = 314330
|
||||
flags = 1
|
||||
data = length 286, hash 5AABFF
|
||||
sample 4:
|
||||
time = 337550
|
||||
flags = 1
|
||||
data = length 275, hash D3109764
|
||||
sample 5:
|
||||
time = 360770
|
||||
flags = 1
|
||||
data = length 284, hash 154B6E9
|
||||
sample 6:
|
||||
time = 383990
|
||||
flags = 1
|
||||
data = length 273, hash 40C8A066
|
||||
sample 7:
|
||||
time = 407210
|
||||
flags = 1
|
||||
data = length 272, hash 4211880F
|
||||
sample 8:
|
||||
time = 430430
|
||||
flags = 1
|
||||
data = length 281, hash 1F534130
|
||||
sample 9:
|
||||
time = 453650
|
||||
flags = 1
|
||||
data = length 279, hash F5B3EE5F
|
||||
sample 10:
|
||||
time = 476870
|
||||
flags = 1
|
||||
data = length 282, hash 6CDF1B54
|
||||
sample 11:
|
||||
time = 500090
|
||||
flags = 1
|
||||
data = length 291, hash 6EC03046
|
||||
sample 12:
|
||||
time = 523310
|
||||
flags = 1
|
||||
data = length 296, hash 9C7F2E6A
|
||||
sample 13:
|
||||
time = 546530
|
||||
flags = 1
|
||||
data = length 282, hash 584ABD5E
|
||||
sample 14:
|
||||
time = 569749
|
||||
flags = 1
|
||||
data = length 283, hash 38CB1734
|
||||
sample 15:
|
||||
time = 592969
|
||||
flags = 1
|
||||
data = length 274, hash 648EC8BD
|
||||
sample 16:
|
||||
time = 616189
|
||||
flags = 1
|
||||
data = length 274, hash E8FE0F68
|
||||
sample 17:
|
||||
time = 639409
|
||||
flags = 1
|
||||
data = length 277, hash 2E1B8A11
|
||||
sample 18:
|
||||
time = 662629
|
||||
flags = 1
|
||||
data = length 282, hash FB6ACCED
|
||||
sample 19:
|
||||
time = 685849
|
||||
flags = 1
|
||||
data = length 283, hash 152D69D
|
||||
sample 20:
|
||||
time = 709069
|
||||
flags = 1
|
||||
data = length 274, hash 45F44C4B
|
||||
sample 21:
|
||||
time = 732289
|
||||
flags = 1
|
||||
data = length 242, hash F9225BB7
|
||||
sample 22:
|
||||
time = 755509
|
||||
flags = 1
|
||||
data = length 207, hash F5DFB6B2
|
||||
sample 23:
|
||||
time = 778729
|
||||
flags = 1
|
||||
data = length 226, hash 41DC63E1
|
||||
sample 24:
|
||||
time = 801949
|
||||
flags = 1
|
||||
data = length 218, hash A82772CF
|
||||
sample 25:
|
||||
time = 825169
|
||||
flags = 1
|
||||
data = length 223, hash 861AB80
|
||||
sample 26:
|
||||
time = 848389
|
||||
flags = 1
|
||||
data = length 220, hash F1CBA15E
|
||||
sample 27:
|
||||
time = 871609
|
||||
flags = 1
|
||||
data = length 203, hash CB57EEF7
|
||||
sample 28:
|
||||
time = 894829
|
||||
flags = 1
|
||||
data = length 206, hash 766F4D9E
|
||||
sample 29:
|
||||
time = 918049
|
||||
flags = 1
|
||||
data = length 210, hash FE2A2935
|
||||
sample 30:
|
||||
time = 941269
|
||||
flags = 1
|
||||
data = length 207, hash A06A178D
|
||||
sample 31:
|
||||
time = 964489
|
||||
flags = 1
|
||||
data = length 206, hash 1ABD9A5F
|
||||
sample 32:
|
||||
time = 987709
|
||||
flags = 1
|
||||
data = length 209, hash 69D7E5F3
|
||||
sample 33:
|
||||
time = 1010929
|
||||
flags = 1
|
||||
data = length 173, hash 7CE0FDCA
|
||||
sample 34:
|
||||
time = 1034149
|
||||
flags = 1
|
||||
data = length 208, hash 21D67E09
|
||||
sample 35:
|
||||
time = 1057369
|
||||
flags = 1
|
||||
data = length 207, hash C7187D46
|
||||
sample 36:
|
||||
time = 1080588
|
||||
flags = 1
|
||||
data = length 180, hash D17CFAF8
|
||||
sample 37:
|
||||
time = 1103808
|
||||
flags = 1
|
||||
data = length 206, hash C58FD669
|
||||
sample 38:
|
||||
time = 1127028
|
||||
flags = 1
|
||||
data = length 212, hash 27E2F2C4
|
||||
sample 39:
|
||||
time = 1150248
|
||||
flags = 1
|
||||
data = length 190, hash 534CC89E
|
||||
sample 40:
|
||||
time = 1173468
|
||||
flags = 1
|
||||
data = length 180, hash 1C58DF95
|
||||
sample 41:
|
||||
time = 1196688
|
||||
flags = 1
|
||||
data = length 213, hash 24FBF10A
|
||||
sample 42:
|
||||
time = 1219908
|
||||
flags = 1
|
||||
data = length 186, hash EFC31805
|
||||
sample 43:
|
||||
time = 1243128
|
||||
flags = 1
|
||||
data = length 208, hash 4A050A0D
|
||||
sample 44:
|
||||
time = 1266348
|
||||
flags = 1
|
||||
data = length 13, hash 2555A7DC
|
||||
tracksEnded = true
|
||||
Loading…
Reference in a new issue