Fragmented Mp4Muxer: add support to B-frame Muxing
Add composition time offset parameter to TRUN box to support muxing of videos containing B-frames by FragmentedMp4Muxer. Update TRUN box version from 0 to 1 in order to manage signed composition time offset. PiperOrigin-RevId: 636426397
This commit is contained in:
parent
1ffeafecc3
commit
37c2d9957e
@ -27,7 +27,7 @@ import androidx.media3.test.utils.DumpableMp4Box;
|
||||
import androidx.media3.test.utils.FakeExtractorOutput;
|
||||
import androidx.media3.test.utils.TestUtil;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -38,14 +38,26 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/** End to end instrumentation tests for {@link FragmentedMp4Muxer}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@RunWith(Parameterized.class)
|
||||
public class FragmentedMp4MuxerEndToEndAndroidTest {
|
||||
private static final String H264_WITH_PYRAMID_B_FRAMES_MP4 =
|
||||
"bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4";
|
||||
private static final String H265_HDR10_MP4 = "hdr10-720p.mp4";
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static ImmutableList<String> mediaSamples() {
|
||||
return ImmutableList.of(H264_WITH_PYRAMID_B_FRAMES_MP4, H265_HDR10_MP4);
|
||||
}
|
||||
|
||||
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Parameter public @MonotonicNonNull String inputFile;
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
private @MonotonicNonNull String outputPath;
|
||||
private @MonotonicNonNull FileOutputStream outputStream;
|
||||
@ -71,7 +83,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest {
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 100_000_000L,
|
||||
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||
feedInputDataToMuxer(context, fragmentedMp4Muxer, H265_HDR10_MP4);
|
||||
feedInputDataToMuxer(context, fragmentedMp4Muxer, checkNotNull(inputFile));
|
||||
} finally {
|
||||
if (fragmentedMp4Muxer != null) {
|
||||
fragmentedMp4Muxer.close();
|
||||
@ -84,7 +96,7 @@ public class FragmentedMp4MuxerEndToEndAndroidTest {
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
fakeExtractorOutput,
|
||||
AndroidMuxerTestUtil.getExpectedDumpFilePath(H265_HDR10_MP4 + "_fragmented"));
|
||||
AndroidMuxerTestUtil.getExpectedDumpFilePath(inputFile + "_fragmented"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -775,7 +775,7 @@ import java.util.Locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate sample composition time offsets (in timebase units).
|
||||
* Calculates sample composition time offsets (in timebase units).
|
||||
*
|
||||
* <p>The sample composition time offset gives offset between composition time (CT) and decoding
|
||||
* time (DT), such that {@code CT(n) = DT(n) + sample_offset(n)}.
|
||||
@ -785,7 +785,7 @@ import java.util.Locale;
|
||||
* @param videoUnitTimescale The timescale of the track.
|
||||
* @return A list of all the sample composition time offsets.
|
||||
*/
|
||||
private static List<Integer> calculateSampleCompositionTimeOffsets(
|
||||
public static List<Integer> calculateSampleCompositionTimeOffsets(
|
||||
List<BufferInfo> samplesInfo, List<Long> durationVu, int videoUnitTimescale) {
|
||||
List<Integer> compositionOffsets = new ArrayList<>(samplesInfo.size());
|
||||
if (samplesInfo.isEmpty()) {
|
||||
@ -998,8 +998,10 @@ import java.util.Locale;
|
||||
}
|
||||
|
||||
/** Returns a track fragment run (trun) box. */
|
||||
public static ByteBuffer trun(List<SampleMetadata> samplesMetadata, int dataOffset) {
|
||||
ByteBuffer contents = ByteBuffer.allocate(getTrunBoxContentSize(samplesMetadata.size()));
|
||||
public static ByteBuffer trun(
|
||||
List<SampleMetadata> samplesMetadata, int dataOffset, boolean hasBFrame) {
|
||||
ByteBuffer contents =
|
||||
ByteBuffer.allocate(getTrunBoxContentSize(samplesMetadata.size(), hasBFrame));
|
||||
|
||||
// 0x000001 data-offset-present.
|
||||
// 0x000100 sample-duration-present: indicates that each sample has its own duration, otherwise
|
||||
@ -1008,8 +1010,13 @@ import java.util.Locale;
|
||||
// default is used.
|
||||
// 0x000400 sample-flags-present: indicates that each sample has its own flags, otherwise the
|
||||
// default is used.
|
||||
// Version is 0x0.
|
||||
int versionAndFlags = 0x0 | 0x000001 | 0x000100 | 0x000200 | 0x000400;
|
||||
// 0x000800 sample-composition-time-offsets-present: indicates that each sample has its own
|
||||
// composition time offset, otherwise default is used.
|
||||
// Version (the most significant byte of versionAndFlags) is 0x1.
|
||||
int versionAndFlags = 0x1 << 24 | 0x000001 | 0x000100 | 0x000200 | 0x000400;
|
||||
if (hasBFrame) {
|
||||
versionAndFlags |= 0x000800;
|
||||
}
|
||||
contents.putInt(versionAndFlags);
|
||||
contents.putInt(samplesMetadata.size()); // An unsigned int(32)
|
||||
contents.putInt(dataOffset); // A signed int(32)
|
||||
@ -1021,16 +1028,19 @@ import java.util.Locale;
|
||||
(currentSampleMetadata.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0
|
||||
? TRUN_BOX_SYNC_SAMPLE_FLAGS
|
||||
: TRUN_BOX_NON_SYNC_SAMPLE_FLAGS);
|
||||
if (hasBFrame) {
|
||||
contents.putInt(currentSampleMetadata.compositionTimeOffsetVu);
|
||||
}
|
||||
}
|
||||
contents.flip();
|
||||
return BoxUtils.wrapIntoBox("trun", contents);
|
||||
}
|
||||
|
||||
/** Returns the size required for {@link #trun(List, int)} box content. */
|
||||
public static int getTrunBoxContentSize(int sampleCount) {
|
||||
/** Returns the size required for {@link #trun(List, int, boolean)} box content. */
|
||||
public static int getTrunBoxContentSize(int sampleCount, boolean hasBFrame) {
|
||||
int trunBoxFixedSize = 3 * BYTES_PER_INTEGER;
|
||||
// 3 int(32-bit) gets written for each sample.
|
||||
return trunBoxFixedSize + 3 * sampleCount * BYTES_PER_INTEGER;
|
||||
int intWrittenPerSample = hasBFrame ? 4 : 3;
|
||||
return trunBoxFixedSize + intWrittenPerSample * sampleCount * BYTES_PER_INTEGER;
|
||||
}
|
||||
|
||||
/** Returns a movie extends (mvex) box. */
|
||||
|
@ -29,7 +29,6 @@ import static java.lang.Math.min;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Util;
|
||||
@ -53,11 +52,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
public final long durationVu;
|
||||
public final int size;
|
||||
public final int flags;
|
||||
public final int compositionTimeOffsetVu;
|
||||
|
||||
public SampleMetadata(long durationsVu, int size, int flags) {
|
||||
public SampleMetadata(long durationsVu, int size, int flags, int compositionTimeOffsetVu) {
|
||||
this.durationVu = durationsVu;
|
||||
this.size = size;
|
||||
this.flags = flags;
|
||||
this.compositionTimeOffsetVu = compositionTimeOffsetVu;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +75,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
private boolean headerCreated;
|
||||
private long minInputPresentationTimeUs;
|
||||
private long maxTrackDurationUs;
|
||||
private long lastSamplePresentationTimeUs;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
@ -102,7 +102,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
this.fragmentDurationUs = fragmentDurationMs * 1_000;
|
||||
minInputPresentationTimeUs = Long.MAX_VALUE;
|
||||
currentFragmentSequenceNumber = 1;
|
||||
lastSamplePresentationTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
public TrackToken addTrack(int sortKey, Format format) {
|
||||
@ -118,9 +117,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
TrackToken token, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo)
|
||||
throws IOException {
|
||||
checkArgument(token instanceof Track);
|
||||
checkArgument(
|
||||
bufferInfo.presentationTimeUs > lastSamplePresentationTimeUs,
|
||||
"Out of order B-frames are not supported");
|
||||
if (!headerCreated) {
|
||||
createHeader();
|
||||
headerCreated = true;
|
||||
@ -130,7 +126,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
createFragment();
|
||||
}
|
||||
track.writeSampleData(byteBuffer, bufferInfo);
|
||||
lastSamplePresentationTimeUs = bufferInfo.presentationTimeUs;
|
||||
BufferInfo firstPendingSample = checkNotNull(track.pendingSamplesBufferInfo.peekFirst());
|
||||
BufferInfo lastPendingSample = checkNotNull(track.pendingSamplesBufferInfo.peekLast());
|
||||
minInputPresentationTimeUs =
|
||||
@ -163,7 +158,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
trafBoxes.add(
|
||||
Boxes.traf(
|
||||
Boxes.tfhd(currentTrackInfo.trackId, /* baseDataOffset= */ moofBoxStartPosition),
|
||||
Boxes.trun(currentTrackInfo.pendingSamplesMetadata, dataOffset)));
|
||||
Boxes.trun(
|
||||
currentTrackInfo.pendingSamplesMetadata,
|
||||
dataOffset,
|
||||
currentTrackInfo.hasBFrame)));
|
||||
dataOffset += currentTrackInfo.totalSamplesSize;
|
||||
}
|
||||
return trafBoxes.build();
|
||||
@ -189,7 +187,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
for (int i = 0; i < trackInfos.size(); i++) {
|
||||
ProcessedTrackInfo trackInfo = trackInfos.get(i);
|
||||
int trunBoxSize =
|
||||
trunBoxHeaderFixedSize + getTrunBoxContentSize(trackInfo.pendingSamplesMetadata.size());
|
||||
trunBoxHeaderFixedSize
|
||||
+ getTrunBoxContentSize(trackInfo.pendingSamplesMetadata.size(), trackInfo.hasBFrame);
|
||||
trafBoxesSize += trafBoxHeaderSize + tfhdBoxSize + trunBoxSize;
|
||||
}
|
||||
|
||||
@ -319,6 +318,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
track.pendingSamplesBufferInfo.clear();
|
||||
}
|
||||
|
||||
boolean hasBFrame = false;
|
||||
ImmutableList<BufferInfo> pendingSamplesBufferInfo = pendingSamplesBufferInfoBuilder.build();
|
||||
List<Long> sampleDurations =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
@ -329,6 +329,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
track.videoUnitTimebase(),
|
||||
Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
|
||||
|
||||
List<Integer> sampleCompositionTimeOffsets =
|
||||
Boxes.calculateSampleCompositionTimeOffsets(
|
||||
pendingSamplesBufferInfo, sampleDurations, track.videoUnitTimebase());
|
||||
if (!sampleCompositionTimeOffsets.isEmpty()) {
|
||||
hasBFrame = true;
|
||||
}
|
||||
|
||||
ImmutableList.Builder<SampleMetadata> pendingSamplesMetadata = new ImmutableList.Builder<>();
|
||||
int totalSamplesSize = 0;
|
||||
for (int i = 0; i < pendingSamplesBufferInfo.size(); i++) {
|
||||
@ -337,12 +344,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
new SampleMetadata(
|
||||
sampleDurations.get(i),
|
||||
pendingSamplesBufferInfo.get(i).size,
|
||||
pendingSamplesBufferInfo.get(i).flags));
|
||||
pendingSamplesBufferInfo.get(i).flags,
|
||||
hasBFrame ? sampleCompositionTimeOffsets.get(i) : 0));
|
||||
}
|
||||
|
||||
return new ProcessedTrackInfo(
|
||||
trackId,
|
||||
totalSamplesSize,
|
||||
hasBFrame,
|
||||
pendingSamplesByteBuffer.build(),
|
||||
pendingSamplesMetadata.build());
|
||||
}
|
||||
@ -350,16 +359,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
private static class ProcessedTrackInfo {
|
||||
public final int trackId;
|
||||
public final int totalSamplesSize;
|
||||
public final boolean hasBFrame;
|
||||
public final ImmutableList<ByteBuffer> pendingSamplesByteBuffer;
|
||||
public final ImmutableList<SampleMetadata> pendingSamplesMetadata;
|
||||
|
||||
public ProcessedTrackInfo(
|
||||
int trackId,
|
||||
int totalSamplesSize,
|
||||
boolean hasBFrame,
|
||||
ImmutableList<ByteBuffer> pendingSamplesByteBuffer,
|
||||
ImmutableList<SampleMetadata> pendingSamplesMetadata) {
|
||||
this.trackId = trackId;
|
||||
this.totalSamplesSize = totalSamplesSize;
|
||||
this.hasBFrame = hasBFrame;
|
||||
this.pendingSamplesByteBuffer = pendingSamplesByteBuffer;
|
||||
this.pendingSamplesMetadata = pendingSamplesMetadata;
|
||||
}
|
||||
|
@ -681,16 +681,39 @@ public class BoxesTest {
|
||||
new SampleMetadata(
|
||||
/* durationsVu= */ 2_000L,
|
||||
/* size= */ 5_000,
|
||||
/* flags= */ i == 0 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0));
|
||||
/* flags= */ i == 0 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0,
|
||||
/* compositionTimeOffsetVu= */ 0));
|
||||
}
|
||||
|
||||
ByteBuffer trunBox = Boxes.trun(samplesMetadata, /* dataOffset= */ 1_000);
|
||||
ByteBuffer trunBox =
|
||||
Boxes.trun(samplesMetadata, /* dataOffset= */ 1_000, /* hasBFrame= */ false);
|
||||
|
||||
DumpableMp4Box dumpableBox = new DumpableMp4Box(trunBox);
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("trun_box"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTrunBox_withBFrame_matchesExpected() throws IOException {
|
||||
int sampleCount = 5;
|
||||
List<SampleMetadata> samplesMetadata = new ArrayList<>(sampleCount);
|
||||
for (int i = 0; i < sampleCount; i++) {
|
||||
samplesMetadata.add(
|
||||
new SampleMetadata(
|
||||
/* durationsVu= */ 2_000L,
|
||||
/* size= */ 5_000,
|
||||
/* flags= */ i == 0 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0,
|
||||
/* compositionTimeOffsetVu= */ 100));
|
||||
}
|
||||
|
||||
ByteBuffer trunBox =
|
||||
Boxes.trun(samplesMetadata, /* dataOffset= */ 1_000, /* hasBFrame= */ true);
|
||||
|
||||
DumpableMp4Box dumpableBox = new DumpableMp4Box(trunBox);
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("trun_box_with_b_frame"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTrexBox_matchesExpected() throws IOException {
|
||||
ByteBuffer trexBox = Boxes.trex(/* trackId= */ 2);
|
||||
|
@ -0,0 +1,501 @@
|
||||
seekMap:
|
||||
isSeekable = false
|
||||
duration = UNSET TIME
|
||||
getPosition(0) = [[timeUs=0, position=695]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 406132
|
||||
sample count = 120
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.64001F
|
||||
width = 800
|
||||
height = 640
|
||||
colorInfo:
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
initializationData:
|
||||
data = length 33, hash A51E6AF9
|
||||
data = length 9, hash FBAE9B2D
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 74666, hash 9AF2BE5A
|
||||
sample 1:
|
||||
time = 133322
|
||||
flags = 0
|
||||
data = length 3689, hash 23BF8CA2
|
||||
sample 2:
|
||||
time = 66655
|
||||
flags = 0
|
||||
data = length 1319, hash 7E6541DB
|
||||
sample 3:
|
||||
time = 33322
|
||||
flags = 0
|
||||
data = length 466, hash ECD93C68
|
||||
sample 4:
|
||||
time = 100000
|
||||
flags = 0
|
||||
data = length 785, hash 3E824588
|
||||
sample 5:
|
||||
time = 266655
|
||||
flags = 0
|
||||
data = length 23472, hash 4A790E9B
|
||||
sample 6:
|
||||
time = 200000
|
||||
flags = 0
|
||||
data = length 169, hash B408CF0C
|
||||
sample 7:
|
||||
time = 166655
|
||||
flags = 0
|
||||
data = length 1008, hash 558016DF
|
||||
sample 8:
|
||||
time = 233322
|
||||
flags = 0
|
||||
data = length 60, hash A5220F0F
|
||||
sample 9:
|
||||
time = 400000
|
||||
flags = 0
|
||||
data = length 718, hash 56CA9233
|
||||
sample 10:
|
||||
time = 333322
|
||||
flags = 0
|
||||
data = length 277, hash F27B77B0
|
||||
sample 11:
|
||||
time = 300000
|
||||
flags = 0
|
||||
data = length 204, hash 451A7EF8
|
||||
sample 12:
|
||||
time = 366655
|
||||
flags = 0
|
||||
data = length 100, hash 72CCF451
|
||||
sample 13:
|
||||
time = 533322
|
||||
flags = 0
|
||||
data = length 2305, hash EE8EAD07
|
||||
sample 14:
|
||||
time = 466655
|
||||
flags = 0
|
||||
data = length 313, hash 23FD6C99
|
||||
sample 15:
|
||||
time = 433322
|
||||
flags = 0
|
||||
data = length 161, hash F9082751
|
||||
sample 16:
|
||||
time = 500000
|
||||
flags = 0
|
||||
data = length 512, hash F0317F7B
|
||||
sample 17:
|
||||
time = 666655
|
||||
flags = 0
|
||||
data = length 4386, hash 536E4530
|
||||
sample 18:
|
||||
time = 600000
|
||||
flags = 0
|
||||
data = length 2418, hash 3CA55886
|
||||
sample 19:
|
||||
time = 566655
|
||||
flags = 0
|
||||
data = length 818, hash CF732FE9
|
||||
sample 20:
|
||||
time = 633322
|
||||
flags = 0
|
||||
data = length 931, hash 9307BF9B
|
||||
sample 21:
|
||||
time = 800000
|
||||
flags = 0
|
||||
data = length 5881, hash 95D65FB
|
||||
sample 22:
|
||||
time = 733322
|
||||
flags = 0
|
||||
data = length 3241, hash C3722BD2
|
||||
sample 23:
|
||||
time = 700000
|
||||
flags = 0
|
||||
data = length 1957, hash 54FE72A0
|
||||
sample 24:
|
||||
time = 766655
|
||||
flags = 0
|
||||
data = length 943, hash 467A1DB1
|
||||
sample 25:
|
||||
time = 933322
|
||||
flags = 0
|
||||
data = length 7927, hash 20EB2632
|
||||
sample 26:
|
||||
time = 866655
|
||||
flags = 0
|
||||
data = length 3313, hash B854BF3E
|
||||
sample 27:
|
||||
time = 833322
|
||||
flags = 0
|
||||
data = length 2729, hash FC827FEE
|
||||
sample 28:
|
||||
time = 900000
|
||||
flags = 0
|
||||
data = length 847, hash 739EFD75
|
||||
sample 29:
|
||||
time = 966655
|
||||
flags = 0
|
||||
data = length 1780, hash 8C1AF0B1
|
||||
sample 30:
|
||||
time = 1000000
|
||||
flags = 1
|
||||
data = length 29827, hash B287A700
|
||||
sample 31:
|
||||
time = 1133322
|
||||
flags = 0
|
||||
data = length 2572, hash AB201EC8
|
||||
sample 32:
|
||||
time = 1066655
|
||||
flags = 0
|
||||
data = length 980, hash BD0ADFF1
|
||||
sample 33:
|
||||
time = 1033322
|
||||
flags = 0
|
||||
data = length 343, hash 645A3973
|
||||
sample 34:
|
||||
time = 1100000
|
||||
flags = 0
|
||||
data = length 476, hash 89BF903C
|
||||
sample 35:
|
||||
time = 1266655
|
||||
flags = 0
|
||||
data = length 9908, hash BDFEA8A4
|
||||
sample 36:
|
||||
time = 1200000
|
||||
flags = 0
|
||||
data = length 2422, hash 863FCD89
|
||||
sample 37:
|
||||
time = 1166655
|
||||
flags = 0
|
||||
data = length 718, hash E21DB793
|
||||
sample 38:
|
||||
time = 1233322
|
||||
flags = 0
|
||||
data = length 475, hash 6E2B14C6
|
||||
sample 39:
|
||||
time = 1400000
|
||||
flags = 0
|
||||
data = length 3084, hash 92862A1A
|
||||
sample 40:
|
||||
time = 1333322
|
||||
flags = 0
|
||||
data = length 825, hash 978654C8
|
||||
sample 41:
|
||||
time = 1300000
|
||||
flags = 0
|
||||
data = length 705, hash 28D04FCA
|
||||
sample 42:
|
||||
time = 1366655
|
||||
flags = 0
|
||||
data = length 335, hash D736EAC1
|
||||
sample 43:
|
||||
time = 1533322
|
||||
flags = 0
|
||||
data = length 3295, hash 2FCFA14A
|
||||
sample 44:
|
||||
time = 1466655
|
||||
flags = 0
|
||||
data = length 897, hash 6C76AFF1
|
||||
sample 45:
|
||||
time = 1433322
|
||||
flags = 0
|
||||
data = length 499, hash DDBE39E
|
||||
sample 46:
|
||||
time = 1500000
|
||||
flags = 0
|
||||
data = length 565, hash D269272C
|
||||
sample 47:
|
||||
time = 1666655
|
||||
flags = 0
|
||||
data = length 1958, hash 4A334D4E
|
||||
sample 48:
|
||||
time = 1600000
|
||||
flags = 0
|
||||
data = length 871, hash 21A0191A
|
||||
sample 49:
|
||||
time = 1566655
|
||||
flags = 0
|
||||
data = length 363, hash 376C3CBE
|
||||
sample 50:
|
||||
time = 1633322
|
||||
flags = 0
|
||||
data = length 398, hash BA958C19
|
||||
sample 51:
|
||||
time = 1800000
|
||||
flags = 0
|
||||
data = length 5413, hash 83EA9FBA
|
||||
sample 52:
|
||||
time = 1733322
|
||||
flags = 0
|
||||
data = length 1124, hash D7ADA732
|
||||
sample 53:
|
||||
time = 1700000
|
||||
flags = 0
|
||||
data = length 579, hash B6D6A34F
|
||||
sample 54:
|
||||
time = 1766655
|
||||
flags = 0
|
||||
data = length 1206, hash 1C5174A3
|
||||
sample 55:
|
||||
time = 1933322
|
||||
flags = 0
|
||||
data = length 5172, hash C4EBB198
|
||||
sample 56:
|
||||
time = 1866655
|
||||
flags = 0
|
||||
data = length 2045, hash 81261E50
|
||||
sample 57:
|
||||
time = 1833322
|
||||
flags = 0
|
||||
data = length 915, hash FFEDB29E
|
||||
sample 58:
|
||||
time = 1900000
|
||||
flags = 0
|
||||
data = length 1513, hash C03809BF
|
||||
sample 59:
|
||||
time = 1966655
|
||||
flags = 0
|
||||
data = length 4744, hash D0E55AF1
|
||||
sample 60:
|
||||
time = 2000000
|
||||
flags = 1
|
||||
data = length 30426, hash E5A29561
|
||||
sample 61:
|
||||
time = 2133322
|
||||
flags = 0
|
||||
data = length 7531, hash 756AE4D1
|
||||
sample 62:
|
||||
time = 2066655
|
||||
flags = 0
|
||||
data = length 2740, hash 669E4DF1
|
||||
sample 63:
|
||||
time = 2033322
|
||||
flags = 0
|
||||
data = length 1829, hash 66A7C400
|
||||
sample 64:
|
||||
time = 2100000
|
||||
flags = 0
|
||||
data = length 1423, hash DD6288B3
|
||||
sample 65:
|
||||
time = 2266655
|
||||
flags = 0
|
||||
data = length 12033, hash 244DD978
|
||||
sample 66:
|
||||
time = 2200000
|
||||
flags = 0
|
||||
data = length 2481, hash 9302A030
|
||||
sample 67:
|
||||
time = 2166655
|
||||
flags = 0
|
||||
data = length 1770, hash 86E54271
|
||||
sample 68:
|
||||
time = 2233322
|
||||
flags = 0
|
||||
data = length 636, hash B0BB7A9D
|
||||
sample 69:
|
||||
time = 2400000
|
||||
flags = 0
|
||||
data = length 5120, hash 8381F6ED
|
||||
sample 70:
|
||||
time = 2333322
|
||||
flags = 0
|
||||
data = length 1610, hash E9A0711D
|
||||
sample 71:
|
||||
time = 2300000
|
||||
flags = 0
|
||||
data = length 961, hash 494E3770
|
||||
sample 72:
|
||||
time = 2366655
|
||||
flags = 0
|
||||
data = length 1402, hash 3D40A6D1
|
||||
sample 73:
|
||||
time = 2533322
|
||||
flags = 0
|
||||
data = length 8006, hash A8C425BC
|
||||
sample 74:
|
||||
time = 2466655
|
||||
flags = 0
|
||||
data = length 4620, hash 18719317
|
||||
sample 75:
|
||||
time = 2433322
|
||||
flags = 0
|
||||
data = length 2507, hash 104771A0
|
||||
sample 76:
|
||||
time = 2500000
|
||||
flags = 0
|
||||
data = length 3970, hash B52DD9E
|
||||
sample 77:
|
||||
time = 2666655
|
||||
flags = 0
|
||||
data = length 6556, hash 173F0724
|
||||
sample 78:
|
||||
time = 2600000
|
||||
flags = 0
|
||||
data = length 1824, hash 8BB687AC
|
||||
sample 79:
|
||||
time = 2566655
|
||||
flags = 0
|
||||
data = length 1851, hash 29CD7E58
|
||||
sample 80:
|
||||
time = 2633322
|
||||
flags = 0
|
||||
data = length 731, hash 4E6BD69C
|
||||
sample 81:
|
||||
time = 2800000
|
||||
flags = 0
|
||||
data = length 3255, hash FCDDDFFC
|
||||
sample 82:
|
||||
time = 2733322
|
||||
flags = 0
|
||||
data = length 1118, hash 77E855CA
|
||||
sample 83:
|
||||
time = 2700000
|
||||
flags = 0
|
||||
data = length 413, hash E83C433F
|
||||
sample 84:
|
||||
time = 2766655
|
||||
flags = 0
|
||||
data = length 514, hash 9ED8EF4B
|
||||
sample 85:
|
||||
time = 2933322
|
||||
flags = 0
|
||||
data = length 2919, hash 93BC27A8
|
||||
sample 86:
|
||||
time = 2866655
|
||||
flags = 0
|
||||
data = length 833, hash 213B7EAB
|
||||
sample 87:
|
||||
time = 2833322
|
||||
flags = 0
|
||||
data = length 574, hash 554020E9
|
||||
sample 88:
|
||||
time = 2900000
|
||||
flags = 0
|
||||
data = length 431, hash 6C3E69F6
|
||||
sample 89:
|
||||
time = 2966655
|
||||
flags = 0
|
||||
data = length 2242, hash 8EC9C1D6
|
||||
sample 90:
|
||||
time = 2999988
|
||||
flags = 1
|
||||
data = length 33075, hash C0FCCB84
|
||||
sample 91:
|
||||
time = 3133311
|
||||
flags = 0
|
||||
data = length 3349, hash ADE2C1A1
|
||||
sample 92:
|
||||
time = 3066644
|
||||
flags = 0
|
||||
data = length 890, hash C384FE6A
|
||||
sample 93:
|
||||
time = 3033311
|
||||
flags = 0
|
||||
data = length 822, hash 2897A348
|
||||
sample 94:
|
||||
time = 3099988
|
||||
flags = 0
|
||||
data = length 347, hash 968D3ED1
|
||||
sample 95:
|
||||
time = 3266644
|
||||
flags = 0
|
||||
data = length 4885, hash 57E006DF
|
||||
sample 96:
|
||||
time = 3199988
|
||||
flags = 0
|
||||
data = length 1714, hash 10B49A30
|
||||
sample 97:
|
||||
time = 3166644
|
||||
flags = 0
|
||||
data = length 502, hash B0FDBCA
|
||||
sample 98:
|
||||
time = 3233311
|
||||
flags = 0
|
||||
data = length 378, hash AFCB47B5
|
||||
sample 99:
|
||||
time = 3399988
|
||||
flags = 0
|
||||
data = length 2216, hash 102B8AD4
|
||||
sample 100:
|
||||
time = 3333311
|
||||
flags = 0
|
||||
data = length 785, hash 10C1C847
|
||||
sample 101:
|
||||
time = 3299988
|
||||
flags = 0
|
||||
data = length 499, hash F11DD54
|
||||
sample 102:
|
||||
time = 3366644
|
||||
flags = 0
|
||||
data = length 352, hash 32BD14FA
|
||||
sample 103:
|
||||
time = 3533311
|
||||
flags = 0
|
||||
data = length 2525, hash F426C83B
|
||||
sample 104:
|
||||
time = 3466644
|
||||
flags = 0
|
||||
data = length 732, hash 6BD8DF40
|
||||
sample 105:
|
||||
time = 3433311
|
||||
flags = 0
|
||||
data = length 466, hash F2253523
|
||||
sample 106:
|
||||
time = 3499988
|
||||
flags = 0
|
||||
data = length 519, hash 457EB20F
|
||||
sample 107:
|
||||
time = 3666644
|
||||
flags = 0
|
||||
data = length 1205, hash A8894214
|
||||
sample 108:
|
||||
time = 3599988
|
||||
flags = 0
|
||||
data = length 483, hash 3C3E6CBA
|
||||
sample 109:
|
||||
time = 3566644
|
||||
flags = 0
|
||||
data = length 157, hash E3D5E025
|
||||
sample 110:
|
||||
time = 3633311
|
||||
flags = 0
|
||||
data = length 237, hash A7217EC5
|
||||
sample 111:
|
||||
time = 3799988
|
||||
flags = 0
|
||||
data = length 1330, hash 6CDE1190
|
||||
sample 112:
|
||||
time = 3733311
|
||||
flags = 0
|
||||
data = length 475, hash B9925752
|
||||
sample 113:
|
||||
time = 3699988
|
||||
flags = 0
|
||||
data = length 392, hash 2709B2E0
|
||||
sample 114:
|
||||
time = 3766644
|
||||
flags = 0
|
||||
data = length 258, hash 900651AF
|
||||
sample 115:
|
||||
time = 3933311
|
||||
flags = 0
|
||||
data = length 1130, hash 9C8E9289
|
||||
sample 116:
|
||||
time = 3866644
|
||||
flags = 0
|
||||
data = length 581, hash 79FAD374
|
||||
sample 117:
|
||||
time = 3833311
|
||||
flags = 0
|
||||
data = length 285, hash B460CF8A
|
||||
sample 118:
|
||||
time = 3899988
|
||||
flags = 0
|
||||
data = length 277, hash A40F948C
|
||||
sample 119:
|
||||
time = 3966644
|
||||
flags = 0
|
||||
data = length 1318, hash 9A6E5D81
|
||||
tracksEnded = true
|
@ -65,12 +65,12 @@ moof (2876 bytes):
|
||||
tfhd (24 bytes):
|
||||
Data = length 16, hash D37153D4
|
||||
trun (1100 bytes):
|
||||
Data = length 1092, hash BA1962E9
|
||||
Data = length 1092, hash 7B5FDF48
|
||||
traf (1720 bytes):
|
||||
tfhd (24 bytes):
|
||||
Data = length 16, hash 67B5C2D5
|
||||
trun (1688 bytes):
|
||||
Data = length 1680, hash 2EDF9B97
|
||||
Data = length 1680, hash 51194976
|
||||
mdat (5712387 bytes):
|
||||
Data = length 5712379, hash 86B2819D
|
||||
moof (1244 bytes):
|
||||
@ -80,11 +80,11 @@ moof (1244 bytes):
|
||||
tfhd (24 bytes):
|
||||
Data = length 16, hash D372A134
|
||||
trun (464 bytes):
|
||||
Data = length 456, hash E01BEFF7
|
||||
Data = length 456, hash AB9FD4D6
|
||||
traf (724 bytes):
|
||||
tfhd (24 bytes):
|
||||
Data = length 16, hash 67B71035
|
||||
trun (692 bytes):
|
||||
Data = length 684, hash 73BBFD29
|
||||
Data = length 684, hash 121FB688
|
||||
mdat (2364921 bytes):
|
||||
Data = length 2364913, hash D363A845
|
||||
|
@ -1,2 +1,2 @@
|
||||
trun (80 bytes):
|
||||
Data = length 72, hash 516DBD9
|
||||
Data = length 72, hash 876190B8
|
||||
|
@ -0,0 +1,2 @@
|
||||
trun (100 bytes):
|
||||
Data = length 92, hash 995185A4
|
Loading…
x
Reference in New Issue
Block a user