From 37c2d9957e8afefce749cef6b3f9cad2c4d98385 Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 22 May 2024 23:04:46 -0700 Subject: [PATCH] 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 --- ...FragmentedMp4MuxerEndToEndAndroidTest.java | 20 +- .../java/androidx/media3/muxer/Boxes.java | 30 +- .../media3/muxer/FragmentedMp4Writer.java | 34 +- .../java/androidx/media3/muxer/BoxesTest.java | 27 +- ...s_30fps_avc_pyramid_3b.mp4_fragmented.dump | 501 ++++++++++++++++++ ...r10-720p.mp4_fragmented_box_structure.dump | 8 +- .../src/test/assets/muxerdumps/trun_box.dump | 2 +- .../muxerdumps/trun_box_with_b_frame.dump | 2 + 8 files changed, 592 insertions(+), 32 deletions(-) create mode 100644 libraries/test_data/src/test/assets/muxerdumps/bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4_fragmented.dump create mode 100644 libraries/test_data/src/test/assets/muxerdumps/trun_box_with_b_frame.dump diff --git a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java index b203748cb1..bdccfd0d0a 100644 --- a/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java +++ b/libraries/muxer/src/androidTest/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndAndroidTest.java @@ -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 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 diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java index cb8df93558..10851ca00d 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java @@ -775,7 +775,7 @@ import java.util.Locale; } /** - * Calculate sample composition time offsets (in timebase units). + * Calculates sample composition time offsets (in timebase units). * *

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 calculateSampleCompositionTimeOffsets( + public static List calculateSampleCompositionTimeOffsets( List samplesInfo, List durationVu, int videoUnitTimescale) { List 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 samplesMetadata, int dataOffset) { - ByteBuffer contents = ByteBuffer.allocate(getTrunBoxContentSize(samplesMetadata.size())); + public static ByteBuffer trun( + List 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. */ diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java index 5ab40933db..00b4a90adf 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java @@ -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 pendingSamplesBufferInfo = pendingSamplesBufferInfoBuilder.build(); List 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 sampleCompositionTimeOffsets = + Boxes.calculateSampleCompositionTimeOffsets( + pendingSamplesBufferInfo, sampleDurations, track.videoUnitTimebase()); + if (!sampleCompositionTimeOffsets.isEmpty()) { + hasBFrame = true; + } + ImmutableList.Builder 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 pendingSamplesByteBuffer; public final ImmutableList pendingSamplesMetadata; public ProcessedTrackInfo( int trackId, int totalSamplesSize, + boolean hasBFrame, ImmutableList pendingSamplesByteBuffer, ImmutableList pendingSamplesMetadata) { this.trackId = trackId; this.totalSamplesSize = totalSamplesSize; + this.hasBFrame = hasBFrame; this.pendingSamplesByteBuffer = pendingSamplesByteBuffer; this.pendingSamplesMetadata = pendingSamplesMetadata; } diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java index 80517dce32..a6710fb37b 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java @@ -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 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); diff --git a/libraries/test_data/src/test/assets/muxerdumps/bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4_fragmented.dump b/libraries/test_data/src/test/assets/muxerdumps/bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4_fragmented.dump new file mode 100644 index 0000000000..7f979888cf --- /dev/null +++ b/libraries/test_data/src/test/assets/muxerdumps/bbb_800x640_768kbps_30fps_avc_pyramid_3b.mp4_fragmented.dump @@ -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 diff --git a/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump b/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump index e2baf278d6..bf4ec72b70 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/hdr10-720p.mp4_fragmented_box_structure.dump @@ -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 diff --git a/libraries/test_data/src/test/assets/muxerdumps/trun_box.dump b/libraries/test_data/src/test/assets/muxerdumps/trun_box.dump index 3cc7d58989..0391e0f16d 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/trun_box.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/trun_box.dump @@ -1,2 +1,2 @@ trun (80 bytes): - Data = length 72, hash 516DBD9 + Data = length 72, hash 876190B8 diff --git a/libraries/test_data/src/test/assets/muxerdumps/trun_box_with_b_frame.dump b/libraries/test_data/src/test/assets/muxerdumps/trun_box_with_b_frame.dump new file mode 100644 index 0000000000..9fa8f55143 --- /dev/null +++ b/libraries/test_data/src/test/assets/muxerdumps/trun_box_with_b_frame.dump @@ -0,0 +1,2 @@ +trun (100 bytes): + Data = length 92, hash 995185A4