From ede3893a3ad08aae4a734f7d95d2cae4c3541ed2 Mon Sep 17 00:00:00 2001 From: ybai001 Date: Thu, 13 Aug 2026 17:09:50 +0800 Subject: [PATCH] Add dby1 compatible brand to the ftyp box if muxing Dolby Content This updates both regular MP4 and fragmented MP4 writer paths so Dolby outputs advertise the expected compatible brand in the container header. --- .../java/androidx/media3/muxer/Boxes.java | 19 ++- .../media3/muxer/FragmentedMp4Writer.java | 2 +- .../java/androidx/media3/muxer/Mp4Muxer.java | 10 +- .../java/androidx/media3/muxer/Mp4Writer.java | 4 +- .../java/androidx/media3/muxer/MuxerUtil.java | 31 ++++ .../java/androidx/media3/muxer/BoxesTest.java | 33 +++- .../muxer/FragmentedMp4MuxerEndToEndTest.java | 27 ++++ .../media3/muxer/Mp4MuxerEndToEndTest.java | 22 +++ .../androidx/media3/muxer/MuxerTestUtil.java | 19 +++ .../androidx/media3/muxer/MuxerUtilTest.java | 144 ++++++++++++++++++ .../muxerdumps/mp4/sample_edit_list.mp4.dump | 8 +- .../mp4/sample_edit_list.mp4_fragmented.dump | 2 +- ...ideo_dovi_1920x1080_60fps_dvav_09.mp4.dump | 8 +- ...920x1080_60fps_dvav_09.mp4_fragmented.dump | 2 +- 14 files changed, 311 insertions(+), 20 deletions(-) create mode 100644 libraries/muxer/src/test/java/androidx/media3/muxer/MuxerUtilTest.java 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 a62a98e89f2..f0b7cc0e2e1 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Boxes.java @@ -1288,8 +1288,13 @@ public static ByteBuffer stbl(ByteBuffer... subBoxes) { return BoxUtils.wrapBoxesIntoBox("stbl", Arrays.asList(subBoxes)); } - /** Creates the ftyp box. */ - public static ByteBuffer ftyp() { + /** + * Creates the ftyp box. + * + * @param additionalCompatibleBrands Additional compatible brands to declare, beyond the default + * set ({@code isom}, {@code iso2}, {@code mp41}). + */ + /* package */ static ByteBuffer ftyp(List additionalCompatibleBrands) { List boxBytes = new ArrayList<>(); String majorVersion = "isom"; @@ -1301,9 +1306,15 @@ public static ByteBuffer ftyp() { minorBytes.flip(); boxBytes.add(minorBytes); - String[] compatibleBrands = {"isom", "iso2", "mp41"}; + List compatibleBrands = new ArrayList<>(Arrays.asList("isom", "iso2", "mp41")); + compatibleBrands.addAll(additionalCompatibleBrands); for (String compatibleBrand : compatibleBrands) { - boxBytes.add(ByteBuffer.wrap(Util.getUtf8Bytes(compatibleBrand))); + byte[] compatibleBrandBytes = Util.getUtf8Bytes(compatibleBrand); + checkArgument( + compatibleBrandBytes.length == 4, + "Compatible brand must be 4 bytes: %s", + compatibleBrand); + boxBytes.add(ByteBuffer.wrap(compatibleBrandBytes)); } return BoxUtils.wrapBoxesIntoBox("ftyp", boxBytes); 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 0721bce33c7..81e0b60dba2 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/FragmentedMp4Writer.java @@ -255,7 +255,7 @@ private static int calculateMoofBoxSize(List trackInfos) { } private void createHeader() throws IOException { - outputChannel.write(Boxes.ftyp()); + outputChannel.write(Boxes.ftyp(MuxerUtil.getFtypCompatibleBrands(tracks))); outputChannel.write( Boxes.moov( tracks, metadataCollector, /* isFragmentedMp4= */ true, lastSampleDurationBehavior)); diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java index 24929e21767..b9f204b2d65 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Muxer.java @@ -484,7 +484,10 @@ private Mp4Muxer( * {@inheritDoc} * *

Tracks can be added at any point before the muxer is closed, even after writing samples to - * other tracks. + * other tracks. Note that a track requiring an additional {@code ftyp} compatible brand (for + * example a {@link MimeTypes#VIDEO_DOLBY_VISION} track, which requires the {@code dby1} brand) + * that is added after samples have already been written to another track will not retroactively + * update the {@code ftyp} box. * *

The order of tracks remains same in which they are added. * @@ -509,7 +512,10 @@ public int addTrack(Format format) throws MuxerException { * Adds a track of the given media format. * *

Tracks can be added at any point before the muxer is closed, even after writing samples to - * other tracks. + * other tracks. Note that a track requiring an additional {@code ftyp} compatible brand (for + * example a {@link MimeTypes#VIDEO_DOLBY_VISION} track, which requires the {@code dby1} brand) + * that is added after samples have already been written to another track will not retroactively + * update the {@code ftyp} box. * *

The final order of tracks is determined by the provided sort key. Tracks with a lower sort * key will be written before tracks with a higher sort key. Ordering between tracks with the same diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java index dedd5be4329..4a825ea09c9 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/Mp4Writer.java @@ -231,7 +231,7 @@ private void writeAxteBox() throws IOException { private ByteBuffer getAxteBox() { // The axte box will have one ftyp and one moov box. - ByteBuffer ftypBox = Boxes.ftyp(); + ByteBuffer ftypBox = Boxes.ftyp(MuxerUtil.getFtypCompatibleBrands(auxiliaryTracks)); MetadataCollector auxiliaryTracksMetadataCollector = new MetadataCollector(); populateAuxiliaryTracksMetadata( auxiliaryTracksMetadataCollector, @@ -314,7 +314,7 @@ public void finalizeMoovBox() throws IOException { private void writeHeader() throws IOException { muxerOutput.setPosition(0L); - muxerOutput.write(Boxes.ftyp()); + muxerOutput.write(Boxes.ftyp(MuxerUtil.getFtypCompatibleBrands(tracks))); if (freeSpaceAfterFtypInBytes > 0) { muxerOutput.write( diff --git a/libraries/muxer/src/main/java/androidx/media3/muxer/MuxerUtil.java b/libraries/muxer/src/main/java/androidx/media3/muxer/MuxerUtil.java index 0c8882e63fb..0ecd8da44ea 100644 --- a/libraries/muxer/src/main/java/androidx/media3/muxer/MuxerUtil.java +++ b/libraries/muxer/src/main/java/androidx/media3/muxer/MuxerUtil.java @@ -34,6 +34,8 @@ import androidx.media3.container.Mp4OrientationData; import androidx.media3.container.Mp4TimestampData; import androidx.media3.container.XmpData; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Longs; import java.io.FileInputStream; import java.io.IOException; @@ -43,6 +45,7 @@ import java.nio.channels.WritableByteChannel; import java.util.List; import java.util.Locale; +import java.util.Objects; /** Utility methods for muxer. */ @UnstableApi @@ -147,6 +150,34 @@ public static void createMotionPhotoFromJpegImageAndBmffVideo( || format.auxiliaryTrackType == C.AUXILIARY_TRACK_TYPE_DEPTH_METADATA); } + /** + * Returns the additional ftyp compatible brands that should be declared for the given tracks. + */ + /* package */ static ImmutableList getFtypCompatibleBrands(List tracks) { + ImmutableSet.Builder compatibleBrands = new ImmutableSet.Builder<>(); + for (int i = 0; i < tracks.size(); i++) { + if (isDolbyTrack(tracks.get(i).format)) { + compatibleBrands.add("dby1"); + } + } + return compatibleBrands.build().asList(); + } + + /** + * Returns whether the given {@linkplain Format track format} is a Dolby format (Dolby Vision + * video, or Dolby AC-3, EAC3, EAC3-JOC, AC-4 or TrueHD audio) that requires the {@code dby1} + * compatible brand in the ftyp box. + */ + private static boolean isDolbyTrack(Format format) { + String sampleMimeType = format.sampleMimeType; + return Objects.equals(sampleMimeType, MimeTypes.VIDEO_DOLBY_VISION) + || Objects.equals(sampleMimeType, MimeTypes.AUDIO_AC3) + || Objects.equals(sampleMimeType, MimeTypes.AUDIO_AC4) + || Objects.equals(sampleMimeType, MimeTypes.AUDIO_E_AC3) + || Objects.equals(sampleMimeType, MimeTypes.AUDIO_E_AC3_JOC) + || Objects.equals(sampleMimeType, MimeTypes.AUDIO_TRUEHD); + } + /** Returns a {@link MdtaMetadataEntry} for the auxiliary tracks offset metadata. */ /* package */ static MdtaMetadataEntry getAuxiliaryTracksOffsetMetadata(long offset) { return new MdtaMetadataEntry( 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 14e6d28381c..4cb4cd32604 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/BoxesTest.java @@ -950,13 +950,44 @@ public void createStssBox_matchesExpected() throws IOException { @Test public void createFtypBox_matchesExpected() throws IOException { - ByteBuffer ftypBox = Boxes.ftyp(); + ByteBuffer ftypBox = Boxes.ftyp(/* additionalCompatibleBrands= */ ImmutableList.of()); DumpableMp4Box dumpableBox = new DumpableMp4Box(ftypBox); DumpFileAsserts.assertOutput( context, dumpableBox, MuxerTestUtil.getExpectedMp4DumpFilePath("ftyp_box")); } + @Test + public void createFtypBox_withInvalidCompatibleBrandLength_throws() { + assertThrows( + IllegalArgumentException.class, + () -> Boxes.ftyp(/* additionalCompatibleBrands= */ ImmutableList.of("dby"))); + } + + @Test + public void createFtypBox_forDolbyVision_containsDby1CompatibleBrand() { + ByteBuffer ftypBox = Boxes.ftyp(/* additionalCompatibleBrands= */ ImmutableList.of("dby1")); + + assertThat(ftypBox.getInt()).isEqualTo(32); + byte[] type = new byte[4]; + ftypBox.get(type); + assertThat(type).isEqualTo(Util.getUtf8Bytes("ftyp")); + assertThat(ftypBox.getInt()).isEqualTo(Util.getIntegerCodeForString("isom")); + assertThat(ftypBox.getInt()).isEqualTo(0x020000); + + List compatibleBrands = new ArrayList<>(); + while (ftypBox.hasRemaining()) { + compatibleBrands.add(ftypBox.getInt()); + } + assertThat(compatibleBrands) + .containsExactly( + Util.getIntegerCodeForString("isom"), + Util.getIntegerCodeForString("iso2"), + Util.getIntegerCodeForString("mp41"), + Util.getIntegerCodeForString("dby1")) + .inOrder(); + } + @Test public void createMfhdBox_matchesExpected() throws IOException { ByteBuffer mfhdBox = Boxes.mfhd(/* sequenceNumber= */ 5); diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndTest.java index 089f61532f4..9fee4cd59ab 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/FragmentedMp4MuxerEndToEndTest.java @@ -15,11 +15,14 @@ */ package androidx.media3.muxer; +import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT; import static androidx.media3.muxer.MuxerTestUtil.feedInputDataToMuxer; +import static androidx.media3.muxer.MuxerTestUtil.getFakeSampleAndSampleInfo; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.truth.Truth.assertThat; import android.content.Context; +import android.util.Pair; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; @@ -83,6 +86,30 @@ public void createFragmentedMp4File_fromInputFileSampleData_matchesExpectedBoxSt + "_fragmented_box_structure")); } + @Test + public void createFragmentedMp4File_withDolbyVisionTrack_ftypContainsDby1CompatibleBrand() + throws Exception { + String outputFilePath = temporaryFolder.newFile().getPath(); + Format dolbyVisionFormat = + FAKE_VIDEO_FORMAT + .buildUpon() + .setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION) + .setCodecs("dvav.09.02") + .build(); + Pair sampleAndSampleInfo = + getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L, /* isVideo= */ true); + + try (FragmentedMp4Muxer muxer = + new FragmentedMp4Muxer.Builder(new FileOutputStream(outputFilePath).getChannel()) + .build()) { + int trackId = muxer.addTrack(dolbyVisionFormat); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + } + + byte[] outputFileBytes = TestUtil.getByteArrayFromFilePath(outputFilePath); + assertThat(MuxerTestUtil.ftypBoxContainsCompatibleBrand(outputFileBytes, "dby1")).isTrue(); + } + @Test public void createFragmentedMp4File_fromAudioOnlyInputFile_writesExpectedFragments() throws Exception { diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java index 0daef53181b..5dea3e38f05 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -105,6 +105,28 @@ public void writeMp4File_withSampleAndMetadata_matchedExpectedBoxStructure() thr MuxerTestUtil.getExpectedMp4DumpFilePath("mp4_with_samples_and_metadata.mp4")); } + @Test + public void createMp4File_withDolbyVisionTrack_ftypContainsDby1CompatibleBrand() + throws Exception { + String outputFilePath = temporaryFolder.newFile().getPath(); + Format dolbyVisionFormat = + FAKE_VIDEO_FORMAT + .buildUpon() + .setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION) + .setCodecs("dvav.09.02") + .build(); + Pair sampleAndSampleInfo = + getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L, /* isVideo= */ true); + + try (Mp4Muxer muxer = new Mp4Muxer.Builder(SeekableMuxerOutput.of(outputFilePath)).build()) { + int trackId = muxer.addTrack(dolbyVisionFormat); + muxer.writeSampleData(trackId, sampleAndSampleInfo.first, sampleAndSampleInfo.second); + } + + byte[] outputFileBytes = TestUtil.getByteArrayFromFilePath(outputFilePath); + assertThat(MuxerTestUtil.ftypBoxContainsCompatibleBrand(outputFileBytes, "dby1")).isTrue(); + } + @Test public void createMp4File_addTrackAndMetadataButNoSamples_createsEmptyFile() throws Exception { String outputFilePath = temporaryFolder.newFile().getPath(); diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerTestUtil.java b/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerTestUtil.java index 185d1c60f08..e2849206d38 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerTestUtil.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerTestUtil.java @@ -27,6 +27,7 @@ import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.MediaFormatUtil; +import androidx.media3.common.util.Util; import androidx.media3.inspector.MediaExtractorCompat; import com.google.common.collect.ImmutableList; import java.io.IOException; @@ -165,5 +166,23 @@ public static void feedInputDataToMuxer( extractor.release(); } + /** + * Returns whether the {@code ftyp} box at the start of {@code outputFileBytes} declares {@code + * compatibleBrand} as one of its compatible brands. + */ + public static boolean ftypBoxContainsCompatibleBrand( + byte[] outputFileBytes, String compatibleBrand) { + ByteBuffer buffer = ByteBuffer.wrap(outputFileBytes); + int ftypBoxSize = buffer.getInt(); + buffer.position(16); // Skip box size, "ftyp", major_brand and minor_version. + int compatibleBrandCode = Util.getIntegerCodeForString(compatibleBrand); + while (buffer.position() < ftypBoxSize) { + if (buffer.getInt() == compatibleBrandCode) { + return true; + } + } + return false; + } + private MuxerTestUtil() {} } diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerUtilTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerUtilTest.java new file mode 100644 index 00000000000..834a81097f5 --- /dev/null +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/MuxerUtilTest.java @@ -0,0 +1,144 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package androidx.media3.muxer; + +import static androidx.media3.muxer.MuxerTestUtil.FAKE_AUDIO_FORMAT; +import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT; +import static com.google.common.truth.Truth.assertThat; + +import androidx.media3.common.Format; +import androidx.media3.common.MimeTypes; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.common.collect.ImmutableList; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Unit tests for {@link MuxerUtil}. */ +@RunWith(AndroidJUnit4.class) +public class MuxerUtilTest { + + @Test + public void getFtypCompatibleBrands_withNonDolbyTracks_returnsEmptyList() { + Track videoTrack = + new Track(/* trackId= */ 0, FAKE_VIDEO_FORMAT, /* sampleCopyEnabled= */ false); + Track audioTrack = + new Track(/* trackId= */ 1, FAKE_AUDIO_FORMAT, /* sampleCopyEnabled= */ false); + + List compatibleBrands = + MuxerUtil.getFtypCompatibleBrands(ImmutableList.of(videoTrack, audioTrack)); + + assertThat(compatibleBrands).isEmpty(); + } + + @Test + public void getFtypCompatibleBrands_withDolbyVisionTrack_returnsDby1() { + Track dolbyVisionTrack = + new Track( + /* trackId= */ 0, + FAKE_VIDEO_FORMAT.buildUpon().setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION).build(), + /* sampleCopyEnabled= */ false); + + List compatibleBrands = + MuxerUtil.getFtypCompatibleBrands(ImmutableList.of(dolbyVisionTrack)); + + assertThat(compatibleBrands).containsExactly("dby1"); + } + + @Test + public void getFtypCompatibleBrands_withMixedDolbyAndNonDolbyTracks_returnsDby1() { + Track videoTrack = + new Track(/* trackId= */ 0, FAKE_VIDEO_FORMAT, /* sampleCopyEnabled= */ false); + Track dolbyVisionTrack = + new Track( + /* trackId= */ 1, + FAKE_VIDEO_FORMAT.buildUpon().setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION).build(), + /* sampleCopyEnabled= */ false); + Track audioTrack = + new Track(/* trackId= */ 2, FAKE_AUDIO_FORMAT, /* sampleCopyEnabled= */ false); + + List compatibleBrands = + MuxerUtil.getFtypCompatibleBrands( + ImmutableList.of(videoTrack, dolbyVisionTrack, audioTrack)); + + assertThat(compatibleBrands).containsExactly("dby1"); + } + + @Test + public void getFtypCompatibleBrands_withMultipleDolbyTracks_returnsSingleDby1() { + Format dolbyVisionFormat = + FAKE_VIDEO_FORMAT.buildUpon().setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION).build(); + Track dolbyVisionTrack1 = + new Track(/* trackId= */ 0, dolbyVisionFormat, /* sampleCopyEnabled= */ false); + Track dolbyVisionTrack2 = + new Track(/* trackId= */ 1, dolbyVisionFormat, /* sampleCopyEnabled= */ false); + Track ac4Track = + new Track( + /* trackId= */ 2, + FAKE_AUDIO_FORMAT.buildUpon().setSampleMimeType(MimeTypes.AUDIO_AC4).build(), + /* sampleCopyEnabled= */ false); + + List compatibleBrands = + MuxerUtil.getFtypCompatibleBrands( + ImmutableList.of(dolbyVisionTrack1, dolbyVisionTrack2, ac4Track)); + + assertThat(compatibleBrands).containsExactly("dby1"); + } + + @Test + public void getFtypCompatibleBrands_withAc3Track_returnsDby1() { + assertThatTrackWithMimeTypeProducesDby1(MimeTypes.AUDIO_AC3); + } + + @Test + public void getFtypCompatibleBrands_withAc4Track_returnsDby1() { + assertThatTrackWithMimeTypeProducesDby1(MimeTypes.AUDIO_AC4); + } + + @Test + public void getFtypCompatibleBrands_withEac3Track_returnsDby1() { + assertThatTrackWithMimeTypeProducesDby1(MimeTypes.AUDIO_E_AC3); + } + + @Test + public void getFtypCompatibleBrands_withEac3JocTrack_returnsDby1() { + assertThatTrackWithMimeTypeProducesDby1(MimeTypes.AUDIO_E_AC3_JOC); + } + + @Test + public void getFtypCompatibleBrands_withTrueHdTrack_returnsDby1() { + assertThatTrackWithMimeTypeProducesDby1(MimeTypes.AUDIO_TRUEHD); + } + + @Test + public void getFtypCompatibleBrands_withEmptyTrackList_returnsEmptyList() { + List compatibleBrands = MuxerUtil.getFtypCompatibleBrands(ImmutableList.of()); + + assertThat(compatibleBrands).isEmpty(); + } + + private static void assertThatTrackWithMimeTypeProducesDby1(String mimeType) { + Track track = + new Track( + /* trackId= */ 0, + FAKE_AUDIO_FORMAT.buildUpon().setSampleMimeType(mimeType).build(), + /* sampleCopyEnabled= */ false); + + List compatibleBrands = MuxerUtil.getFtypCompatibleBrands(ImmutableList.of(track)); + + assertThat(compatibleBrands).containsExactly("dby1"); + } +} diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4.dump index 517f8615b62..0442aeb3a7d 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4.dump @@ -1,10 +1,10 @@ seekMap: isSeekable = true duration = 2680000 - getPosition(0) = [[timeUs=-455000, position=400052], [timeUs=611666, position=411095]] - getPosition(1) = [[timeUs=-455000, position=400052], [timeUs=611666, position=411095]] - getPosition(1340000) = [[timeUs=611666, position=411095], [timeUs=1680000, position=429829]] - getPosition(2680000) = [[timeUs=1680000, position=429829]] + getPosition(0) = [[timeUs=-455000, position=400056], [timeUs=611666, position=411099]] + getPosition(1) = [[timeUs=-455000, position=400056], [timeUs=611666, position=411099]] + getPosition(1340000) = [[timeUs=611666, position=411099], [timeUs=1680000, position=429833]] + getPosition(2680000) = [[timeUs=1680000, position=429833]] numberOfTracks = 3 track 0: total output bytes = 3226787 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4_fragmented.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4_fragmented.dump index 4ce874ebcfb..711c6e6dd25 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4_fragmented.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4/sample_edit_list.mp4_fragmented.dump @@ -1,7 +1,7 @@ seekMap: isSeekable = false duration = UNSET TIME - getPosition(0) = [[timeUs=0, position=1909]] + getPosition(0) = [[timeUs=0, position=1913]] numberOfTracks = 3 track 0: total output bytes = 3226787 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4.dump index 582b1a1bb3d..902213d022e 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4.dump @@ -1,10 +1,10 @@ seekMap: isSeekable = true duration = 1284200 - getPosition(0) = [[timeUs=0, position=400052]] - getPosition(1) = [[timeUs=0, position=400052]] - getPosition(642100) = [[timeUs=0, position=400052]] - getPosition(1284200) = [[timeUs=0, position=400052]] + getPosition(0) = [[timeUs=0, position=400056]] + getPosition(1) = [[timeUs=0, position=400056]] + getPosition(642100) = [[timeUs=0, position=400056]] + getPosition(1284200) = [[timeUs=0, position=400056]] numberOfTracks = 2 track 0: total output bytes = 3324667 diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4_fragmented.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4_fragmented.dump index ed81e8895a7..846f51eb87d 100644 --- a/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4_fragmented.dump +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4/video_dovi_1920x1080_60fps_dvav_09.mp4_fragmented.dump @@ -1,7 +1,7 @@ seekMap: isSeekable = false duration = UNSET TIME - getPosition(0) = [[timeUs=0, position=1284]] + getPosition(0) = [[timeUs=0, position=1288]] numberOfTracks = 2 track 0: total output bytes = 3324667