diff --git a/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_with_increasing_timestamps_320w_240h.mp4.clipped.dump b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_with_increasing_timestamps_320w_240h.mp4.clipped.dump new file mode 100644 index 0000000000..87dcf11f2e --- /dev/null +++ b/libraries/test_data/src/test/assets/transformerdumps/mp4/sample_with_increasing_timestamps_320w_240h.mp4.clipped.dump @@ -0,0 +1,991 @@ +containerMimeType = video/mp4 +format 0: + averageBitrate = 192181 + peakBitrate = 192181 + id = 2 + sampleMimeType = audio/mp4a-latm + codecs = mp4a.40.2 + maxInputSize = 643 + channelCount = 2 + sampleRate = 48000 + language = en + metadata = entries=[TSSE: description=null: value=Lavf58.76.100] + initializationData: + data = length 2, hash 560 +format 1: + id = 1 + sampleMimeType = video/avc + codecs = avc1.42C015 + maxInputSize = 14839 + width = 320 + height = 240 + frameRate = 59.997425 + colorInfo: + colorSpace = 2 + colorRange = 1 + colorTransfer = 3 + hdrStaticInfo = length 0, hash 0 + initializationData: + data = length 31, hash 4B108214 + data = length 9, hash FBA158BB +sample: + trackIndex = 1 + dataHashCode = 983000500 + size = 13539 + isKeyFrame = true + presentationTimeUs = 0 +sample: + trackIndex = 1 + dataHashCode = -1834230781 + size = 32 + isKeyFrame = false + presentationTimeUs = 16666 +sample: + trackIndex = 1 + dataHashCode = 521720738 + size = 1534 + isKeyFrame = false + presentationTimeUs = 33333 +sample: + trackIndex = 1 + dataHashCode = 722836039 + size = 123 + isKeyFrame = false + presentationTimeUs = 50000 +sample: + trackIndex = 1 + dataHashCode = -1702585381 + size = 2061 + isKeyFrame = false + presentationTimeUs = 66666 +sample: + trackIndex = 1 + dataHashCode = -365856396 + size = 147 + isKeyFrame = false + presentationTimeUs = 83333 +sample: + trackIndex = 1 + dataHashCode = 1258185334 + size = 2534 + isKeyFrame = false + presentationTimeUs = 100000 +sample: + trackIndex = 1 + dataHashCode = -179623006 + size = 87 + isKeyFrame = false + presentationTimeUs = 116666 +sample: + trackIndex = 1 + dataHashCode = -541393824 + size = 2762 + isKeyFrame = false + presentationTimeUs = 133333 +sample: + trackIndex = 1 + dataHashCode = -1912932514 + size = 57 + isKeyFrame = false + presentationTimeUs = 150000 +sample: + trackIndex = 1 + dataHashCode = 485634444 + size = 2833 + isKeyFrame = false + presentationTimeUs = 166666 +sample: + trackIndex = 1 + dataHashCode = 570625802 + size = 189 + isKeyFrame = false + presentationTimeUs = 183333 +sample: + trackIndex = 1 + dataHashCode = 1819668957 + size = 3153 + isKeyFrame = false + presentationTimeUs = 200000 +sample: + trackIndex = 1 + dataHashCode = 1004398066 + size = 104 + isKeyFrame = false + presentationTimeUs = 216666 +sample: + trackIndex = 1 + dataHashCode = 2087741113 + size = 2304 + isKeyFrame = false + presentationTimeUs = 233333 +sample: + trackIndex = 1 + dataHashCode = -419782502 + size = 222 + isKeyFrame = false + presentationTimeUs = 250000 +sample: + trackIndex = 1 + dataHashCode = -1867110345 + size = 2306 + isKeyFrame = false + presentationTimeUs = 266666 +sample: + trackIndex = 1 + dataHashCode = 1908323737 + size = 257 + isKeyFrame = false + presentationTimeUs = 283333 +sample: + trackIndex = 1 + dataHashCode = 884063337 + size = 2201 + isKeyFrame = false + presentationTimeUs = 300000 +sample: + trackIndex = 1 + dataHashCode = -1308458590 + size = 174 + isKeyFrame = false + presentationTimeUs = 316666 +sample: + trackIndex = 1 + dataHashCode = -1686938678 + size = 2524 + isKeyFrame = false + presentationTimeUs = 333333 +sample: + trackIndex = 1 + dataHashCode = -1372845971 + size = 171 + isKeyFrame = false + presentationTimeUs = 350000 +sample: + trackIndex = 1 + dataHashCode = 1130876644 + size = 2306 + isKeyFrame = false + presentationTimeUs = 366666 +sample: + trackIndex = 1 + dataHashCode = 1707671352 + size = 188 + isKeyFrame = false + presentationTimeUs = 383333 +sample: + trackIndex = 1 + dataHashCode = 300233313 + size = 2529 + isKeyFrame = false + presentationTimeUs = 400000 +sample: + trackIndex = 1 + dataHashCode = -1284013406 + size = 182 + isKeyFrame = false + presentationTimeUs = 416666 +sample: + trackIndex = 1 + dataHashCode = -2088617828 + size = 2047 + isKeyFrame = false + presentationTimeUs = 433333 +sample: + trackIndex = 1 + dataHashCode = 2116374999 + size = 259 + isKeyFrame = false + presentationTimeUs = 450000 +sample: + trackIndex = 1 + dataHashCode = -2123019940 + size = 2234 + isKeyFrame = false + presentationTimeUs = 466666 +sample: + trackIndex = 1 + dataHashCode = 1901454757 + size = 138 + isKeyFrame = false + presentationTimeUs = 483333 +sample: + trackIndex = 1 + dataHashCode = 1576638059 + size = 2088 + isKeyFrame = false + presentationTimeUs = 500000 +sample: + trackIndex = 1 + dataHashCode = 1120133924 + size = 151 + isKeyFrame = false + presentationTimeUs = 516666 +sample: + trackIndex = 0 + dataHashCode = 620415738 + size = 508 + isKeyFrame = true + presentationTimeUs = 7020 +sample: + trackIndex = 0 + dataHashCode = 33931768 + size = 504 + isKeyFrame = true + presentationTimeUs = 28354 +sample: + trackIndex = 0 + dataHashCode = 800699278 + size = 508 + isKeyFrame = true + presentationTimeUs = 49687 +sample: + trackIndex = 0 + dataHashCode = 584185366 + size = 519 + isKeyFrame = true + presentationTimeUs = 71020 +sample: + trackIndex = 0 + dataHashCode = 1490843354 + size = 528 + isKeyFrame = true + presentationTimeUs = 92354 +sample: + trackIndex = 0 + dataHashCode = -720335181 + size = 511 + isKeyFrame = true + presentationTimeUs = 113687 +sample: + trackIndex = 0 + dataHashCode = 197135781 + size = 523 + isKeyFrame = true + presentationTimeUs = 135020 +sample: + trackIndex = 0 + dataHashCode = 294457020 + size = 511 + isKeyFrame = true + presentationTimeUs = 156354 +sample: + trackIndex = 0 + dataHashCode = 194307558 + size = 503 + isKeyFrame = true + presentationTimeUs = 177687 +sample: + trackIndex = 0 + dataHashCode = 1687202651 + size = 507 + isKeyFrame = true + presentationTimeUs = 199020 +sample: + trackIndex = 0 + dataHashCode = -1695580898 + size = 517 + isKeyFrame = true + presentationTimeUs = 220354 +sample: + trackIndex = 0 + dataHashCode = -1416688734 + size = 510 + isKeyFrame = true + presentationTimeUs = 241687 +sample: + trackIndex = 0 + dataHashCode = -239330254 + size = 511 + isKeyFrame = true + presentationTimeUs = 263020 +sample: + trackIndex = 0 + dataHashCode = 1449437418 + size = 509 + isKeyFrame = true + presentationTimeUs = 284354 +sample: + trackIndex = 0 + dataHashCode = -1480882788 + size = 508 + isKeyFrame = true + presentationTimeUs = 305687 +sample: + trackIndex = 0 + dataHashCode = -1628064098 + size = 511 + isKeyFrame = true + presentationTimeUs = 327020 +sample: + trackIndex = 0 + dataHashCode = 1717254647 + size = 514 + isKeyFrame = true + presentationTimeUs = 348354 +sample: + trackIndex = 0 + dataHashCode = -1317174771 + size = 503 + isKeyFrame = true + presentationTimeUs = 369687 +sample: + trackIndex = 0 + dataHashCode = 1001148219 + size = 510 + isKeyFrame = true + presentationTimeUs = 391020 +sample: + trackIndex = 0 + dataHashCode = 1259307086 + size = 511 + isKeyFrame = true + presentationTimeUs = 412354 +sample: + trackIndex = 0 + dataHashCode = -27251144 + size = 507 + isKeyFrame = true + presentationTimeUs = 433687 +sample: + trackIndex = 0 + dataHashCode = -129676969 + size = 509 + isKeyFrame = true + presentationTimeUs = 455020 +sample: + trackIndex = 0 + dataHashCode = 1228056327 + size = 523 + isKeyFrame = true + presentationTimeUs = 476354 +sample: + trackIndex = 0 + dataHashCode = -1301514722 + size = 501 + isKeyFrame = true + presentationTimeUs = 497687 +sample: + trackIndex = 0 + dataHashCode = 204329022 + size = 514 + isKeyFrame = true + presentationTimeUs = 519020 +sample: + trackIndex = 1 + dataHashCode = 264118578 + size = 2235 + isKeyFrame = false + presentationTimeUs = 533333 +sample: + trackIndex = 1 + dataHashCode = 64254117 + size = 164 + isKeyFrame = false + presentationTimeUs = 550000 +sample: + trackIndex = 1 + dataHashCode = -1000078879 + size = 2231 + isKeyFrame = false + presentationTimeUs = 566666 +sample: + trackIndex = 1 + dataHashCode = 286919946 + size = 123 + isKeyFrame = false + presentationTimeUs = 583333 +sample: + trackIndex = 1 + dataHashCode = -320312658 + size = 2303 + isKeyFrame = false + presentationTimeUs = 600000 +sample: + trackIndex = 1 + dataHashCode = 1057750590 + size = 175 + isKeyFrame = false + presentationTimeUs = 616666 +sample: + trackIndex = 1 + dataHashCode = 1961415074 + size = 2165 + isKeyFrame = false + presentationTimeUs = 633333 +sample: + trackIndex = 1 + dataHashCode = 667267023 + size = 260 + isKeyFrame = false + presentationTimeUs = 650000 +sample: + trackIndex = 1 + dataHashCode = 979033489 + size = 1924 + isKeyFrame = false + presentationTimeUs = 666666 +sample: + trackIndex = 1 + dataHashCode = -1974473017 + size = 286 + isKeyFrame = false + presentationTimeUs = 683333 +sample: + trackIndex = 1 + dataHashCode = -962519103 + size = 1992 + isKeyFrame = false + presentationTimeUs = 700000 +sample: + trackIndex = 1 + dataHashCode = -1312094075 + size = 204 + isKeyFrame = false + presentationTimeUs = 716666 +sample: + trackIndex = 1 + dataHashCode = 2068151127 + size = 1826 + isKeyFrame = false + presentationTimeUs = 733333 +sample: + trackIndex = 1 + dataHashCode = -1531967506 + size = 284 + isKeyFrame = false + presentationTimeUs = 750000 +sample: + trackIndex = 1 + dataHashCode = -778066699 + size = 1940 + isKeyFrame = false + presentationTimeUs = 766666 +sample: + trackIndex = 1 + dataHashCode = -1219952117 + size = 129 + isKeyFrame = false + presentationTimeUs = 783333 +sample: + trackIndex = 1 + dataHashCode = -1218204223 + size = 1947 + isKeyFrame = false + presentationTimeUs = 800000 +sample: + trackIndex = 1 + dataHashCode = -1816247511 + size = 147 + isKeyFrame = false + presentationTimeUs = 816666 +sample: + trackIndex = 1 + dataHashCode = 299686318 + size = 2066 + isKeyFrame = false + presentationTimeUs = 833333 +sample: + trackIndex = 1 + dataHashCode = -1520242765 + size = 185 + isKeyFrame = false + presentationTimeUs = 850000 +sample: + trackIndex = 1 + dataHashCode = -1702498409 + size = 2159 + isKeyFrame = false + presentationTimeUs = 866666 +sample: + trackIndex = 1 + dataHashCode = 345202950 + size = 189 + isKeyFrame = false + presentationTimeUs = 883333 +sample: + trackIndex = 1 + dataHashCode = 220746796 + size = 2098 + isKeyFrame = false + presentationTimeUs = 900000 +sample: + trackIndex = 1 + dataHashCode = -32341189 + size = 159 + isKeyFrame = false + presentationTimeUs = 916666 +sample: + trackIndex = 1 + dataHashCode = -1838476361 + size = 1914 + isKeyFrame = false + presentationTimeUs = 933333 +sample: + trackIndex = 1 + dataHashCode = -1322093590 + size = 99 + isKeyFrame = false + presentationTimeUs = 950000 +sample: + trackIndex = 1 + dataHashCode = -1391064751 + size = 2168 + isKeyFrame = false + presentationTimeUs = 966666 +sample: + trackIndex = 1 + dataHashCode = 1479204931 + size = 129 + isKeyFrame = false + presentationTimeUs = 983333 +sample: + trackIndex = 1 + dataHashCode = 1131230500 + size = 2327 + isKeyFrame = false + presentationTimeUs = 1000000 +sample: + trackIndex = 1 + dataHashCode = -393815961 + size = 160 + isKeyFrame = false + presentationTimeUs = 1016666 +sample: + trackIndex = 1 + dataHashCode = -242739025 + size = 2136 + isKeyFrame = false + presentationTimeUs = 1033333 +sample: + trackIndex = 0 + dataHashCode = 204379389 + size = 504 + isKeyFrame = true + presentationTimeUs = 540354 +sample: + trackIndex = 0 + dataHashCode = 694913274 + size = 508 + isKeyFrame = true + presentationTimeUs = 561687 +sample: + trackIndex = 0 + dataHashCode = 289018778 + size = 513 + isKeyFrame = true + presentationTimeUs = 583020 +sample: + trackIndex = 0 + dataHashCode = -693167785 + size = 517 + isKeyFrame = true + presentationTimeUs = 604354 +sample: + trackIndex = 0 + dataHashCode = 253824480 + size = 510 + isKeyFrame = true + presentationTimeUs = 625687 +sample: + trackIndex = 0 + dataHashCode = -142385998 + size = 516 + isKeyFrame = true + presentationTimeUs = 647020 +sample: + trackIndex = 0 + dataHashCode = 917740295 + size = 506 + isKeyFrame = true + presentationTimeUs = 668354 +sample: + trackIndex = 0 + dataHashCode = -1795733204 + size = 504 + isKeyFrame = true + presentationTimeUs = 689687 +sample: + trackIndex = 0 + dataHashCode = 1282735099 + size = 518 + isKeyFrame = true + presentationTimeUs = 711020 +sample: + trackIndex = 0 + dataHashCode = -834522889 + size = 512 + isKeyFrame = true + presentationTimeUs = 732354 +sample: + trackIndex = 0 + dataHashCode = -1590936932 + size = 506 + isKeyFrame = true + presentationTimeUs = 753687 +sample: + trackIndex = 0 + dataHashCode = -697315454 + size = 529 + isKeyFrame = true + presentationTimeUs = 775020 +sample: + trackIndex = 0 + dataHashCode = -1563590541 + size = 514 + isKeyFrame = true + presentationTimeUs = 796354 +sample: + trackIndex = 0 + dataHashCode = -674722870 + size = 509 + isKeyFrame = true + presentationTimeUs = 817687 +sample: + trackIndex = 0 + dataHashCode = -272827525 + size = 510 + isKeyFrame = true + presentationTimeUs = 839020 +sample: + trackIndex = 0 + dataHashCode = 903683051 + size = 524 + isKeyFrame = true + presentationTimeUs = 860354 +sample: + trackIndex = 0 + dataHashCode = 57039157 + size = 509 + isKeyFrame = true + presentationTimeUs = 881687 +sample: + trackIndex = 0 + dataHashCode = 674330068 + size = 514 + isKeyFrame = true + presentationTimeUs = 903020 +sample: + trackIndex = 0 + dataHashCode = -1896569421 + size = 514 + isKeyFrame = true + presentationTimeUs = 924354 +sample: + trackIndex = 0 + dataHashCode = -837719592 + size = 502 + isKeyFrame = true + presentationTimeUs = 945687 +sample: + trackIndex = 0 + dataHashCode = 1269429850 + size = 507 + isKeyFrame = true + presentationTimeUs = 967020 +sample: + trackIndex = 0 + dataHashCode = -884799857 + size = 497 + isKeyFrame = true + presentationTimeUs = 988354 +sample: + trackIndex = 0 + dataHashCode = -1865947937 + size = 512 + isKeyFrame = true + presentationTimeUs = 1009687 +sample: + trackIndex = 0 + dataHashCode = 1197648682 + size = 500 + isKeyFrame = true + presentationTimeUs = 1031020 +sample: + trackIndex = 1 + dataHashCode = 65238903 + size = 163 + isKeyFrame = false + presentationTimeUs = 1050000 +sample: + trackIndex = 1 + dataHashCode = 1720840922 + size = 2043 + isKeyFrame = false + presentationTimeUs = 1066666 +sample: + trackIndex = 1 + dataHashCode = -1006231050 + size = 178 + isKeyFrame = false + presentationTimeUs = 1083333 +sample: + trackIndex = 1 + dataHashCode = 1742965952 + size = 2022 + isKeyFrame = false + presentationTimeUs = 1100000 +sample: + trackIndex = 1 + dataHashCode = -971065365 + size = 240 + isKeyFrame = false + presentationTimeUs = 1116666 +sample: + trackIndex = 1 + dataHashCode = 1757434551 + size = 1887 + isKeyFrame = false + presentationTimeUs = 1133333 +sample: + trackIndex = 1 + dataHashCode = 1501849116 + size = 252 + isKeyFrame = false + presentationTimeUs = 1150000 +sample: + trackIndex = 1 + dataHashCode = 825501977 + size = 1816 + isKeyFrame = false + presentationTimeUs = 1166666 +sample: + trackIndex = 1 + dataHashCode = -1616223509 + size = 246 + isKeyFrame = false + presentationTimeUs = 1183333 +sample: + trackIndex = 1 + dataHashCode = 457119646 + size = 1817 + isKeyFrame = false + presentationTimeUs = 1200000 +sample: + trackIndex = 1 + dataHashCode = -1382929639 + size = 146 + isKeyFrame = false + presentationTimeUs = 1216666 +sample: + trackIndex = 1 + dataHashCode = -1580853131 + size = 1929 + isKeyFrame = false + presentationTimeUs = 1233333 +sample: + trackIndex = 1 + dataHashCode = 1758706551 + size = 196 + isKeyFrame = false + presentationTimeUs = 1250000 +sample: + trackIndex = 1 + dataHashCode = 207289556 + size = 2154 + isKeyFrame = false + presentationTimeUs = 1266666 +sample: + trackIndex = 1 + dataHashCode = -981284942 + size = 182 + isKeyFrame = false + presentationTimeUs = 1283333 +sample: + trackIndex = 1 + dataHashCode = 855103964 + size = 2144 + isKeyFrame = false + presentationTimeUs = 1300000 +sample: + trackIndex = 1 + dataHashCode = 380479426 + size = 90 + isKeyFrame = false + presentationTimeUs = 1316666 +sample: + trackIndex = 1 + dataHashCode = -1677996152 + size = 2005 + isKeyFrame = false + presentationTimeUs = 1333333 +sample: + trackIndex = 1 + dataHashCode = 1516852008 + size = 156 + isKeyFrame = false + presentationTimeUs = 1350000 +sample: + trackIndex = 1 + dataHashCode = -1602805193 + size = 1772 + isKeyFrame = false + presentationTimeUs = 1366666 +sample: + trackIndex = 1 + dataHashCode = -1720426556 + size = 162 + isKeyFrame = false + presentationTimeUs = 1383333 +sample: + trackIndex = 1 + dataHashCode = -1392260423 + size = 1865 + isKeyFrame = false + presentationTimeUs = 1400000 +sample: + trackIndex = 1 + dataHashCode = -1842432151 + size = 151 + isKeyFrame = false + presentationTimeUs = 1416666 +sample: + trackIndex = 1 + dataHashCode = -537063215 + size = 1848 + isKeyFrame = false + presentationTimeUs = 1433333 +sample: + trackIndex = 1 + dataHashCode = 2089388394 + size = 206 + isKeyFrame = false + presentationTimeUs = 1450000 +sample: + trackIndex = 1 + dataHashCode = -1761777019 + size = 1934 + isKeyFrame = false + presentationTimeUs = 1466666 +sample: + trackIndex = 1 + dataHashCode = 235471194 + size = 119 + isKeyFrame = false + presentationTimeUs = 1483333 +sample: + trackIndex = 0 + dataHashCode = -320096195 + size = 509 + isKeyFrame = true + presentationTimeUs = 1052354 +sample: + trackIndex = 0 + dataHashCode = -744850549 + size = 511 + isKeyFrame = true + presentationTimeUs = 1073687 +sample: + trackIndex = 0 + dataHashCode = 1457899387 + size = 505 + isKeyFrame = true + presentationTimeUs = 1095020 +sample: + trackIndex = 0 + dataHashCode = 168118808 + size = 519 + isKeyFrame = true + presentationTimeUs = 1116354 +sample: + trackIndex = 0 + dataHashCode = 896298799 + size = 506 + isKeyFrame = true + presentationTimeUs = 1137687 +sample: + trackIndex = 0 + dataHashCode = -1766408057 + size = 513 + isKeyFrame = true + presentationTimeUs = 1159020 +sample: + trackIndex = 0 + dataHashCode = 988509435 + size = 517 + isKeyFrame = true + presentationTimeUs = 1180354 +sample: + trackIndex = 0 + dataHashCode = 1031000863 + size = 529 + isKeyFrame = true + presentationTimeUs = 1201687 +sample: + trackIndex = 0 + dataHashCode = 63390943 + size = 517 + isKeyFrame = true + presentationTimeUs = 1223020 +sample: + trackIndex = 0 + dataHashCode = -747883422 + size = 517 + isKeyFrame = true + presentationTimeUs = 1244354 +sample: + trackIndex = 0 + dataHashCode = -1574660470 + size = 526 + isKeyFrame = true + presentationTimeUs = 1265687 +sample: + trackIndex = 0 + dataHashCode = 1371653176 + size = 515 + isKeyFrame = true + presentationTimeUs = 1287020 +sample: + trackIndex = 0 + dataHashCode = -873513581 + size = 503 + isKeyFrame = true + presentationTimeUs = 1308354 +sample: + trackIndex = 0 + dataHashCode = -1886763688 + size = 514 + isKeyFrame = true + presentationTimeUs = 1329687 +sample: + trackIndex = 0 + dataHashCode = 1308763541 + size = 512 + isKeyFrame = true + presentationTimeUs = 1351020 +sample: + trackIndex = 0 + dataHashCode = 490619935 + size = 505 + isKeyFrame = true + presentationTimeUs = 1372354 +sample: + trackIndex = 0 + dataHashCode = -671375789 + size = 512 + isKeyFrame = true + presentationTimeUs = 1393687 +sample: + trackIndex = 0 + dataHashCode = -1950105780 + size = 521 + isKeyFrame = true + presentationTimeUs = 1415020 +sample: + trackIndex = 0 + dataHashCode = -1430221498 + size = 533 + isKeyFrame = true + presentationTimeUs = 1436354 +sample: + trackIndex = 0 + dataHashCode = 529950036 + size = 505 + isKeyFrame = true + presentationTimeUs = 1457687 +sample: + trackIndex = 0 + dataHashCode = 1705899587 + size = 497 + isKeyFrame = true + presentationTimeUs = 1479020 +released = true diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java index 0fc6473e64..94fa717381 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -758,6 +758,7 @@ public final class Transformer { removeAudio, removeVideo, transformationRequest, + mediaItem.clippingConfiguration.startsAtKeyFrame, videoFrameEffects, encoderFactory, decoderFactory, @@ -871,6 +872,7 @@ public final class Transformer { private final boolean removeAudio; private final boolean removeVideo; private final TransformationRequest transformationRequest; + private final boolean clippingStartsAtKeyFrame; private final ImmutableList videoFrameEffects; private final Codec.EncoderFactory encoderFactory; private final Codec.DecoderFactory decoderFactory; @@ -884,6 +886,7 @@ public final class Transformer { boolean removeAudio, boolean removeVideo, TransformationRequest transformationRequest, + boolean clippingStartsAtKeyFrame, ImmutableList videoFrameEffects, Codec.EncoderFactory encoderFactory, Codec.DecoderFactory decoderFactory, @@ -895,6 +898,7 @@ public final class Transformer { this.removeAudio = removeAudio; this.removeVideo = removeVideo; this.transformationRequest = transformationRequest; + this.clippingStartsAtKeyFrame = clippingStartsAtKeyFrame; this.videoFrameEffects = videoFrameEffects; this.encoderFactory = encoderFactory; this.decoderFactory = decoderFactory; @@ -932,6 +936,7 @@ public final class Transformer { muxerWrapper, mediaClock, transformationRequest, + clippingStartsAtKeyFrame, videoFrameEffects, encoderFactory, decoderFactory, diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerVideoRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerVideoRenderer.java index 94bae3a888..0321934a56 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerVideoRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerVideoRenderer.java @@ -35,6 +35,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private static final String TAG = "TVideoRenderer"; private final Context context; + private final boolean clippingStartsAtKeyFrame; private final ImmutableList effects; private final Codec.EncoderFactory encoderFactory; private final Codec.DecoderFactory decoderFactory; @@ -49,6 +50,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; MuxerWrapper muxerWrapper, TransformerMediaClock mediaClock, TransformationRequest transformationRequest, + boolean clippingStartsAtKeyFrame, ImmutableList effects, Codec.EncoderFactory encoderFactory, Codec.DecoderFactory decoderFactory, @@ -57,6 +59,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; Transformer.DebugViewProvider debugViewProvider) { super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest, fallbackListener); this.context = context; + this.clippingStartsAtKeyFrame = clippingStartsAtKeyFrame; this.effects = effects; this.encoderFactory = encoderFactory; this.decoderFactory = decoderFactory; @@ -110,8 +113,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } private boolean shouldPassthrough(Format inputFormat) { - // TODO(b/233988291): Use passthrough pipeline if the clipping start is a key-frame. - if (startPositionOffsetUs != 0) { + if (startPositionOffsetUs != 0 && !clippingStartsAtKeyFrame) { return false; } if (encoderFactory.videoNeedsEncoding()) { diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java index 2b4c23de88..ebd9a0287b 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -73,9 +73,11 @@ import org.robolectric.shadows.ShadowMediaCodecList; @RunWith(AndroidJUnit4.class) public final class TransformerEndToEndTest { - private static final String URI_PREFIX = "asset:///media/"; + private static final String ASSET_URI_PREFIX = "asset:///media/"; private static final String FILE_VIDEO_ONLY = "mp4/sample_18byte_nclx_colr.mp4"; private static final String FILE_AUDIO_VIDEO = "mp4/sample.mp4"; + private static final String FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S = + "mp4/sample_with_increasing_timestamps_320w_240h.mp4"; private static final String FILE_WITH_SUBTITLES = "mkv/sample_with_srt.mkv"; private static final String FILE_WITH_SEF_SLOW_MOTION = "mp4/sample_sef_slow_motion.mp4"; private static final String FILE_AUDIO_UNSUPPORTED_BY_DECODER = "amr/sample_wb.amr"; @@ -109,7 +111,7 @@ public final class TransformerEndToEndTest { @Test public void startTransformation_videoOnlyPassthrough_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -121,7 +123,7 @@ public final class TransformerEndToEndTest { public void startTransformation_audioOnlyPassthrough_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -139,7 +141,7 @@ public final class TransformerEndToEndTest { .setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer .build()) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -151,7 +153,7 @@ public final class TransformerEndToEndTest { @Test public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -159,6 +161,30 @@ public final class TransformerEndToEndTest { DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO)); } + @Test + public void startTransformation_audioAndVideo_withClippingStartAtKeyFrame_completesSuccessfully() + throws Exception { + Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); + MediaItem mediaItem = + new MediaItem.Builder() + .setUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S) + .setClippingConfiguration( + new MediaItem.ClippingConfiguration.Builder() + .setStartPositionMs(12_500) + .setEndPositionMs(14_000) + .setStartsAtKeyFrame(true) + .build()) + .build(); + + transformer.startTransformation(mediaItem, outputPath); + TransformerTestRunner.runUntilCompleted(transformer); + + DumpFileAsserts.assertOutput( + context, + testMuxer, + getDumpFileName(FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S + ".clipped")); + } + @Test public void startTransformation_withSubtitles_completesSuccessfully() throws Exception { Transformer transformer = @@ -166,7 +192,7 @@ public final class TransformerEndToEndTest { .setTransformationRequest( new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build()) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_SUBTITLES); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_WITH_SUBTITLES); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -178,7 +204,7 @@ public final class TransformerEndToEndTest { public void startTransformation_successiveTransformations_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); // Transform first media item. transformer.startTransformation(mediaItem, outputPath); @@ -195,7 +221,7 @@ public final class TransformerEndToEndTest { @Test public void startTransformation_concurrentTransformations_throwsError() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY); transformer.startTransformation(mediaItem, outputPath); @@ -207,7 +233,7 @@ public final class TransformerEndToEndTest { public void startTransformation_removeAudio_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).setRemoveAudio(true).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -220,7 +246,7 @@ public final class TransformerEndToEndTest { public void startTransformation_removeVideo_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).setRemoveVideo(true).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -240,7 +266,7 @@ public final class TransformerEndToEndTest { .addListener(mockListener2) .addListener(mockListener3) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -263,7 +289,7 @@ public final class TransformerEndToEndTest { .setTransformationRequest( // Request transcoding so that decoder is used. new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build()) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER); transformer.startTransformation(mediaItem, outputPath); TransformationException exception = TransformerTestRunner.runUntilError(transformer); @@ -288,7 +314,7 @@ public final class TransformerEndToEndTest { .addListener(mockListener2) .addListener(mockListener3) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -314,7 +340,7 @@ public final class TransformerEndToEndTest { .addListener(mockListener3) .build(); Transformer transformer2 = transformer1.buildUpon().removeListener(mockListener2).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer2.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer2); @@ -331,7 +357,7 @@ public final class TransformerEndToEndTest { .setTransformationRequest( new TransformationRequest.Builder().setFlattenForSlowMotion(true).build()) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_SEF_SLOW_MOTION); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_WITH_SEF_SLOW_MOTION); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -352,7 +378,7 @@ public final class TransformerEndToEndTest { }; Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).addListener(listener).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -374,7 +400,7 @@ public final class TransformerEndToEndTest { MimeTypes.AUDIO_AMR_NB) // unsupported by encoder, supported by muxer .build()) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); transformer.startTransformation(mediaItem, outputPath); TransformationException exception = TransformerTestRunner.runUntilError(transformer); @@ -394,7 +420,7 @@ public final class TransformerEndToEndTest { .setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer .build()) .build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER); transformer.startTransformation(mediaItem, outputPath); TransformationException exception = TransformerTestRunner.runUntilError(transformer); @@ -420,7 +446,7 @@ public final class TransformerEndToEndTest { public void startTransformation_withAudioMuxerFormatUnsupported_completesWithError() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); transformer.startTransformation(mediaItem, outputPath); TransformationException exception = TransformerTestRunner.runUntilError(transformer); @@ -441,7 +467,7 @@ public final class TransformerEndToEndTest { new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build(); Transformer transformer = createTransformerBuilder(/* enableFallback= */ true).addListener(mockListener).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer); @@ -455,7 +481,7 @@ public final class TransformerEndToEndTest { @Test public void startTransformation_afterCancellation_completesSuccessfully() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); transformer.startTransformation(mediaItem, outputPath); transformer.cancel(); @@ -475,7 +501,7 @@ public final class TransformerEndToEndTest { Looper looper = anotherThread.getLooper(); Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).setLooper(looper).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); AtomicReference exception = new AtomicReference<>(); CountDownLatch countDownLatch = new CountDownLatch(1); @@ -500,7 +526,7 @@ public final class TransformerEndToEndTest { @Test public void startTransformation_fromWrongThread_throwsError() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO); HandlerThread anotherThread = new HandlerThread("AnotherThread"); AtomicReference illegalStateException = new AtomicReference<>(); CountDownLatch countDownLatch = new CountDownLatch(1); @@ -527,7 +553,7 @@ public final class TransformerEndToEndTest { @Test public void getProgress_knownDuration_returnsConsistentStates() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY); AtomicInteger previousProgressState = new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY); AtomicBoolean foundInconsistentState = new AtomicBoolean(); @@ -573,7 +599,7 @@ public final class TransformerEndToEndTest { @Test public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY); List progresses = new ArrayList<>(); Handler progressHandler = new Handler(Looper.myLooper()) { @@ -608,7 +634,7 @@ public final class TransformerEndToEndTest { @Test public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY); @Transformer.ProgressState int stateBeforeTransform = transformer.getProgress(progressHolder); transformer.startTransformation(mediaItem, outputPath); @@ -622,7 +648,7 @@ public final class TransformerEndToEndTest { @Test public void getProgress_unknownDuration_returnsConsistentStates() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_UNKNOWN_DURATION); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_UNKNOWN_DURATION); AtomicInteger previousProgressState = new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY); AtomicBoolean foundInconsistentState = new AtomicBoolean(); @@ -689,7 +715,7 @@ public final class TransformerEndToEndTest { @Test public void cancel_afterCompletion_doesNotThrow() throws Exception { Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); - MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY); + MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY); transformer.startTransformation(mediaItem, outputPath); TransformerTestRunner.runUntilCompleted(transformer);