diff --git a/libraries/container/src/main/java/androidx/media3/container/NalUnitUtil.java b/libraries/container/src/main/java/androidx/media3/container/NalUnitUtil.java index 4f3fa76e34..75689dcfe6 100644 --- a/libraries/container/src/main/java/androidx/media3/container/NalUnitUtil.java +++ b/libraries/container/src/main/java/androidx/media3/container/NalUnitUtil.java @@ -682,16 +682,22 @@ public final class NalUnitUtil { } /** - * Returns the number of bytes needed from the NAL unit to determine whether subsequent NAL units - * can depend on the current NAL unit. + * Returns the number of bytes in the NAL unit header. + * + *

The NAL unit header can be used to determine the NAL unit type and whether subsequent NAL + * units can depend on the current NAL unit. + * + *

This is {@code nalUnitHeaderBytes} from the H.264 spec, or the size of {@code + * nal_unit_header()} in H.265. * * @param format The sample {@link Format}. */ - public static int numberOfBytesToDetermineSampleDependencies(Format format) { + public static int numberOfBytesInNalUnitHeader(Format format) { if (Objects.equals(format.sampleMimeType, MimeTypes.VIDEO_H264)) { return 1; } - if (Objects.equals(format.sampleMimeType, MimeTypes.VIDEO_H265)) { + if (Objects.equals(format.sampleMimeType, MimeTypes.VIDEO_H265) + || MimeTypes.containsCodecsCorrespondingToMimeType(format.codecs, MimeTypes.VIDEO_H265)) { return 2; } return 0; diff --git a/libraries/container/src/test/java/androidx/media3/container/NalUnitUtilTest.java b/libraries/container/src/test/java/androidx/media3/container/NalUnitUtilTest.java index fa2cd5a6dc..57de655137 100644 --- a/libraries/container/src/test/java/androidx/media3/container/NalUnitUtilTest.java +++ b/libraries/container/src/test/java/androidx/media3/container/NalUnitUtilTest.java @@ -16,7 +16,7 @@ package androidx.media3.container; import static androidx.media3.container.NalUnitUtil.isDependedOn; -import static androidx.media3.container.NalUnitUtil.numberOfBytesToDetermineSampleDependencies; +import static androidx.media3.container.NalUnitUtil.numberOfBytesInNalUnitHeader; import static androidx.media3.test.utils.TestUtil.createByteArray; import static com.google.common.truth.Truth.assertThat; @@ -499,10 +499,10 @@ public final class NalUnitUtilTest { } @Test - public void numberOfBytesToDetermineSampleDependencies_vp8_returnsZero() { + public void numberOfBytesInNalUnitHeader_vp8_returnsZero() { Format vp8Video = new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_VP8).build(); - assertThat(numberOfBytesToDetermineSampleDependencies(vp8Video)).isEqualTo(0); + assertThat(numberOfBytesInNalUnitHeader(vp8Video)).isEqualTo(0); } @Test diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java index 6bd37531e3..7091ac0e6c 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/FragmentedMp4Extractor.java @@ -149,6 +149,14 @@ public class FragmentedMp4Extractor implements Extractor { */ public static final int FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES = 1 << 6; // 64 + /** + * Flag to extract additional sample dependency information, and mark output buffers with {@link + * C#BUFFER_FLAG_NOT_DEPENDED_ON} for {@linkplain MimeTypes#VIDEO_H265 H.265} video. + * + *

See {@link #FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES}. + */ + public static final int FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265 = 1 << 7; + /** * @deprecated Use {@link #newFactory(SubtitleParser.Factory)} instead. */ @@ -193,7 +201,7 @@ public class FragmentedMp4Extractor implements Extractor { // Temporary arrays. private final ParsableByteArray nalStartCode; private final ParsableByteArray nalPrefix; - private final ParsableByteArray nalBuffer; + private final ParsableByteArray nalUnitWithoutHeaderBuffer; private final byte[] scratchBytes; private final ParsableByteArray scratch; @@ -400,8 +408,8 @@ public class FragmentedMp4Extractor implements Extractor { eventMessageEncoder = new EventMessageEncoder(); atomHeader = new ParsableByteArray(Mp4Box.LONG_HEADER_SIZE); nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE); - nalPrefix = new ParsableByteArray(5); - nalBuffer = new ParsableByteArray(); + nalPrefix = new ParsableByteArray(6); + nalUnitWithoutHeaderBuffer = new ParsableByteArray(); scratchBytes = new byte[16]; scratch = new ParsableByteArray(scratchBytes); containerAtoms = new ArrayDeque<>(); @@ -1533,12 +1541,10 @@ public class FragmentedMp4Extractor implements Extractor { if (parserState == STATE_READING_SAMPLE_START) { sampleSize = trackBundle.getCurrentSampleSize(); // We must check all NAL units in the Fragmented MP4 sample for dependencies. - // When FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES is unset, or codec is not supported, + // When reading sample dependencies is disabled, or codec is not supported, // set isSampleDependedOn = true and skip parsing the payload bytes. isSampleDependedOn = - (flags & FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES) == 0 - || !Objects.equals( - trackBundle.moovSampleTable.track.format.sampleMimeType, MimeTypes.VIDEO_H264); + !canReadWithinGopSampleDependencies(trackBundle.moovSampleTable.track.format); if (trackBundle.currentSampleIndex < trackBundle.firstSampleToOutputIndex) { input.skipFully(sampleSize); @@ -1585,57 +1591,74 @@ public class FragmentedMp4Extractor implements Extractor { nalPrefixData[0] = 0; nalPrefixData[1] = 0; nalPrefixData[2] = 0; - int nalUnitPrefixLength = track.nalUnitLengthFieldLength + 1; int nalUnitLengthFieldLengthDiff = 4 - track.nalUnitLengthFieldLength; // NAL units are length delimited, but the decoder requires start code delimited units. // Loop until we've written the sample to the track output, replacing length delimiters with // start codes as we encounter them. while (sampleBytesWritten < sampleSize) { if (sampleCurrentNalBytesRemaining == 0) { + int numberOfNalUnitHeaderBytesToRead = 0; + if (ceaTrackOutputs.length > 0 || !isSampleDependedOn) { + // Try to read the NAL unit header if we're parsing captions or sample dependencies. + int nalUnitHeaderSize = NalUnitUtil.numberOfBytesInNalUnitHeader(track.format); + if (track.nalUnitLengthFieldLength + nalUnitHeaderSize + <= sampleSize - sampleBytesWritten) { + // In some malformed videos with padding, the NAL unit may be empty. + // See b/383201567#comment20 + // Only try to read the header if there are enough bytes in this sample. + numberOfNalUnitHeaderBytesToRead = nalUnitHeaderSize; + } + } + // Read numberOfNalUnitHeaderBytesToRead in the same readFully call that reads the NAL + // length. This ensures sampleBytesRead, sampleBytesWritten and isSampleDependedOn remain + // in a consistent state if we have read failures. + int nalUnitPrefixLength = + track.nalUnitLengthFieldLength + numberOfNalUnitHeaderBytesToRead; // Read the NAL length so that we know where we find the next one, and its type. input.readFully(nalPrefixData, nalUnitLengthFieldLengthDiff, nalUnitPrefixLength); nalPrefix.setPosition(0); int nalLengthInt = nalPrefix.readInt(); - if (nalLengthInt < 1) { + if (nalLengthInt < 0) { throw ParserException.createForMalformedContainer( "Invalid NAL length", /* cause= */ null); } - sampleCurrentNalBytesRemaining = nalLengthInt - 1; + sampleCurrentNalBytesRemaining = nalLengthInt - numberOfNalUnitHeaderBytesToRead; // Write a start code for the current NAL unit. nalStartCode.setPosition(0); output.sampleData(nalStartCode, 4); - // Write the NAL unit type byte. - output.sampleData(nalPrefix, 1); + sampleBytesWritten += 4; + sampleSize += nalUnitLengthFieldLengthDiff; processSeiNalUnitPayload = ceaTrackOutputs.length > 0 + && numberOfNalUnitHeaderBytesToRead > 0 && NalUnitUtil.isNalUnitSei(track.format, nalPrefixData[4]); - sampleBytesWritten += 5; - sampleSize += nalUnitLengthFieldLengthDiff; - if (!isSampleDependedOn - && Objects.equals( - trackBundle.moovSampleTable.track.format.sampleMimeType, MimeTypes.VIDEO_H264) - && NalUnitUtil.isH264NalUnitDependedOn(nalPrefixData[4])) { + // Write the extra NAL unit bytes to the output. + output.sampleData(nalPrefix, numberOfNalUnitHeaderBytesToRead); + sampleBytesWritten += numberOfNalUnitHeaderBytesToRead; + if (numberOfNalUnitHeaderBytesToRead > 0 + && !isSampleDependedOn + && NalUnitUtil.isDependedOn( + nalPrefixData, + /* offset= */ 4, + /* length= */ numberOfNalUnitHeaderBytesToRead, + track.format)) { isSampleDependedOn = true; } } else { int writtenBytes; if (processSeiNalUnitPayload) { - // Read and write the payload of the SEI NAL unit. - nalBuffer.reset(sampleCurrentNalBytesRemaining); - input.readFully(nalBuffer.getData(), 0, sampleCurrentNalBytesRemaining); - output.sampleData(nalBuffer, sampleCurrentNalBytesRemaining); + // Read and write the remaining payload of the SEI NAL unit. + nalUnitWithoutHeaderBuffer.reset(sampleCurrentNalBytesRemaining); + input.readFully( + nalUnitWithoutHeaderBuffer.getData(), 0, sampleCurrentNalBytesRemaining); + output.sampleData(nalUnitWithoutHeaderBuffer, sampleCurrentNalBytesRemaining); writtenBytes = sampleCurrentNalBytesRemaining; // Unescape and process the SEI NAL unit. int unescapedLength = - NalUnitUtil.unescapeStream(nalBuffer.getData(), nalBuffer.limit()); - // If the format is H.265/HEVC the NAL unit header has two bytes so skip one more byte. - nalBuffer.setPosition( - Objects.equals(track.format.sampleMimeType, MimeTypes.VIDEO_H265) - || MimeTypes.containsCodecsCorrespondingToMimeType( - track.format.codecs, MimeTypes.VIDEO_H265) - ? 1 - : 0); - nalBuffer.setLimit(unescapedLength); + NalUnitUtil.unescapeStream( + nalUnitWithoutHeaderBuffer.getData(), nalUnitWithoutHeaderBuffer.limit()); + nalUnitWithoutHeaderBuffer.setPosition(0); + nalUnitWithoutHeaderBuffer.setLimit(unescapedLength); if (track.format.maxNumReorderSamples == Format.NO_VALUE) { if (reorderingSeiMessageQueue.getMaxSize() != 0) { @@ -1645,7 +1668,7 @@ public class FragmentedMp4Extractor implements Extractor { != track.format.maxNumReorderSamples) { reorderingSeiMessageQueue.setMaxSize(track.format.maxNumReorderSamples); } - reorderingSeiMessageQueue.add(sampleTimeUs, nalBuffer); + reorderingSeiMessageQueue.add(sampleTimeUs, nalUnitWithoutHeaderBuffer); if ((trackBundle.getCurrentSampleFlags() & C.BUFFER_FLAG_END_OF_STREAM) != 0) { reorderingSeiMessageQueue.flush(); @@ -1666,7 +1689,7 @@ public class FragmentedMp4Extractor implements Extractor { } @C.BufferFlags int sampleFlags = trackBundle.getCurrentSampleFlags(); - if ((flags & FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES) != 0 && !isSampleDependedOn) { + if (!isSampleDependedOn) { sampleFlags |= C.BUFFER_FLAG_NOT_DEPENDED_ON; } @@ -1688,6 +1711,20 @@ public class FragmentedMp4Extractor implements Extractor { return true; } + /** + * Returns whether reading within GOP sample dependencies is enabled for the sample {@link + * Format}. + */ + private boolean canReadWithinGopSampleDependencies(Format format) { + if (Objects.equals(format.sampleMimeType, MimeTypes.VIDEO_H264)) { + return (flags & FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES) != 0; + } + if (Objects.equals(format.sampleMimeType, MimeTypes.VIDEO_H265)) { + return (flags & FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265) != 0; + } + return false; + } + /** * Called immediately after outputting a non-metadata sample, to output any pending metadata * samples. diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java index 0f0e4be0e2..4b874be88c 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/Mp4Extractor.java @@ -902,15 +902,14 @@ public final class Mp4Extractor implements Extractor, SeekMap { int nalUnitPrefixLength = track.track.nalUnitLengthFieldLength; int numberOfBytesToDetermineSampleDependencies = 0; if (!isSampleDependedOn - && nalUnitPrefixLength - + NalUnitUtil.numberOfBytesToDetermineSampleDependencies(track.track.format) + && nalUnitPrefixLength + NalUnitUtil.numberOfBytesInNalUnitHeader(track.track.format) <= track.sampleTable.sizes[sampleIndex] - sampleBytesRead) { // Parsing sample dependencies needs the first few NAL unit bytes. Read them in the same // readFully call that reads the NAL length. This ensures sampleBytesRead, // sampleBytesWritten and isSampleDependedOn remain in a consistent state if we have // read failures. numberOfBytesToDetermineSampleDependencies = - NalUnitUtil.numberOfBytesToDetermineSampleDependencies(track.track.format); + NalUnitUtil.numberOfBytesInNalUnitHeader(track.track.format); nalUnitPrefixLength = track.track.nalUnitLengthFieldLength + numberOfBytesToDetermineSampleDependencies; } diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/FragmentedMp4ExtractorParameterizedTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/FragmentedMp4ExtractorParameterizedTest.java index c7bd6cd1ec..3e19c45378 100644 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/FragmentedMp4ExtractorParameterizedTest.java +++ b/libraries/extractor/src/test/java/androidx/media3/extractor/mp4/FragmentedMp4ExtractorParameterizedTest.java @@ -200,6 +200,16 @@ public final class FragmentedMp4ExtractorParameterizedTest { /* closedCaptionFormats= */ ImmutableList.of(), "media/mp4/sample_fragmented_iamf.mp4"); } + @Test + public void sampleWithNonReferenceH265FramesAndCaptions() throws Exception { + // Enabling the CEA-608 track enables SEI payload parsing. + List closedCaptions = + Collections.singletonList( + new Format.Builder().setSampleMimeType(MimeTypes.APPLICATION_CEA608).build()); + + assertExtractorBehavior(closedCaptions, "media/mp4/fragmented_captions_h265.mp4"); + } + private void assertExtractorBehavior(List closedCaptionFormats, String file) throws IOException { ExtractorAsserts.AssertionConfig.Builder assertionConfigBuilder = @@ -232,6 +242,7 @@ public final class FragmentedMp4ExtractorParameterizedTest { } if (readWithinGopSampleDependencies) { flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES; + flags |= FragmentedMp4Extractor.FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES_H265; } @FragmentedMp4Extractor.Flags int finalFlags = flags; diff --git a/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.0.dump b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.0.dump new file mode 100644 index 0000000000..23c9d2aae3 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.0.dump @@ -0,0 +1,283 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = [[timeUs=0, position=3203]] +numberOfTracks = 2 +track 0: + total output bytes = 24020 + sample count = 61 + format 0: + id = 1 + containerMimeType = video/mp4 + sampleMimeType = video/hevc + codecs = hvc1.1.6.L60.90 + maxNumReorderSamples = 2 + width = 416 + height = 234 + maxSubLayers = 1 + colorInfo: + colorSpace = 2 + colorRange = 2 + colorTransfer = 3 + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 2426, hash 25737613 + sample 0: + time = 66733 + flags = 1 + data = length 5220, hash 5F0CCC08 + sample 1: + time = 233566 + flags = 0 + data = length 615, hash CBFF4D3C + sample 2: + time = 166833 + flags = 0 + data = length 217, hash B600557D + sample 3: + time = 100100 + flags = 0 + data = length 177, hash 99B5D77F + sample 4: + time = 133466 + flags = 0 + data = length 190, hash AF7F85A2 + sample 5: + time = 200200 + flags = 0 + data = length 225, hash BA8F2E19 + sample 6: + time = 333666 + flags = 0 + data = length 330, hash DCBABAE8 + sample 7: + time = 300300 + flags = 0 + data = length 183, hash 15A2DB25 + sample 8: + time = 266933 + flags = 0 + data = length 154, hash 81018D0E + sample 9: + time = 400400 + flags = 0 + data = length 576, hash C9C5389F + sample 10: + time = 367033 + flags = 0 + data = length 173, hash 2D567C7E + sample 11: + time = 500500 + flags = 0 + data = length 356, hash A6D37B60 + sample 12: + time = 467133 + flags = 0 + data = length 188, hash 11AB1597 + sample 13: + time = 433766 + flags = 0 + data = length 174, hash 18C46868 + sample 14: + time = 567233 + flags = 0 + data = length 331, hash EEA184AF + sample 15: + time = 533866 + flags = 0 + data = length 213, hash 3FAB17EE + sample 16: + time = 667333 + flags = 0 + data = length 371, hash D0ECAE97 + sample 17: + time = 633966 + flags = 0 + data = length 179, hash 796F24AF + sample 18: + time = 600600 + flags = 0 + data = length 154, hash FD43F0C6 + sample 19: + time = 734066 + flags = 0 + data = length 622, hash 8AD9409C + sample 20: + time = 700700 + flags = 0 + data = length 195, hash 4EFA8FFD + sample 21: + time = 900900 + flags = 0 + data = length 424, hash 5F9D809C + sample 22: + time = 834166 + flags = 0 + data = length 187, hash FB5137FD + sample 23: + time = 767433 + flags = 0 + data = length 162, hash 7B352EA + sample 24: + time = 800800 + flags = 0 + data = length 173, hash 42EBA5AC + sample 25: + time = 867533 + flags = 0 + data = length 205, hash 15D2186B + sample 26: + time = 1001000 + flags = 0 + data = length 342, hash 70E9AD53 + sample 27: + time = 967633 + flags = 0 + data = length 200, hash 2C923950 + sample 28: + time = 934266 + flags = 0 + data = length 150, hash 242935D6 + sample 29: + time = 1167833 + flags = 0 + data = length 802, hash 60213433 + sample 30: + time = 1101100 + flags = 0 + data = length 203, hash 21B384E5 + sample 31: + time = 1034366 + flags = 0 + data = length 185, hash B2735872 + sample 32: + time = 1067733 + flags = 0 + data = length 1310, hash 8D4F7E35 + sample 33: + time = 1134466 + flags = 0 + data = length 176, hash D1D91C73 + sample 34: + time = 1334666 + flags = 0 + data = length 258, hash 92056B3A + sample 35: + time = 1267933 + flags = 0 + data = length 214, hash 86C47DEC + sample 36: + time = 1201200 + flags = 0 + data = length 201, hash AFA1B6D4 + sample 37: + time = 1234566 + flags = 0 + data = length 146, hash 3E1B1C72 + sample 38: + time = 1301300 + flags = 0 + data = length 173, hash FC0B911D + sample 39: + time = 1401400 + flags = 0 + data = length 617, hash 35AAFB9 + sample 40: + time = 1368033 + flags = 0 + data = length 179, hash E9838582 + sample 41: + time = 1468133 + flags = 0 + data = length 395, hash 8F5373AC + sample 42: + time = 1434766 + flags = 0 + data = length 184, hash 10ED9B63 + sample 43: + time = 1634966 + flags = 0 + data = length 460, hash ED8ECDE7 + sample 44: + time = 1568233 + flags = 0 + data = length 184, hash BF273413 + sample 45: + time = 1501500 + flags = 0 + data = length 162, hash FE32A96B + sample 46: + time = 1534866 + flags = 0 + data = length 201, hash BBB627F2 + sample 47: + time = 1601600 + flags = 0 + data = length 169, hash AFD9804F + sample 48: + time = 1735066 + flags = 0 + data = length 668, hash 4B9FB50F + sample 49: + time = 1701700 + flags = 0 + data = length 219, hash E2A651A2 + sample 50: + time = 1668333 + flags = 0 + data = length 162, hash ECB52FD2 + sample 51: + time = 1901900 + flags = 0 + data = length 405, hash 7DA640B4 + sample 52: + time = 1835166 + flags = 0 + data = length 188, hash 46D5E9D4 + sample 53: + time = 1768433 + flags = 0 + data = length 167, hash 65F87E6A + sample 54: + time = 1801800 + flags = 0 + data = length 161, hash 2E37B5E0 + sample 55: + time = 1868533 + flags = 0 + data = length 199, hash D63CF14E + sample 56: + time = 2002000 + flags = 0 + data = length 282, hash E748555D + sample 57: + time = 1968633 + flags = 0 + data = length 199, hash F341EE39 + sample 58: + time = 1935266 + flags = 0 + data = length 166, hash 32F07BFF + sample 59: + time = 2068733 + flags = 0 + data = length 2246, hash E07DFCAE + sample 60: + time = 2035366 + flags = 0 + data = length 53, hash D9F70BD5 +track 100: + total output bytes = 45 + sample count = 2 + format 0: + sampleMimeType = application/cea-608 + sample 0: + time = 66733 + flags = 1 + data = length 36, hash 6E15DFAD + sample 1: + time = 1935266 + flags = 1 + data = length 9, hash 604EC6AA +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.reading_within_gop_sample_dependencies.0.dump b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.reading_within_gop_sample_dependencies.0.dump new file mode 100644 index 0000000000..fbf4d20816 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.reading_within_gop_sample_dependencies.0.dump @@ -0,0 +1,283 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = [[timeUs=0, position=3203]] +numberOfTracks = 2 +track 0: + total output bytes = 24020 + sample count = 61 + format 0: + id = 1 + containerMimeType = video/mp4 + sampleMimeType = video/hevc + codecs = hvc1.1.6.L60.90 + maxNumReorderSamples = 2 + width = 416 + height = 234 + maxSubLayers = 1 + colorInfo: + colorSpace = 2 + colorRange = 2 + colorTransfer = 3 + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 2426, hash 25737613 + sample 0: + time = 66733 + flags = 1 + data = length 5220, hash 5F0CCC08 + sample 1: + time = 233566 + flags = 0 + data = length 615, hash CBFF4D3C + sample 2: + time = 166833 + flags = 0 + data = length 217, hash B600557D + sample 3: + time = 100100 + flags = 67108864 + data = length 177, hash 99B5D77F + sample 4: + time = 133466 + flags = 67108864 + data = length 190, hash AF7F85A2 + sample 5: + time = 200200 + flags = 67108864 + data = length 225, hash BA8F2E19 + sample 6: + time = 333666 + flags = 0 + data = length 330, hash DCBABAE8 + sample 7: + time = 300300 + flags = 0 + data = length 183, hash 15A2DB25 + sample 8: + time = 266933 + flags = 67108864 + data = length 154, hash 81018D0E + sample 9: + time = 400400 + flags = 0 + data = length 576, hash C9C5389F + sample 10: + time = 367033 + flags = 67108864 + data = length 173, hash 2D567C7E + sample 11: + time = 500500 + flags = 0 + data = length 356, hash A6D37B60 + sample 12: + time = 467133 + flags = 0 + data = length 188, hash 11AB1597 + sample 13: + time = 433766 + flags = 67108864 + data = length 174, hash 18C46868 + sample 14: + time = 567233 + flags = 0 + data = length 331, hash EEA184AF + sample 15: + time = 533866 + flags = 67108864 + data = length 213, hash 3FAB17EE + sample 16: + time = 667333 + flags = 0 + data = length 371, hash D0ECAE97 + sample 17: + time = 633966 + flags = 0 + data = length 179, hash 796F24AF + sample 18: + time = 600600 + flags = 67108864 + data = length 154, hash FD43F0C6 + sample 19: + time = 734066 + flags = 0 + data = length 622, hash 8AD9409C + sample 20: + time = 700700 + flags = 67108864 + data = length 195, hash 4EFA8FFD + sample 21: + time = 900900 + flags = 0 + data = length 424, hash 5F9D809C + sample 22: + time = 834166 + flags = 0 + data = length 187, hash FB5137FD + sample 23: + time = 767433 + flags = 67108864 + data = length 162, hash 7B352EA + sample 24: + time = 800800 + flags = 67108864 + data = length 173, hash 42EBA5AC + sample 25: + time = 867533 + flags = 67108864 + data = length 205, hash 15D2186B + sample 26: + time = 1001000 + flags = 0 + data = length 342, hash 70E9AD53 + sample 27: + time = 967633 + flags = 0 + data = length 200, hash 2C923950 + sample 28: + time = 934266 + flags = 67108864 + data = length 150, hash 242935D6 + sample 29: + time = 1167833 + flags = 0 + data = length 802, hash 60213433 + sample 30: + time = 1101100 + flags = 0 + data = length 203, hash 21B384E5 + sample 31: + time = 1034366 + flags = 67108864 + data = length 185, hash B2735872 + sample 32: + time = 1067733 + flags = 67108864 + data = length 1310, hash 8D4F7E35 + sample 33: + time = 1134466 + flags = 67108864 + data = length 176, hash D1D91C73 + sample 34: + time = 1334666 + flags = 0 + data = length 258, hash 92056B3A + sample 35: + time = 1267933 + flags = 0 + data = length 214, hash 86C47DEC + sample 36: + time = 1201200 + flags = 67108864 + data = length 201, hash AFA1B6D4 + sample 37: + time = 1234566 + flags = 67108864 + data = length 146, hash 3E1B1C72 + sample 38: + time = 1301300 + flags = 67108864 + data = length 173, hash FC0B911D + sample 39: + time = 1401400 + flags = 0 + data = length 617, hash 35AAFB9 + sample 40: + time = 1368033 + flags = 67108864 + data = length 179, hash E9838582 + sample 41: + time = 1468133 + flags = 0 + data = length 395, hash 8F5373AC + sample 42: + time = 1434766 + flags = 67108864 + data = length 184, hash 10ED9B63 + sample 43: + time = 1634966 + flags = 0 + data = length 460, hash ED8ECDE7 + sample 44: + time = 1568233 + flags = 0 + data = length 184, hash BF273413 + sample 45: + time = 1501500 + flags = 67108864 + data = length 162, hash FE32A96B + sample 46: + time = 1534866 + flags = 67108864 + data = length 201, hash BBB627F2 + sample 47: + time = 1601600 + flags = 67108864 + data = length 169, hash AFD9804F + sample 48: + time = 1735066 + flags = 0 + data = length 668, hash 4B9FB50F + sample 49: + time = 1701700 + flags = 0 + data = length 219, hash E2A651A2 + sample 50: + time = 1668333 + flags = 67108864 + data = length 162, hash ECB52FD2 + sample 51: + time = 1901900 + flags = 0 + data = length 405, hash 7DA640B4 + sample 52: + time = 1835166 + flags = 0 + data = length 188, hash 46D5E9D4 + sample 53: + time = 1768433 + flags = 67108864 + data = length 167, hash 65F87E6A + sample 54: + time = 1801800 + flags = 67108864 + data = length 161, hash 2E37B5E0 + sample 55: + time = 1868533 + flags = 67108864 + data = length 199, hash D63CF14E + sample 56: + time = 2002000 + flags = 0 + data = length 282, hash E748555D + sample 57: + time = 1968633 + flags = 0 + data = length 199, hash F341EE39 + sample 58: + time = 1935266 + flags = 0 + data = length 166, hash 32F07BFF + sample 59: + time = 2068733 + flags = 0 + data = length 2246, hash E07DFCAE + sample 60: + time = 2035366 + flags = 67108864 + data = length 53, hash D9F70BD5 +track 100: + total output bytes = 45 + sample count = 2 + format 0: + sampleMimeType = application/cea-608 + sample 0: + time = 66733 + flags = 1 + data = length 36, hash 6E15DFAD + sample 1: + time = 1935266 + flags = 1 + data = length 9, hash 604EC6AA +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.reading_within_gop_sample_dependencies.unknown_length.dump b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.reading_within_gop_sample_dependencies.unknown_length.dump new file mode 100644 index 0000000000..fbf4d20816 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.reading_within_gop_sample_dependencies.unknown_length.dump @@ -0,0 +1,283 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = [[timeUs=0, position=3203]] +numberOfTracks = 2 +track 0: + total output bytes = 24020 + sample count = 61 + format 0: + id = 1 + containerMimeType = video/mp4 + sampleMimeType = video/hevc + codecs = hvc1.1.6.L60.90 + maxNumReorderSamples = 2 + width = 416 + height = 234 + maxSubLayers = 1 + colorInfo: + colorSpace = 2 + colorRange = 2 + colorTransfer = 3 + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 2426, hash 25737613 + sample 0: + time = 66733 + flags = 1 + data = length 5220, hash 5F0CCC08 + sample 1: + time = 233566 + flags = 0 + data = length 615, hash CBFF4D3C + sample 2: + time = 166833 + flags = 0 + data = length 217, hash B600557D + sample 3: + time = 100100 + flags = 67108864 + data = length 177, hash 99B5D77F + sample 4: + time = 133466 + flags = 67108864 + data = length 190, hash AF7F85A2 + sample 5: + time = 200200 + flags = 67108864 + data = length 225, hash BA8F2E19 + sample 6: + time = 333666 + flags = 0 + data = length 330, hash DCBABAE8 + sample 7: + time = 300300 + flags = 0 + data = length 183, hash 15A2DB25 + sample 8: + time = 266933 + flags = 67108864 + data = length 154, hash 81018D0E + sample 9: + time = 400400 + flags = 0 + data = length 576, hash C9C5389F + sample 10: + time = 367033 + flags = 67108864 + data = length 173, hash 2D567C7E + sample 11: + time = 500500 + flags = 0 + data = length 356, hash A6D37B60 + sample 12: + time = 467133 + flags = 0 + data = length 188, hash 11AB1597 + sample 13: + time = 433766 + flags = 67108864 + data = length 174, hash 18C46868 + sample 14: + time = 567233 + flags = 0 + data = length 331, hash EEA184AF + sample 15: + time = 533866 + flags = 67108864 + data = length 213, hash 3FAB17EE + sample 16: + time = 667333 + flags = 0 + data = length 371, hash D0ECAE97 + sample 17: + time = 633966 + flags = 0 + data = length 179, hash 796F24AF + sample 18: + time = 600600 + flags = 67108864 + data = length 154, hash FD43F0C6 + sample 19: + time = 734066 + flags = 0 + data = length 622, hash 8AD9409C + sample 20: + time = 700700 + flags = 67108864 + data = length 195, hash 4EFA8FFD + sample 21: + time = 900900 + flags = 0 + data = length 424, hash 5F9D809C + sample 22: + time = 834166 + flags = 0 + data = length 187, hash FB5137FD + sample 23: + time = 767433 + flags = 67108864 + data = length 162, hash 7B352EA + sample 24: + time = 800800 + flags = 67108864 + data = length 173, hash 42EBA5AC + sample 25: + time = 867533 + flags = 67108864 + data = length 205, hash 15D2186B + sample 26: + time = 1001000 + flags = 0 + data = length 342, hash 70E9AD53 + sample 27: + time = 967633 + flags = 0 + data = length 200, hash 2C923950 + sample 28: + time = 934266 + flags = 67108864 + data = length 150, hash 242935D6 + sample 29: + time = 1167833 + flags = 0 + data = length 802, hash 60213433 + sample 30: + time = 1101100 + flags = 0 + data = length 203, hash 21B384E5 + sample 31: + time = 1034366 + flags = 67108864 + data = length 185, hash B2735872 + sample 32: + time = 1067733 + flags = 67108864 + data = length 1310, hash 8D4F7E35 + sample 33: + time = 1134466 + flags = 67108864 + data = length 176, hash D1D91C73 + sample 34: + time = 1334666 + flags = 0 + data = length 258, hash 92056B3A + sample 35: + time = 1267933 + flags = 0 + data = length 214, hash 86C47DEC + sample 36: + time = 1201200 + flags = 67108864 + data = length 201, hash AFA1B6D4 + sample 37: + time = 1234566 + flags = 67108864 + data = length 146, hash 3E1B1C72 + sample 38: + time = 1301300 + flags = 67108864 + data = length 173, hash FC0B911D + sample 39: + time = 1401400 + flags = 0 + data = length 617, hash 35AAFB9 + sample 40: + time = 1368033 + flags = 67108864 + data = length 179, hash E9838582 + sample 41: + time = 1468133 + flags = 0 + data = length 395, hash 8F5373AC + sample 42: + time = 1434766 + flags = 67108864 + data = length 184, hash 10ED9B63 + sample 43: + time = 1634966 + flags = 0 + data = length 460, hash ED8ECDE7 + sample 44: + time = 1568233 + flags = 0 + data = length 184, hash BF273413 + sample 45: + time = 1501500 + flags = 67108864 + data = length 162, hash FE32A96B + sample 46: + time = 1534866 + flags = 67108864 + data = length 201, hash BBB627F2 + sample 47: + time = 1601600 + flags = 67108864 + data = length 169, hash AFD9804F + sample 48: + time = 1735066 + flags = 0 + data = length 668, hash 4B9FB50F + sample 49: + time = 1701700 + flags = 0 + data = length 219, hash E2A651A2 + sample 50: + time = 1668333 + flags = 67108864 + data = length 162, hash ECB52FD2 + sample 51: + time = 1901900 + flags = 0 + data = length 405, hash 7DA640B4 + sample 52: + time = 1835166 + flags = 0 + data = length 188, hash 46D5E9D4 + sample 53: + time = 1768433 + flags = 67108864 + data = length 167, hash 65F87E6A + sample 54: + time = 1801800 + flags = 67108864 + data = length 161, hash 2E37B5E0 + sample 55: + time = 1868533 + flags = 67108864 + data = length 199, hash D63CF14E + sample 56: + time = 2002000 + flags = 0 + data = length 282, hash E748555D + sample 57: + time = 1968633 + flags = 0 + data = length 199, hash F341EE39 + sample 58: + time = 1935266 + flags = 0 + data = length 166, hash 32F07BFF + sample 59: + time = 2068733 + flags = 0 + data = length 2246, hash E07DFCAE + sample 60: + time = 2035366 + flags = 67108864 + data = length 53, hash D9F70BD5 +track 100: + total output bytes = 45 + sample count = 2 + format 0: + sampleMimeType = application/cea-608 + sample 0: + time = 66733 + flags = 1 + data = length 36, hash 6E15DFAD + sample 1: + time = 1935266 + flags = 1 + data = length 9, hash 604EC6AA +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.unknown_length.dump b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.unknown_length.dump new file mode 100644 index 0000000000..23c9d2aae3 --- /dev/null +++ b/libraries/test_data/src/test/assets/extractordumps/mp4/fragmented_captions_h265.mp4.unknown_length.dump @@ -0,0 +1,283 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = [[timeUs=0, position=3203]] +numberOfTracks = 2 +track 0: + total output bytes = 24020 + sample count = 61 + format 0: + id = 1 + containerMimeType = video/mp4 + sampleMimeType = video/hevc + codecs = hvc1.1.6.L60.90 + maxNumReorderSamples = 2 + width = 416 + height = 234 + maxSubLayers = 1 + colorInfo: + colorSpace = 2 + colorRange = 2 + colorTransfer = 3 + lumaBitdepth = 8 + chromaBitdepth = 8 + initializationData: + data = length 2426, hash 25737613 + sample 0: + time = 66733 + flags = 1 + data = length 5220, hash 5F0CCC08 + sample 1: + time = 233566 + flags = 0 + data = length 615, hash CBFF4D3C + sample 2: + time = 166833 + flags = 0 + data = length 217, hash B600557D + sample 3: + time = 100100 + flags = 0 + data = length 177, hash 99B5D77F + sample 4: + time = 133466 + flags = 0 + data = length 190, hash AF7F85A2 + sample 5: + time = 200200 + flags = 0 + data = length 225, hash BA8F2E19 + sample 6: + time = 333666 + flags = 0 + data = length 330, hash DCBABAE8 + sample 7: + time = 300300 + flags = 0 + data = length 183, hash 15A2DB25 + sample 8: + time = 266933 + flags = 0 + data = length 154, hash 81018D0E + sample 9: + time = 400400 + flags = 0 + data = length 576, hash C9C5389F + sample 10: + time = 367033 + flags = 0 + data = length 173, hash 2D567C7E + sample 11: + time = 500500 + flags = 0 + data = length 356, hash A6D37B60 + sample 12: + time = 467133 + flags = 0 + data = length 188, hash 11AB1597 + sample 13: + time = 433766 + flags = 0 + data = length 174, hash 18C46868 + sample 14: + time = 567233 + flags = 0 + data = length 331, hash EEA184AF + sample 15: + time = 533866 + flags = 0 + data = length 213, hash 3FAB17EE + sample 16: + time = 667333 + flags = 0 + data = length 371, hash D0ECAE97 + sample 17: + time = 633966 + flags = 0 + data = length 179, hash 796F24AF + sample 18: + time = 600600 + flags = 0 + data = length 154, hash FD43F0C6 + sample 19: + time = 734066 + flags = 0 + data = length 622, hash 8AD9409C + sample 20: + time = 700700 + flags = 0 + data = length 195, hash 4EFA8FFD + sample 21: + time = 900900 + flags = 0 + data = length 424, hash 5F9D809C + sample 22: + time = 834166 + flags = 0 + data = length 187, hash FB5137FD + sample 23: + time = 767433 + flags = 0 + data = length 162, hash 7B352EA + sample 24: + time = 800800 + flags = 0 + data = length 173, hash 42EBA5AC + sample 25: + time = 867533 + flags = 0 + data = length 205, hash 15D2186B + sample 26: + time = 1001000 + flags = 0 + data = length 342, hash 70E9AD53 + sample 27: + time = 967633 + flags = 0 + data = length 200, hash 2C923950 + sample 28: + time = 934266 + flags = 0 + data = length 150, hash 242935D6 + sample 29: + time = 1167833 + flags = 0 + data = length 802, hash 60213433 + sample 30: + time = 1101100 + flags = 0 + data = length 203, hash 21B384E5 + sample 31: + time = 1034366 + flags = 0 + data = length 185, hash B2735872 + sample 32: + time = 1067733 + flags = 0 + data = length 1310, hash 8D4F7E35 + sample 33: + time = 1134466 + flags = 0 + data = length 176, hash D1D91C73 + sample 34: + time = 1334666 + flags = 0 + data = length 258, hash 92056B3A + sample 35: + time = 1267933 + flags = 0 + data = length 214, hash 86C47DEC + sample 36: + time = 1201200 + flags = 0 + data = length 201, hash AFA1B6D4 + sample 37: + time = 1234566 + flags = 0 + data = length 146, hash 3E1B1C72 + sample 38: + time = 1301300 + flags = 0 + data = length 173, hash FC0B911D + sample 39: + time = 1401400 + flags = 0 + data = length 617, hash 35AAFB9 + sample 40: + time = 1368033 + flags = 0 + data = length 179, hash E9838582 + sample 41: + time = 1468133 + flags = 0 + data = length 395, hash 8F5373AC + sample 42: + time = 1434766 + flags = 0 + data = length 184, hash 10ED9B63 + sample 43: + time = 1634966 + flags = 0 + data = length 460, hash ED8ECDE7 + sample 44: + time = 1568233 + flags = 0 + data = length 184, hash BF273413 + sample 45: + time = 1501500 + flags = 0 + data = length 162, hash FE32A96B + sample 46: + time = 1534866 + flags = 0 + data = length 201, hash BBB627F2 + sample 47: + time = 1601600 + flags = 0 + data = length 169, hash AFD9804F + sample 48: + time = 1735066 + flags = 0 + data = length 668, hash 4B9FB50F + sample 49: + time = 1701700 + flags = 0 + data = length 219, hash E2A651A2 + sample 50: + time = 1668333 + flags = 0 + data = length 162, hash ECB52FD2 + sample 51: + time = 1901900 + flags = 0 + data = length 405, hash 7DA640B4 + sample 52: + time = 1835166 + flags = 0 + data = length 188, hash 46D5E9D4 + sample 53: + time = 1768433 + flags = 0 + data = length 167, hash 65F87E6A + sample 54: + time = 1801800 + flags = 0 + data = length 161, hash 2E37B5E0 + sample 55: + time = 1868533 + flags = 0 + data = length 199, hash D63CF14E + sample 56: + time = 2002000 + flags = 0 + data = length 282, hash E748555D + sample 57: + time = 1968633 + flags = 0 + data = length 199, hash F341EE39 + sample 58: + time = 1935266 + flags = 0 + data = length 166, hash 32F07BFF + sample 59: + time = 2068733 + flags = 0 + data = length 2246, hash E07DFCAE + sample 60: + time = 2035366 + flags = 0 + data = length 53, hash D9F70BD5 +track 100: + total output bytes = 45 + sample count = 2 + format 0: + sampleMimeType = application/cea-608 + sample 0: + time = 66733 + flags = 1 + data = length 36, hash 6E15DFAD + sample 1: + time = 1935266 + flags = 1 + data = length 9, hash 604EC6AA +tracksEnded = true diff --git a/libraries/test_data/src/test/assets/media/mp4/fragmented_captions_h265.mp4 b/libraries/test_data/src/test/assets/media/mp4/fragmented_captions_h265.mp4 new file mode 100644 index 0000000000..901e165ce2 Binary files /dev/null and b/libraries/test_data/src/test/assets/media/mp4/fragmented_captions_h265.mp4 differ