mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Implement trim optimization in Transformer
PiperOrigin-RevId: 584622392
This commit is contained in:
parent
6435ddb89e
commit
2d77e4d22c
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,560 @@
|
|||||||
|
format video:
|
||||||
|
id = 1
|
||||||
|
sampleMimeType = video/avc
|
||||||
|
codecs = avc1.42C015
|
||||||
|
maxInputSize = 14839
|
||||||
|
width = 320
|
||||||
|
height = 240
|
||||||
|
frameRate = 59.997425
|
||||||
|
colorInfo:
|
||||||
|
colorSpace = 2
|
||||||
|
colorRange = 1
|
||||||
|
colorTransfer = 3
|
||||||
|
lumaBitdepth = 8
|
||||||
|
chromaBitdepth = 8
|
||||||
|
metadata = entries=[TSSE: description=null: values=[Lavf58.76.100], Mp4Timestamp: creation time=0, modification time=0, timescale=1000]
|
||||||
|
initializationData:
|
||||||
|
data = length 31, hash 4B108214
|
||||||
|
data = length 9, hash FBA158BB
|
||||||
|
container metadata = entries=[TSSE: description=null: values=[Lavf58.76.100], Mp4Timestamp: creation time=0, modification time=0, timescale=1000]
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 983000500
|
||||||
|
size = 13539
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 0
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1834230781
|
||||||
|
size = 32
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 16666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 521720738
|
||||||
|
size = 1534
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 33333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 722836039
|
||||||
|
size = 123
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 50000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1702585381
|
||||||
|
size = 2061
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 66666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -365856396
|
||||||
|
size = 147
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 83333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1258185334
|
||||||
|
size = 2534
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 100000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -179623006
|
||||||
|
size = 87
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 116666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -541393824
|
||||||
|
size = 2762
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 133333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1912932514
|
||||||
|
size = 57
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 150000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 485634444
|
||||||
|
size = 2833
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 166666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 570625802
|
||||||
|
size = 189
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 183333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1819668957
|
||||||
|
size = 3153
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 200000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1004398066
|
||||||
|
size = 104
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 216666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 2087741113
|
||||||
|
size = 2304
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 233333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -419782502
|
||||||
|
size = 222
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 250000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1867110345
|
||||||
|
size = 2306
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 266666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1908323737
|
||||||
|
size = 257
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 283333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 884063337
|
||||||
|
size = 2201
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 300000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1308458590
|
||||||
|
size = 174
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 316666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1686938678
|
||||||
|
size = 2524
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 333333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1372845971
|
||||||
|
size = 171
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 350000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1130876644
|
||||||
|
size = 2306
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 366666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1707671352
|
||||||
|
size = 188
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 383333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 300233313
|
||||||
|
size = 2529
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 400000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1284013406
|
||||||
|
size = 182
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 416666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -2088617828
|
||||||
|
size = 2047
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 433333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 2116374999
|
||||||
|
size = 259
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 450000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -2123019940
|
||||||
|
size = 2234
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 466666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1901454757
|
||||||
|
size = 138
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 483333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1576638059
|
||||||
|
size = 2088
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 500000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1120133924
|
||||||
|
size = 151
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 516666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 264118578
|
||||||
|
size = 2235
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 533333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 64254117
|
||||||
|
size = 164
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 550000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1000078879
|
||||||
|
size = 2231
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 566666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 286919946
|
||||||
|
size = 123
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 583333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -320312658
|
||||||
|
size = 2303
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 600000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1057750590
|
||||||
|
size = 175
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 616666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1961415074
|
||||||
|
size = 2165
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 633333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 667267023
|
||||||
|
size = 260
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 650000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 979033489
|
||||||
|
size = 1924
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 666666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1974473017
|
||||||
|
size = 286
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 683333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -962519103
|
||||||
|
size = 1992
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 700000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1312094075
|
||||||
|
size = 204
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 716666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 2068151127
|
||||||
|
size = 1826
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 733333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1531967506
|
||||||
|
size = 284
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 750000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -778066699
|
||||||
|
size = 1940
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 766666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1219952117
|
||||||
|
size = 129
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 783333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1218204223
|
||||||
|
size = 1947
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 800000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1816247511
|
||||||
|
size = 147
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 816666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 299686318
|
||||||
|
size = 2066
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 833333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1520242765
|
||||||
|
size = 185
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 850000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1702498409
|
||||||
|
size = 2159
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 866666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 345202950
|
||||||
|
size = 189
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 883333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 220746796
|
||||||
|
size = 2098
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 900000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -32341189
|
||||||
|
size = 159
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 916666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1838476361
|
||||||
|
size = 1914
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 933333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1322093590
|
||||||
|
size = 99
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 950000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1391064751
|
||||||
|
size = 2168
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 966666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1479204931
|
||||||
|
size = 129
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 983333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1131230500
|
||||||
|
size = 2327
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1000000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -393815961
|
||||||
|
size = 160
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1016666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -242739025
|
||||||
|
size = 2136
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1033333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 65238903
|
||||||
|
size = 163
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1050000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1720840922
|
||||||
|
size = 2043
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1066666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1006231050
|
||||||
|
size = 178
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1083333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1742965952
|
||||||
|
size = 2022
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1100000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -971065365
|
||||||
|
size = 240
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1116666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1757434551
|
||||||
|
size = 1887
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1133333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1501849116
|
||||||
|
size = 252
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1150000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 825501977
|
||||||
|
size = 1816
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1166666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1616223509
|
||||||
|
size = 246
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1183333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 457119646
|
||||||
|
size = 1817
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1200000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1382929639
|
||||||
|
size = 146
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1216666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1580853131
|
||||||
|
size = 1929
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1233333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1758706551
|
||||||
|
size = 196
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1250000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 207289556
|
||||||
|
size = 2154
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1266666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -981284942
|
||||||
|
size = 182
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1283333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 855103964
|
||||||
|
size = 2144
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1300000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 380479426
|
||||||
|
size = 90
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1316666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1677996152
|
||||||
|
size = 2005
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1333333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 1516852008
|
||||||
|
size = 156
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1350000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1602805193
|
||||||
|
size = 1772
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1366666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1720426556
|
||||||
|
size = 162
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1383333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1392260423
|
||||||
|
size = 1865
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1400000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1842432151
|
||||||
|
size = 151
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1416666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -537063215
|
||||||
|
size = 1848
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1433333
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 2089388394
|
||||||
|
size = 206
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1450000
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = -1761777019
|
||||||
|
size = 1934
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1466666
|
||||||
|
sample:
|
||||||
|
trackType = video
|
||||||
|
dataHashCode = 235471194
|
||||||
|
size = 119
|
||||||
|
isKeyFrame = false
|
||||||
|
presentationTimeUs = 1483333
|
||||||
|
released = true
|
@ -0,0 +1,31 @@
|
|||||||
|
format audio:
|
||||||
|
averageBitrate = 131072
|
||||||
|
sampleMimeType = audio/mp4a-latm
|
||||||
|
channelCount = 1
|
||||||
|
sampleRate = 44100
|
||||||
|
pcmEncoding = 2
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = -8136122
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 0
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 1750866613
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 100000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = -1100753636
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 200000
|
||||||
|
sample:
|
||||||
|
trackType = audio
|
||||||
|
dataHashCode = 507833230
|
||||||
|
size = 8820
|
||||||
|
isKeyFrame = true
|
||||||
|
presentationTimeUs = 300000
|
||||||
|
released = true
|
@ -16,7 +16,9 @@
|
|||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||||
|
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||||
|
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.ColorInfo;
|
import androidx.media3.common.ColorInfo;
|
||||||
@ -24,6 +26,10 @@ import androidx.media3.common.MediaItem;
|
|||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
@ -46,6 +52,7 @@ public final class ExportResult {
|
|||||||
private int width;
|
private int width;
|
||||||
private int videoFrameCount;
|
private int videoFrameCount;
|
||||||
@Nullable private String videoEncoderName;
|
@Nullable private String videoEncoderName;
|
||||||
|
private @OptimizationResult int optimizationResult;
|
||||||
@Nullable private ExportException exportException;
|
@Nullable private ExportException exportException;
|
||||||
|
|
||||||
/** Creates a builder. */
|
/** Creates a builder. */
|
||||||
@ -192,6 +199,21 @@ public final class ExportResult {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets {@link OptimizationResult} to indicate an optimization as been successful, or has failed
|
||||||
|
* and normal export proceeded instead.
|
||||||
|
*
|
||||||
|
* <p>The default value is {@link #OPTIMIZATION_NONE}.
|
||||||
|
*
|
||||||
|
* @param optimizationResult The {@link OptimizationResult}.
|
||||||
|
* @return This {@link Builder}.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setOptimizationResult(@OptimizationResult int optimizationResult) {
|
||||||
|
this.optimizationResult = optimizationResult;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Sets the {@link ExportException} that caused the export to fail. */
|
/** Sets the {@link ExportException} that caused the export to fail. */
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public Builder setExportException(@Nullable ExportException exportException) {
|
public Builder setExportException(@Nullable ExportException exportException) {
|
||||||
@ -215,6 +237,7 @@ public final class ExportResult {
|
|||||||
width,
|
width,
|
||||||
videoFrameCount,
|
videoFrameCount,
|
||||||
videoEncoderName,
|
videoEncoderName,
|
||||||
|
optimizationResult,
|
||||||
exportException);
|
exportException);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,6 +286,38 @@ public final class ExportResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the result of an optimized operation, such as {@link
|
||||||
|
* Transformer.Builder#experimentalSetTrimOptimizationEnabled}. One of {@link #OPTIMIZATION_NONE},
|
||||||
|
* {@link #OPTIMIZATION_SUCCEEDED}, {@link #OPTIMIZATION_FAILED_NO_VIDEO_TRACK_TO_TRIM} or {@link
|
||||||
|
* #OPTIMIZATION_FAILED_EXTRACTION_FAILED}.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@Target(TYPE_USE)
|
||||||
|
@IntDef({
|
||||||
|
OPTIMIZATION_NONE,
|
||||||
|
OPTIMIZATION_SUCCEEDED,
|
||||||
|
OPTIMIZATION_FAILED_NO_VIDEO_TRACK_TO_TRIM,
|
||||||
|
OPTIMIZATION_FAILED_EXTRACTION_FAILED
|
||||||
|
})
|
||||||
|
@interface OptimizationResult {}
|
||||||
|
|
||||||
|
/** No optimizations were applied since none were requested. */
|
||||||
|
public static final int OPTIMIZATION_NONE = 0;
|
||||||
|
|
||||||
|
/** The optimization was successfully applied. */
|
||||||
|
public static final int OPTIMIZATION_SUCCEEDED = 1;
|
||||||
|
|
||||||
|
/** The trim optimization failed because there was no video track. Normal export proceeded. */
|
||||||
|
public static final int OPTIMIZATION_FAILED_NO_VIDEO_TRACK_TO_TRIM = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optimization failed because mp4 metadata extraction failed (possibly because the file
|
||||||
|
* wasn't an mp4 file). Normal export proceeded.
|
||||||
|
*/
|
||||||
|
public static final int OPTIMIZATION_FAILED_EXTRACTION_FAILED = 3;
|
||||||
|
|
||||||
/** The list of {@linkplain ProcessedInput processed inputs}. */
|
/** The list of {@linkplain ProcessedInput processed inputs}. */
|
||||||
public final ImmutableList<ProcessedInput> processedInputs;
|
public final ImmutableList<ProcessedInput> processedInputs;
|
||||||
|
|
||||||
@ -306,6 +361,9 @@ public final class ExportResult {
|
|||||||
/** The name of the video encoder used, or {@code null} if none were used. */
|
/** The name of the video encoder used, or {@code null} if none were used. */
|
||||||
@Nullable public final String videoEncoderName;
|
@Nullable public final String videoEncoderName;
|
||||||
|
|
||||||
|
/** The result of any requested optimizations. */
|
||||||
|
public final @OptimizationResult int optimizationResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ExportException} that caused the export to fail, or {@code null} if the export was a
|
* The {@link ExportException} that caused the export to fail, or {@code null} if the export was a
|
||||||
* success.
|
* success.
|
||||||
@ -326,6 +384,7 @@ public final class ExportResult {
|
|||||||
int width,
|
int width,
|
||||||
int videoFrameCount,
|
int videoFrameCount,
|
||||||
@Nullable String videoEncoderName,
|
@Nullable String videoEncoderName,
|
||||||
|
@OptimizationResult int optimizationResult,
|
||||||
@Nullable ExportException exportException) {
|
@Nullable ExportException exportException) {
|
||||||
this.processedInputs = processedInputs;
|
this.processedInputs = processedInputs;
|
||||||
this.durationMs = durationMs;
|
this.durationMs = durationMs;
|
||||||
@ -340,6 +399,7 @@ public final class ExportResult {
|
|||||||
this.width = width;
|
this.width = width;
|
||||||
this.videoFrameCount = videoFrameCount;
|
this.videoFrameCount = videoFrameCount;
|
||||||
this.videoEncoderName = videoEncoderName;
|
this.videoEncoderName = videoEncoderName;
|
||||||
|
this.optimizationResult = optimizationResult;
|
||||||
this.exportException = exportException;
|
this.exportException = exportException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@ import static androidx.media3.common.util.Assertions.checkArgument;
|
|||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
|
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
|
||||||
|
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_FAILED_EXTRACTION_FAILED;
|
||||||
|
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_FAILED_NO_VIDEO_TRACK_TO_TRIM;
|
||||||
|
import static androidx.media3.transformer.TransmuxTranscodeHelper.buildNewCompositionWithClipTimes;
|
||||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -99,6 +102,7 @@ public final class Transformer {
|
|||||||
private boolean removeAudio;
|
private boolean removeAudio;
|
||||||
private boolean removeVideo;
|
private boolean removeVideo;
|
||||||
private boolean flattenForSlowMotion;
|
private boolean flattenForSlowMotion;
|
||||||
|
private boolean trimOptimizationEnabled;
|
||||||
private ListenerSet<Transformer.Listener> listeners;
|
private ListenerSet<Transformer.Listener> listeners;
|
||||||
private AssetLoader.@MonotonicNonNull Factory assetLoaderFactory;
|
private AssetLoader.@MonotonicNonNull Factory assetLoaderFactory;
|
||||||
private AudioMixer.Factory audioMixerFactory;
|
private AudioMixer.Factory audioMixerFactory;
|
||||||
@ -138,6 +142,7 @@ public final class Transformer {
|
|||||||
this.videoEffects = transformer.videoEffects;
|
this.videoEffects = transformer.videoEffects;
|
||||||
this.removeAudio = transformer.removeAudio;
|
this.removeAudio = transformer.removeAudio;
|
||||||
this.removeVideo = transformer.removeVideo;
|
this.removeVideo = transformer.removeVideo;
|
||||||
|
this.trimOptimizationEnabled = transformer.trimOptimizationEnabled;
|
||||||
this.listeners = transformer.listeners;
|
this.listeners = transformer.listeners;
|
||||||
this.assetLoaderFactory = transformer.assetLoaderFactory;
|
this.assetLoaderFactory = transformer.assetLoaderFactory;
|
||||||
this.audioMixerFactory = transformer.audioMixerFactory;
|
this.audioMixerFactory = transformer.audioMixerFactory;
|
||||||
@ -282,6 +287,39 @@ public final class Transformer {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: b/304476154 - Support audio and progress updates in trim optimization.
|
||||||
|
/**
|
||||||
|
* Sets whether to attempt to optimize trims from the start of the {@link EditedMediaItem} by
|
||||||
|
* transcoding as little of the file as possible and transmuxing the rest.
|
||||||
|
*
|
||||||
|
* <p>This optimization has the following limitations:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Only supported for single-asset (i.e. only one {@link EditedMediaItem} in the whole
|
||||||
|
* {@link Composition}) exports of mp4 files.
|
||||||
|
* <li>Not guaranteed to work with any effects.
|
||||||
|
* <li>Video track only (removes audio from the file).
|
||||||
|
* <li>Progress updates will be unavailable.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>{@link ExportResult#optimizationResult} will indicate whether the optimization was
|
||||||
|
* applied.
|
||||||
|
*
|
||||||
|
* <p>This process relies on the given {@linkplain #setEncoderFactory EncoderFactory} providing
|
||||||
|
* the right encoder level and profiles when transcoding, so that the transcoded and transmuxed
|
||||||
|
* segments of the file can be stitched together. If the file segments can't be stitched
|
||||||
|
* together, the {@linkplain #start(Composition, String) export operation} will throw an
|
||||||
|
* exception.
|
||||||
|
*
|
||||||
|
* @param enabled Whether to enable trim optimization.
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder experimentalSetTrimOptimizationEnabled(boolean enabled) {
|
||||||
|
trimOptimizationEnabled = enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #addListener(Listener)}, {@link #removeListener(Listener)} or {@link
|
* @deprecated Use {@link #addListener(Listener)}, {@link #removeListener(Listener)} or {@link
|
||||||
* #removeAllListeners()} instead.
|
* #removeAllListeners()} instead.
|
||||||
@ -497,6 +535,7 @@ public final class Transformer {
|
|||||||
removeAudio,
|
removeAudio,
|
||||||
removeVideo,
|
removeVideo,
|
||||||
flattenForSlowMotion,
|
flattenForSlowMotion,
|
||||||
|
trimOptimizationEnabled,
|
||||||
listeners,
|
listeners,
|
||||||
assetLoaderFactory,
|
assetLoaderFactory,
|
||||||
audioMixerFactory,
|
audioMixerFactory,
|
||||||
@ -668,7 +707,9 @@ public final class Transformer {
|
|||||||
TRANSFORMER_STATE_REMUX_PROCESSED_VIDEO,
|
TRANSFORMER_STATE_REMUX_PROCESSED_VIDEO,
|
||||||
TRANSFORMER_STATE_PROCESS_REMAINING_VIDEO,
|
TRANSFORMER_STATE_PROCESS_REMAINING_VIDEO,
|
||||||
TRANSFORMER_STATE_PROCESS_AUDIO,
|
TRANSFORMER_STATE_PROCESS_AUDIO,
|
||||||
TRANSFORMER_STATE_COPY_OUTPUT
|
TRANSFORMER_STATE_COPY_OUTPUT,
|
||||||
|
TRANSFORMER_STATE_TRANSCODE_VIDEO_START,
|
||||||
|
TRANSFORMER_STATE_TRANSMUX_REMAINING_VIDEO
|
||||||
})
|
})
|
||||||
private @interface TransformerState {}
|
private @interface TransformerState {}
|
||||||
|
|
||||||
@ -677,6 +718,8 @@ public final class Transformer {
|
|||||||
private static final int TRANSFORMER_STATE_PROCESS_REMAINING_VIDEO = 2;
|
private static final int TRANSFORMER_STATE_PROCESS_REMAINING_VIDEO = 2;
|
||||||
private static final int TRANSFORMER_STATE_PROCESS_AUDIO = 3;
|
private static final int TRANSFORMER_STATE_PROCESS_AUDIO = 3;
|
||||||
private static final int TRANSFORMER_STATE_COPY_OUTPUT = 4;
|
private static final int TRANSFORMER_STATE_COPY_OUTPUT = 4;
|
||||||
|
private static final int TRANSFORMER_STATE_TRANSCODE_VIDEO_START = 5;
|
||||||
|
private static final int TRANSFORMER_STATE_TRANSMUX_REMAINING_VIDEO = 6;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final TransformationRequest transformationRequest;
|
private final TransformationRequest transformationRequest;
|
||||||
@ -685,6 +728,7 @@ public final class Transformer {
|
|||||||
private final boolean removeAudio;
|
private final boolean removeAudio;
|
||||||
private final boolean removeVideo;
|
private final boolean removeVideo;
|
||||||
private final boolean flattenForSlowMotion;
|
private final boolean flattenForSlowMotion;
|
||||||
|
private final boolean trimOptimizationEnabled;
|
||||||
private final ListenerSet<Transformer.Listener> listeners;
|
private final ListenerSet<Transformer.Listener> listeners;
|
||||||
@Nullable private final AssetLoader.Factory assetLoaderFactory;
|
@Nullable private final AssetLoader.Factory assetLoaderFactory;
|
||||||
private final AudioMixer.Factory audioMixerFactory;
|
private final AudioMixer.Factory audioMixerFactory;
|
||||||
@ -704,10 +748,12 @@ public final class Transformer {
|
|||||||
private @MonotonicNonNull String outputFilePath;
|
private @MonotonicNonNull String outputFilePath;
|
||||||
private @MonotonicNonNull String oldFilePath;
|
private @MonotonicNonNull String oldFilePath;
|
||||||
private @TransformerState int transformerState;
|
private @TransformerState int transformerState;
|
||||||
private ExportResumeHelper.@MonotonicNonNull ResumeMetadata resumeMetadata;
|
private TransmuxTranscodeHelper.@MonotonicNonNull ResumeMetadata resumeMetadata;
|
||||||
private @MonotonicNonNull ListenableFuture<ExportResumeHelper.ResumeMetadata>
|
private @MonotonicNonNull ListenableFuture<TransmuxTranscodeHelper.ResumeMetadata>
|
||||||
getResumeMetadataFuture;
|
getResumeMetadataFuture;
|
||||||
private @MonotonicNonNull ListenableFuture<Void> copyOutputFuture;
|
private @MonotonicNonNull ListenableFuture<Void> copyOutputFuture;
|
||||||
|
private @MonotonicNonNull ListenableFuture<Mp4MetadataInfo> getMp4MetadataInfoFuture;
|
||||||
|
private @MonotonicNonNull Mp4MetadataInfo mp4MetadataInfo;
|
||||||
|
|
||||||
private Transformer(
|
private Transformer(
|
||||||
Context context,
|
Context context,
|
||||||
@ -717,6 +763,7 @@ public final class Transformer {
|
|||||||
boolean removeAudio,
|
boolean removeAudio,
|
||||||
boolean removeVideo,
|
boolean removeVideo,
|
||||||
boolean flattenForSlowMotion,
|
boolean flattenForSlowMotion,
|
||||||
|
boolean trimOptimizationEnabled,
|
||||||
ListenerSet<Listener> listeners,
|
ListenerSet<Listener> listeners,
|
||||||
@Nullable AssetLoader.Factory assetLoaderFactory,
|
@Nullable AssetLoader.Factory assetLoaderFactory,
|
||||||
AudioMixer.Factory audioMixerFactory,
|
AudioMixer.Factory audioMixerFactory,
|
||||||
@ -734,6 +781,7 @@ public final class Transformer {
|
|||||||
this.removeAudio = removeAudio;
|
this.removeAudio = removeAudio;
|
||||||
this.removeVideo = removeVideo;
|
this.removeVideo = removeVideo;
|
||||||
this.flattenForSlowMotion = flattenForSlowMotion;
|
this.flattenForSlowMotion = flattenForSlowMotion;
|
||||||
|
this.trimOptimizationEnabled = trimOptimizationEnabled;
|
||||||
this.listeners = listeners;
|
this.listeners = listeners;
|
||||||
this.assetLoaderFactory = assetLoaderFactory;
|
this.assetLoaderFactory = assetLoaderFactory;
|
||||||
this.audioMixerFactory = audioMixerFactory;
|
this.audioMixerFactory = audioMixerFactory;
|
||||||
@ -868,12 +916,17 @@ public final class Transformer {
|
|||||||
* @throws IllegalStateException If an export is already in progress.
|
* @throws IllegalStateException If an export is already in progress.
|
||||||
*/
|
*/
|
||||||
public void start(Composition composition, String path) {
|
public void start(Composition composition, String path) {
|
||||||
|
verifyApplicationThread();
|
||||||
initialize(composition, path);
|
initialize(composition, path);
|
||||||
|
if (!trimOptimizationEnabled || isMultiAsset()) {
|
||||||
startInternal(
|
startInternal(
|
||||||
composition,
|
composition,
|
||||||
new MuxerWrapper(path, muxerFactory, componentListener, MuxerWrapper.MUXER_MODE_DEFAULT),
|
new MuxerWrapper(path, muxerFactory, componentListener, MuxerWrapper.MUXER_MODE_DEFAULT),
|
||||||
componentListener,
|
componentListener,
|
||||||
/* initialTimestampOffsetUs= */ 0);
|
/* initialTimestampOffsetUs= */ 0);
|
||||||
|
} else {
|
||||||
|
transcodeVideoBeforeFirstSyncSampleAfterTrimStartTime();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1026,6 +1079,10 @@ public final class Transformer {
|
|||||||
* <li>The output is an MP4 file.
|
* <li>The output is an MP4 file.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
* <p>Note that export optimizations (such as {@linkplain
|
||||||
|
* Builder#experimentalSetTrimOptimizationEnabled trim optimization}) will not be applied upon
|
||||||
|
* resumption.
|
||||||
|
*
|
||||||
* @param composition The {@link Composition} to resume export.
|
* @param composition The {@link Composition} to resume export.
|
||||||
* @param outputFilePath The path to the output file. This must be different from the output path
|
* @param outputFilePath The path to the output file. This must be different from the output path
|
||||||
* of the cancelled export.
|
* of the cancelled export.
|
||||||
@ -1060,13 +1117,13 @@ public final class Transformer {
|
|||||||
private void remuxProcessedVideo() {
|
private void remuxProcessedVideo() {
|
||||||
transformerState = TRANSFORMER_STATE_REMUX_PROCESSED_VIDEO;
|
transformerState = TRANSFORMER_STATE_REMUX_PROCESSED_VIDEO;
|
||||||
getResumeMetadataFuture =
|
getResumeMetadataFuture =
|
||||||
ExportResumeHelper.getResumeMetadataAsync(
|
TransmuxTranscodeHelper.getResumeMetadataAsync(
|
||||||
context, checkNotNull(oldFilePath), checkNotNull(composition));
|
context, checkNotNull(oldFilePath), checkNotNull(composition));
|
||||||
Futures.addCallback(
|
Futures.addCallback(
|
||||||
getResumeMetadataFuture,
|
getResumeMetadataFuture,
|
||||||
new FutureCallback<ExportResumeHelper.ResumeMetadata>() {
|
new FutureCallback<TransmuxTranscodeHelper.ResumeMetadata>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(ExportResumeHelper.ResumeMetadata resumeMetadata) {
|
public void onSuccess(TransmuxTranscodeHelper.ResumeMetadata resumeMetadata) {
|
||||||
// If there is no video track to remux or the last sync sample is actually the first
|
// If there is no video track to remux or the last sync sample is actually the first
|
||||||
// sample, then start the normal Export.
|
// sample, then start the normal Export.
|
||||||
if (resumeMetadata.lastSyncSampleTimestampUs == C.TIME_UNSET
|
if (resumeMetadata.lastSyncSampleTimestampUs == C.TIME_UNSET
|
||||||
@ -1085,7 +1142,7 @@ public final class Transformer {
|
|||||||
MuxerWrapper.MUXER_MODE_MUX_PARTIAL_VIDEO);
|
MuxerWrapper.MUXER_MODE_MUX_PARTIAL_VIDEO);
|
||||||
|
|
||||||
startInternal(
|
startInternal(
|
||||||
ExportResumeHelper.createVideoOnlyComposition(
|
TransmuxTranscodeHelper.createVideoOnlyComposition(
|
||||||
oldFilePath,
|
oldFilePath,
|
||||||
/* clippingEndPositionUs= */ resumeMetadata.lastSyncSampleTimestampUs),
|
/* clippingEndPositionUs= */ resumeMetadata.lastSyncSampleTimestampUs),
|
||||||
checkNotNull(remuxingMuxerWrapper),
|
checkNotNull(remuxingMuxerWrapper),
|
||||||
@ -1105,7 +1162,7 @@ public final class Transformer {
|
|||||||
private void processRemainingVideo() {
|
private void processRemainingVideo() {
|
||||||
transformerState = TRANSFORMER_STATE_PROCESS_REMAINING_VIDEO;
|
transformerState = TRANSFORMER_STATE_PROCESS_REMAINING_VIDEO;
|
||||||
Composition videoOnlyComposition =
|
Composition videoOnlyComposition =
|
||||||
ExportResumeHelper.buildUponComposition(
|
TransmuxTranscodeHelper.buildUponComposition(
|
||||||
checkNotNull(composition),
|
checkNotNull(composition),
|
||||||
/* removeAudio= */ true,
|
/* removeAudio= */ true,
|
||||||
/* removeVideo= */ false,
|
/* removeVideo= */ false,
|
||||||
@ -1125,7 +1182,7 @@ public final class Transformer {
|
|||||||
transformerState = TRANSFORMER_STATE_PROCESS_AUDIO;
|
transformerState = TRANSFORMER_STATE_PROCESS_AUDIO;
|
||||||
|
|
||||||
startInternal(
|
startInternal(
|
||||||
ExportResumeHelper.createAudioTranscodeAndVideoTransmuxComposition(
|
TransmuxTranscodeHelper.createAudioTranscodeAndVideoTransmuxComposition(
|
||||||
checkNotNull(composition), checkNotNull(outputFilePath)),
|
checkNotNull(composition), checkNotNull(outputFilePath)),
|
||||||
new MuxerWrapper(
|
new MuxerWrapper(
|
||||||
checkNotNull(oldFilePath),
|
checkNotNull(oldFilePath),
|
||||||
@ -1140,7 +1197,7 @@ public final class Transformer {
|
|||||||
private void copyOutput() {
|
private void copyOutput() {
|
||||||
transformerState = TRANSFORMER_STATE_COPY_OUTPUT;
|
transformerState = TRANSFORMER_STATE_COPY_OUTPUT;
|
||||||
copyOutputFuture =
|
copyOutputFuture =
|
||||||
ExportResumeHelper.copyFileAsync(
|
TransmuxTranscodeHelper.copyFileAsync(
|
||||||
new File(checkNotNull(oldFilePath)), new File(checkNotNull(outputFilePath)));
|
new File(checkNotNull(oldFilePath)), new File(checkNotNull(outputFilePath)));
|
||||||
|
|
||||||
Futures.addCallback(
|
Futures.addCallback(
|
||||||
@ -1161,6 +1218,102 @@ public final class Transformer {
|
|||||||
applicationHandler::post);
|
applicationHandler::post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void transcodeVideoBeforeFirstSyncSampleAfterTrimStartTime() {
|
||||||
|
transformerState = TRANSFORMER_STATE_TRANSCODE_VIDEO_START;
|
||||||
|
MediaItem firstMediaItem =
|
||||||
|
checkNotNull(composition).sequences.get(0).editedMediaItems.get(0).mediaItem;
|
||||||
|
long trimStartTimeUs = firstMediaItem.clippingConfiguration.startPositionUs;
|
||||||
|
getMp4MetadataInfoFuture =
|
||||||
|
TransmuxTranscodeHelper.getMp4MetadataInfo(
|
||||||
|
context,
|
||||||
|
checkNotNull(firstMediaItem.localConfiguration).uri.toString(),
|
||||||
|
trimStartTimeUs);
|
||||||
|
Futures.addCallback(
|
||||||
|
getMp4MetadataInfoFuture,
|
||||||
|
new FutureCallback<Mp4MetadataInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Mp4MetadataInfo mp4MetadataInfo) {
|
||||||
|
if (mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs == C.TIME_UNSET) {
|
||||||
|
exportResultBuilder.setOptimizationResult(OPTIMIZATION_FAILED_NO_VIDEO_TRACK_TO_TRIM);
|
||||||
|
processFullInput();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs == trimStartTimeUs) {
|
||||||
|
Transformer.this.composition =
|
||||||
|
buildNewCompositionWithClipTimes(
|
||||||
|
composition,
|
||||||
|
trimStartTimeUs,
|
||||||
|
firstMediaItem.clippingConfiguration.endPositionUs,
|
||||||
|
mp4MetadataInfo.durationUs,
|
||||||
|
/* startsAtKeyFrame= */ true);
|
||||||
|
processFullInput();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transformer.this.mp4MetadataInfo = mp4MetadataInfo;
|
||||||
|
Composition trancodeComposition =
|
||||||
|
buildNewCompositionWithClipTimes(
|
||||||
|
composition,
|
||||||
|
trimStartTimeUs,
|
||||||
|
mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs,
|
||||||
|
mp4MetadataInfo.durationUs,
|
||||||
|
/* startsAtKeyFrame= */ false);
|
||||||
|
|
||||||
|
// TODO: b/304476154 - Check for cases where we shouldTranscode anyway and proceed with
|
||||||
|
// normal export instead.
|
||||||
|
remuxingMuxerWrapper =
|
||||||
|
new MuxerWrapper(
|
||||||
|
checkNotNull(outputFilePath),
|
||||||
|
muxerFactory,
|
||||||
|
componentListener,
|
||||||
|
MuxerWrapper.MUXER_MODE_MUX_PARTIAL_VIDEO);
|
||||||
|
startInternal(
|
||||||
|
trancodeComposition,
|
||||||
|
remuxingMuxerWrapper,
|
||||||
|
componentListener,
|
||||||
|
/* initialTimestampOffsetUs= */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
exportResultBuilder.setOptimizationResult(OPTIMIZATION_FAILED_EXTRACTION_FAILED);
|
||||||
|
processFullInput();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
applicationHandler::post);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transmuxRemainingVideo() {
|
||||||
|
transformerState = TRANSFORMER_STATE_TRANSMUX_REMAINING_VIDEO;
|
||||||
|
// TODO: b/304476154 - check original file format against transcode file format here to fail
|
||||||
|
// fast if necessary.
|
||||||
|
MediaItem firstMediaItem =
|
||||||
|
checkNotNull(composition).sequences.get(0).editedMediaItems.get(0).mediaItem;
|
||||||
|
long trimStartTimeUs = firstMediaItem.clippingConfiguration.startPositionUs;
|
||||||
|
long trimEndTimeUs = firstMediaItem.clippingConfiguration.endPositionUs;
|
||||||
|
checkNotNull(mp4MetadataInfo);
|
||||||
|
Composition transmuxComposition =
|
||||||
|
buildNewCompositionWithClipTimes(
|
||||||
|
composition,
|
||||||
|
mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs,
|
||||||
|
trimEndTimeUs,
|
||||||
|
mp4MetadataInfo.durationUs,
|
||||||
|
/* startsAtKeyFrame= */ true);
|
||||||
|
checkNotNull(remuxingMuxerWrapper);
|
||||||
|
remuxingMuxerWrapper.changeToAppendVideoMode();
|
||||||
|
startInternal(
|
||||||
|
transmuxComposition,
|
||||||
|
remuxingMuxerWrapper,
|
||||||
|
componentListener,
|
||||||
|
/* initialTimestampOffsetUs= */ mp4MetadataInfo.firstSyncSampleTimestampUsAfterTimeUs
|
||||||
|
- trimStartTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMultiAsset() {
|
||||||
|
return checkNotNull(composition).sequences.size() > 1
|
||||||
|
|| composition.sequences.get(0).editedMediaItems.size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyApplicationThread() {
|
private void verifyApplicationThread() {
|
||||||
if (Looper.myLooper() != looper) {
|
if (Looper.myLooper() != looper) {
|
||||||
throw new IllegalStateException("Transformer is accessed on the wrong thread.");
|
throw new IllegalStateException("Transformer is accessed on the wrong thread.");
|
||||||
@ -1173,7 +1326,6 @@ public final class Transformer {
|
|||||||
ComponentListener componentListener,
|
ComponentListener componentListener,
|
||||||
long initialTimestampOffsetUs) {
|
long initialTimestampOffsetUs) {
|
||||||
checkArgument(composition.effects.audioProcessors.isEmpty());
|
checkArgument(composition.effects.audioProcessors.isEmpty());
|
||||||
verifyApplicationThread();
|
|
||||||
checkState(transformerInternal == null, "There is already an export in progress.");
|
checkState(transformerInternal == null, "There is already an export in progress.");
|
||||||
TransformationRequest transformationRequest = this.transformationRequest;
|
TransformationRequest transformationRequest = this.transformationRequest;
|
||||||
if (composition.hdrMode != Composition.HDR_MODE_KEEP_HDR) {
|
if (composition.hdrMode != Composition.HDR_MODE_KEEP_HDR) {
|
||||||
@ -1209,7 +1361,7 @@ public final class Transformer {
|
|||||||
debugViewProvider,
|
debugViewProvider,
|
||||||
clock,
|
clock,
|
||||||
initialTimestampOffsetUs,
|
initialTimestampOffsetUs,
|
||||||
/* matchInitializationData= */ false);
|
/* matchInitializationData= */ trimOptimizationEnabled);
|
||||||
transformerInternal.start();
|
transformerInternal.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,6 +1410,11 @@ public final class Transformer {
|
|||||||
processAudio();
|
processAudio();
|
||||||
} else if (transformerState == TRANSFORMER_STATE_PROCESS_AUDIO) {
|
} else if (transformerState == TRANSFORMER_STATE_PROCESS_AUDIO) {
|
||||||
copyOutput();
|
copyOutput();
|
||||||
|
} else if (transformerState == TRANSFORMER_STATE_TRANSCODE_VIDEO_START) {
|
||||||
|
transmuxRemainingVideo();
|
||||||
|
} else if (transformerState == TRANSFORMER_STATE_TRANSMUX_REMAINING_VIDEO) {
|
||||||
|
exportResultBuilder.setOptimizationResult(ExportResult.OPTIMIZATION_SUCCEEDED);
|
||||||
|
onExportCompletedWithSuccess();
|
||||||
} else {
|
} else {
|
||||||
onExportCompletedWithSuccess();
|
onExportCompletedWithSuccess();
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ import java.io.OutputStream;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Utility methods for resuming an export. */
|
/** Utility methods used in transmux-transcode exports. */
|
||||||
/* package */ final class ExportResumeHelper {
|
/* package */ final class TransmuxTranscodeHelper {
|
||||||
|
|
||||||
/** Provides metadata required to resume an export. */
|
/** Provides metadata required to resume an export. */
|
||||||
public static final class ResumeMetadata {
|
public static final class ResumeMetadata {
|
||||||
@ -59,7 +59,59 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExportResumeHelper() {}
|
public static ListenableFuture<Mp4MetadataInfo> getMp4MetadataInfo(
|
||||||
|
Context context, String filePath, long timeUs) {
|
||||||
|
SettableFuture<Mp4MetadataInfo> mp4MetadataInfoSettableFuture = SettableFuture.create();
|
||||||
|
new Thread("TransmuxTranscodeHelper:Mp4MetadataInfo") {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
mp4MetadataInfoSettableFuture.set(Mp4MetadataInfo.create(context, filePath, timeUs));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
mp4MetadataInfoSettableFuture.setException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
return mp4MetadataInfoSettableFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Composition buildNewCompositionWithClipTimes(
|
||||||
|
Composition oldComposition,
|
||||||
|
long startTimeUs,
|
||||||
|
long endTimeUs,
|
||||||
|
long mediaDurationUs,
|
||||||
|
boolean startsAtKeyFrame) {
|
||||||
|
EditedMediaItem firstEditedMediaItem = oldComposition.sequences.get(0).editedMediaItems.get(0);
|
||||||
|
|
||||||
|
MediaItem.ClippingConfiguration clippingConfiguration =
|
||||||
|
new MediaItem.ClippingConfiguration.Builder()
|
||||||
|
.setStartPositionUs(startTimeUs)
|
||||||
|
.setEndPositionUs(endTimeUs)
|
||||||
|
.setStartsAtKeyFrame(startsAtKeyFrame)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MediaItem mediaItem =
|
||||||
|
firstEditedMediaItem
|
||||||
|
.mediaItem
|
||||||
|
.buildUpon()
|
||||||
|
.setClippingConfiguration(clippingConfiguration)
|
||||||
|
.build();
|
||||||
|
EditedMediaItem editedMediaItem =
|
||||||
|
firstEditedMediaItem
|
||||||
|
.buildUpon()
|
||||||
|
.setMediaItem(mediaItem)
|
||||||
|
.setDurationUs(mediaDurationUs)
|
||||||
|
// TODO: b/304476154 - Support audio in trim optimization.
|
||||||
|
.setRemoveAudio(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return oldComposition
|
||||||
|
.buildUpon()
|
||||||
|
.setSequences(ImmutableList.of(new EditedMediaItemSequence(editedMediaItem)))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TransmuxTranscodeHelper() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a video only {@link Composition} from the given {@code filePath} and {@code
|
* Returns a video only {@link Composition} from the given {@code filePath} and {@code
|
||||||
@ -94,7 +146,7 @@ import java.util.List;
|
|||||||
public static Composition createAudioTranscodeAndVideoTransmuxComposition(
|
public static Composition createAudioTranscodeAndVideoTransmuxComposition(
|
||||||
Composition composition, String videoFilePath) {
|
Composition composition, String videoFilePath) {
|
||||||
Composition audioOnlyComposition =
|
Composition audioOnlyComposition =
|
||||||
ExportResumeHelper.buildUponComposition(
|
TransmuxTranscodeHelper.buildUponComposition(
|
||||||
checkNotNull(composition),
|
checkNotNull(composition),
|
||||||
/* removeAudio= */ false,
|
/* removeAudio= */ false,
|
||||||
/* removeVideo= */ true,
|
/* removeVideo= */ true,
|
||||||
@ -203,7 +255,7 @@ import java.util.List;
|
|||||||
public static ListenableFuture<ResumeMetadata> getResumeMetadataAsync(
|
public static ListenableFuture<ResumeMetadata> getResumeMetadataAsync(
|
||||||
Context context, String filePath, Composition composition) {
|
Context context, String filePath, Composition composition) {
|
||||||
SettableFuture<ResumeMetadata> resumeMetadataSettableFuture = SettableFuture.create();
|
SettableFuture<ResumeMetadata> resumeMetadataSettableFuture = SettableFuture.create();
|
||||||
new Thread("ExportResumeHelper:ResumeMetadata") {
|
new Thread("TransmuxTranscodeHelper:ResumeMetadata") {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -256,7 +308,7 @@ import java.util.List;
|
|||||||
/** Copies {@link File} content from source to destination asynchronously. */
|
/** Copies {@link File} content from source to destination asynchronously. */
|
||||||
public static ListenableFuture<Void> copyFileAsync(File source, File destination) {
|
public static ListenableFuture<Void> copyFileAsync(File source, File destination) {
|
||||||
SettableFuture<Void> copyFileSettableFuture = SettableFuture.create();
|
SettableFuture<Void> copyFileSettableFuture = SettableFuture.create();
|
||||||
new Thread("ExportResumeHelper:CopyFile") {
|
new Thread("TransmuxTranscodeHelper:CopyFile") {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (copyFileSettableFuture.isCancelled()) {
|
if (copyFileSettableFuture.isCancelled()) {
|
@ -152,6 +152,87 @@ public final class MediaItemExportTest {
|
|||||||
/* modifications...= */ "clipped"));
|
/* modifications...= */ "clipped"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void start_trimOptimizationEnabled_clippingConfigurationUnset_outputMatchesOriginal()
|
||||||
|
throws Exception {
|
||||||
|
Transformer transformer =
|
||||||
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false)
|
||||||
|
.experimentalSetTrimOptimizationEnabled(true)
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
transformer.start(mediaItem, outputDir.newFile().getPath());
|
||||||
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
|
assertThat(exportResult.optimizationResult).isEqualTo(ExportResult.OPTIMIZATION_NONE);
|
||||||
|
// Asserts against file generated when experimentalSetTrimOptimizationEnabled is set to false.
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(/* originalFileName= */ FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void start_trimOptimizationEnabled_withClippingStartAtKeyFrame_completesSuccessfully()
|
||||||
|
throws Exception {
|
||||||
|
Transformer transformer =
|
||||||
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false)
|
||||||
|
.experimentalSetTrimOptimizationEnabled(true)
|
||||||
|
.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)
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
transformer.start(mediaItem, outputDir.newFile().getPath());
|
||||||
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
|
assertThat(exportResult.optimizationResult).isEqualTo(ExportResult.OPTIMIZATION_NONE);
|
||||||
|
// TODO: b/304476154 - When trim optimization supports audio, remove trim optimization specific
|
||||||
|
// file and use the pre-existing clipped file made from normal export path.
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(
|
||||||
|
/* originalFileName= */ FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S,
|
||||||
|
/* modifications...= */ "trimOptimizedClippedAtKeyFrame"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void start_trimOptimizationEnabled_fileNotMp4_fallbackToNormalExport() throws Exception {
|
||||||
|
Transformer transformer =
|
||||||
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false)
|
||||||
|
.experimentalSetTrimOptimizationEnabled(true)
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri(ASSET_URI_PREFIX + FILE_AUDIO_RAW)
|
||||||
|
.setClippingConfiguration(
|
||||||
|
new MediaItem.ClippingConfiguration.Builder()
|
||||||
|
.setStartPositionUs(500_000)
|
||||||
|
.setEndPositionUs(900_000)
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
transformer.start(mediaItem, outputDir.newFile().getPath());
|
||||||
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
|
assertThat(exportResult.optimizationResult).isNotEqualTo(ExportResult.OPTIMIZATION_SUCCEEDED);
|
||||||
|
assertThat(exportResult.optimizationResult).isNotEqualTo(ExportResult.OPTIMIZATION_NONE);
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(/* originalFileName= */ FILE_AUDIO_RAW, /* modifications...= */ "clipped"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void start_withSubtitlesVideoOnly_completesSuccessfully() throws Exception {
|
public void start_withSubtitlesVideoOnly_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
|
@ -29,6 +29,7 @@ import static androidx.media3.transformer.TestUtil.createPitchChangingAudioProce
|
|||||||
import static androidx.media3.transformer.TestUtil.createTransformerBuilder;
|
import static androidx.media3.transformer.TestUtil.createTransformerBuilder;
|
||||||
import static androidx.media3.transformer.TestUtil.getDumpFileName;
|
import static androidx.media3.transformer.TestUtil.getDumpFileName;
|
||||||
import static androidx.media3.transformer.TestUtil.removeEncodersAndDecoders;
|
import static androidx.media3.transformer.TestUtil.removeEncodersAndDecoders;
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
@ -177,6 +178,56 @@ public final class SequenceExportTest {
|
|||||||
"transmux"));
|
"transmux"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
start_trimOptimizationEnabled_concatenateClippedMediaItemsWithTransmux_completesSuccessfully()
|
||||||
|
throws Exception {
|
||||||
|
Transformer transformer =
|
||||||
|
createTransformerBuilder(muxerFactory, /* enableFallback= */ false)
|
||||||
|
.experimentalSetTrimOptimizationEnabled(true)
|
||||||
|
.build();
|
||||||
|
MediaItem.ClippingConfiguration clippingConfiguration1 =
|
||||||
|
new MediaItem.ClippingConfiguration.Builder()
|
||||||
|
.setStartPositionMs(0) // Corresponds to key frame.
|
||||||
|
.setEndPositionMs(500)
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem1 =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S)
|
||||||
|
.setClippingConfiguration(clippingConfiguration1)
|
||||||
|
.build();
|
||||||
|
EditedMediaItem editedMediaItem1 = new EditedMediaItem.Builder(mediaItem1).build();
|
||||||
|
MediaItem.ClippingConfiguration clippingConfiguration2 =
|
||||||
|
new MediaItem.ClippingConfiguration.Builder()
|
||||||
|
.setStartPositionMs(12_500) // Corresponds to key frame.
|
||||||
|
.setEndPositionMs(14_000)
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem2 =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S)
|
||||||
|
.setClippingConfiguration(clippingConfiguration2)
|
||||||
|
.build();
|
||||||
|
EditedMediaItem editedMediaItem2 = new EditedMediaItem.Builder(mediaItem2).build();
|
||||||
|
Composition composition =
|
||||||
|
new Composition.Builder(new EditedMediaItemSequence(editedMediaItem1, editedMediaItem2))
|
||||||
|
.setTransmuxAudio(true)
|
||||||
|
.setTransmuxVideo(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
transformer.start(composition, outputDir.newFile().getPath());
|
||||||
|
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
|
||||||
|
|
||||||
|
assertThat(exportResult.optimizationResult).isEqualTo(ExportResult.OPTIMIZATION_NONE);
|
||||||
|
DumpFileAsserts.assertOutput(
|
||||||
|
context,
|
||||||
|
muxerFactory.getCreatedMuxer(),
|
||||||
|
getDumpFileName(
|
||||||
|
/* originalFileName= */ FILE_AUDIO_VIDEO_INCREASING_TIMESTAMPS_15S,
|
||||||
|
/* modifications...= */ "clipped",
|
||||||
|
"clipped",
|
||||||
|
"transmux"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void concatenateAudioAndSilence_withTransmuxVideo_completesSuccessfully()
|
public void concatenateAudioAndSilence_withTransmuxVideo_completesSuccessfully()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user