Throw when inferred sample MIME type is not supported by the muxer.
This is better than silently dropping tracks as done previously. Later, we will implement fallback to transcoding to a supported MIME type. PiperOrigin-RevId: 418006258
This commit is contained in:
parent
036a28b292
commit
fe1ffdb959
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,10 @@
|
||||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
channelCount = 1
|
||||
sampleRate = 44100
|
||||
pcmEncoding = 2
|
||||
format 1:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.640034
|
||||
@ -11,181 +16,355 @@ format 0:
|
||||
data = length 30, hash F6F3D010
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -252482306
|
||||
size = 36477
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 67864034
|
||||
size = 5341
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 67000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 897273234
|
||||
size = 596
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 33000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -1549870586
|
||||
size = 7704
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 200000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 672384813
|
||||
size = 989
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 133000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -988996493
|
||||
size = 721
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 100000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 1711151377
|
||||
size = 519
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 167000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -506806036
|
||||
size = 6160
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 333000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 1902167649
|
||||
size = 953
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 267000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 2054873212
|
||||
size = 620
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 233000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 1556608231
|
||||
size = 405
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -1648978019
|
||||
size = 4852
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 433000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -484808327
|
||||
size = 547
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -20706048
|
||||
size = 570
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 2085064574
|
||||
size = 5525
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 555688582
|
||||
size = 416
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 2000837254
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 4717
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1593942879
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 9456
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 587837542
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 14196
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1836423877
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 18935
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 874705099
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 23674
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -269206181
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 28413
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -58682425
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 33152
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -859796970
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 37892
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 711911523
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 42631
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -694513071
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 47370
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1124371059
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 52109
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 297166745
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 56849
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -937110638
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 61588
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1050158990
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 66327
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1109510229
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 71066
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1297086772
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 75805
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1739939803
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 80545
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1149727930
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 85284
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1627652713
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 90023
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -551926260
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 94762
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 45987178
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 99502
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -903675808
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 104241
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -755916991
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 108980
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1355207303
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 113719
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -975703389
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 118459
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1933194670
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 123198
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -565778989
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 127937
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1454083383
|
||||
size = 418
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 132676
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -637074022
|
||||
size = 1082
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -1824027029
|
||||
size = 807
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -1701945306
|
||||
size = 744
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 533000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -952425536
|
||||
size = 4732
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -1978031576
|
||||
size = 1004
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 633000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -2128215508
|
||||
size = 794
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -259850011
|
||||
size = 645
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 1920983928
|
||||
size = 2684
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 833000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 1100642337
|
||||
size = 787
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 1544917830
|
||||
size = 649
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 733000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -116205995
|
||||
size = 509
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = 696343585
|
||||
size = 1226
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 967000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -644371190
|
||||
size = 898
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 900000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -1606273467
|
||||
size = 476
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
trackIndex = 1
|
||||
dataHashCode = -571265861
|
||||
size = 486
|
||||
isKeyFrame = false
|
||||
|
@ -0,0 +1,198 @@
|
||||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.64001F
|
||||
maxInputSize = 36722
|
||||
width = 1080
|
||||
height = 720
|
||||
frameRate = 29.970028
|
||||
colorInfo:
|
||||
colorSpace = 1
|
||||
colorRange = 2
|
||||
colorTransfer = 3
|
||||
hdrStaticInfo = length 0, hash 0
|
||||
initializationData:
|
||||
data = length 29, hash 4746B5D9
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -770308242
|
||||
size = 36692
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -732087136
|
||||
size = 5312
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 66733
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 468156717
|
||||
size = 599
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 33366
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1150349584
|
||||
size = 7735
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 200200
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1443582006
|
||||
size = 987
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 133466
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -310585145
|
||||
size = 673
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 100100
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 807460688
|
||||
size = 523
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 166833
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1936487090
|
||||
size = 6061
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 333666
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -32297181
|
||||
size = 992
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 266933
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1529616406
|
||||
size = 623
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 233566
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1949198785
|
||||
size = 421
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300300
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -147880287
|
||||
size = 4899
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 433766
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1369083472
|
||||
size = 568
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400400
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 965782073
|
||||
size = 620
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367033
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -261176150
|
||||
size = 5450
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567233
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1830836678
|
||||
size = 1051
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500500
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1767407540
|
||||
size = 874
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467133
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 918440283
|
||||
size = 781
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 533866
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1408463661
|
||||
size = 4725
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700700
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1569455924
|
||||
size = 1022
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 633966
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1723778407
|
||||
size = 790
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600600
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1578275472
|
||||
size = 610
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667333
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1989768395
|
||||
size = 2751
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 834166
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1215674502
|
||||
size = 745
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767433
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -814473606
|
||||
size = 621
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 734066
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 498370894
|
||||
size = 505
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800800
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1051506468
|
||||
size = 1268
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 967633
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1025604144
|
||||
size = 880
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 900900
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -913586520
|
||||
size = 530
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867533
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1340459242
|
||||
size = 568
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 934266
|
||||
released = true
|
@ -161,6 +161,16 @@ public final class TransformationException extends Exception {
|
||||
/** Caused by an audio processor initialization failure. */
|
||||
public static final int ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED = 6001;
|
||||
|
||||
// Muxing errors (7xxx).
|
||||
|
||||
/**
|
||||
* Caused by an output sample MIME type inferred from the input not being supported by the muxer.
|
||||
*
|
||||
* <p>Use {@link TransformationRequest.Builder#setAudioMimeType(String)} or {@link
|
||||
* TransformationRequest.Builder#setVideoMimeType(String)} to transcode to a supported MIME type.
|
||||
*/
|
||||
public static final int ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED = 7001;
|
||||
|
||||
private static final ImmutableBiMap<String, @ErrorCode Integer> NAME_TO_ERROR_CODE =
|
||||
new ImmutableBiMap.Builder<String, @ErrorCode Integer>()
|
||||
.put("ERROR_CODE_FAILED_RUNTIME_CHECK", ERROR_CODE_FAILED_RUNTIME_CHECK)
|
||||
@ -182,6 +192,9 @@ public final class TransformationException extends Exception {
|
||||
.put("ERROR_CODE_GL_INIT_FAILED", ERROR_CODE_GL_INIT_FAILED)
|
||||
.put("ERROR_CODE_GL_PROCESSING_FAILED", ERROR_CODE_GL_PROCESSING_FAILED)
|
||||
.put("ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED", ERROR_CODE_AUDIO_PROCESSOR_INIT_FAILED)
|
||||
.put(
|
||||
"ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED",
|
||||
ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED)
|
||||
.buildOrThrow();
|
||||
|
||||
/** Returns the {@code errorCode} for a given name. */
|
||||
@ -232,6 +245,17 @@ public final class TransformationException extends Exception {
|
||||
componentName + " error, audio_format = " + audioFormat, cause, errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for a muxer related exception.
|
||||
*
|
||||
* @param cause The cause of the failure.
|
||||
* @param errorCode See {@link #errorCode}.
|
||||
* @return The created instance.
|
||||
*/
|
||||
/* package */ static TransformationException createForMuxer(Throwable cause, int errorCode) {
|
||||
return new TransformationException("Muxer error", cause, errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for an unexpected exception.
|
||||
*
|
||||
|
@ -808,13 +808,9 @@ public final class Transformer {
|
||||
@Override
|
||||
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||
if (muxerWrapper.getTrackCount() == 0) {
|
||||
// TODO(b/209469847): Do not silently drop unsupported tracks and throw a more specific
|
||||
// exception earlier.
|
||||
handleTransformationEnded(
|
||||
TransformationException.createForUnexpected(
|
||||
new IllegalStateException(
|
||||
"The output does not contain any tracks. Check that at least one of the input"
|
||||
+ " sample formats is supported.")));
|
||||
new IllegalStateException("The output does not contain any tracks.")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package androidx.media3.transformer;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@ -57,26 +58,46 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
this.transformationRequest = transformationRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the renderer supports the track type of the given input format.
|
||||
*
|
||||
* @param inputFormat The input format.
|
||||
* @return The {@link Capabilities} for this format.
|
||||
* @throws ExoPlaybackException If the muxer does not support the output sample MIME type derived
|
||||
* from the input {@code format} and {@link TransformationRequest}.
|
||||
*/
|
||||
@Override
|
||||
@C.FormatSupport
|
||||
public final int supportsFormat(Format format) {
|
||||
@Nullable String sampleMimeType = format.sampleMimeType;
|
||||
if (MimeTypes.getTrackType(sampleMimeType) != getTrackType()) {
|
||||
@Capabilities
|
||||
public final int supportsFormat(Format inputFormat) throws ExoPlaybackException {
|
||||
@Nullable String inputSampleMimeType = inputFormat.sampleMimeType;
|
||||
if (inputSampleMimeType == null
|
||||
|| MimeTypes.getTrackType(inputSampleMimeType) != getTrackType()) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
||||
} else if ((MimeTypes.isAudio(sampleMimeType)
|
||||
&& muxerWrapper.supportsSampleMimeType(
|
||||
transformationRequest.audioMimeType == null
|
||||
? sampleMimeType
|
||||
: transformationRequest.audioMimeType))
|
||||
|| (MimeTypes.isVideo(sampleMimeType)
|
||||
&& muxerWrapper.supportsSampleMimeType(
|
||||
transformationRequest.videoMimeType == null
|
||||
? sampleMimeType
|
||||
: transformationRequest.videoMimeType))) {
|
||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
||||
} else {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
|
||||
}
|
||||
|
||||
// If the output sample MIME type is given in the transformationRequest it has already been
|
||||
// validated by the builder.
|
||||
if (MimeTypes.isAudio(inputSampleMimeType) && transformationRequest.audioMimeType != null) {
|
||||
checkState(muxerWrapper.supportsSampleMimeType(transformationRequest.audioMimeType));
|
||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
||||
}
|
||||
if (MimeTypes.isVideo(inputSampleMimeType) && transformationRequest.videoMimeType != null) {
|
||||
checkState(muxerWrapper.supportsSampleMimeType(transformationRequest.videoMimeType));
|
||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
||||
}
|
||||
|
||||
// When the output sample MIME type is not given in the transformationRequest, it is inferred
|
||||
// from the input.
|
||||
if (muxerWrapper.supportsSampleMimeType(inputSampleMimeType)) {
|
||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
||||
}
|
||||
throw wrapTransformationException(
|
||||
TransformationException.createForMuxer(
|
||||
new IllegalArgumentException(
|
||||
"The sample MIME inferred from the input is not supported by the muxer. "
|
||||
+ "Input sample MIME type: "
|
||||
+ inputSampleMimeType),
|
||||
TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -103,16 +124,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
while (feedMuxerFromPipeline() || samplePipeline.processData() || feedPipelineFromInput()) {}
|
||||
} catch (TransformationException e) {
|
||||
// Transformer extracts the TransformationException from this ExoPlaybackException again. This
|
||||
// temporary wrapping is needed due to the dependence on ExoPlayer's BaseRenderer.
|
||||
throw ExoPlaybackException.createForRenderer(
|
||||
e,
|
||||
"Transformer",
|
||||
getIndex(),
|
||||
/* rendererFormat= */ null,
|
||||
C.FORMAT_HANDLED,
|
||||
/* isRecoverable= */ false,
|
||||
PlaybackException.ERROR_CODE_UNSPECIFIED);
|
||||
throw wrapTransformationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,4 +238,23 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExoPlaybackException} wrapping the {@link TransformationException}.
|
||||
*
|
||||
* <p>This temporary wrapping is needed due to the dependence on ExoPlayer's BaseRenderer. {@link
|
||||
* Transformer} extracts the {@link TransformationException} from this {@link
|
||||
* ExoPlaybackException} again.
|
||||
*/
|
||||
private ExoPlaybackException wrapTransformationException(
|
||||
TransformationException transformationException) {
|
||||
return ExoPlaybackException.createForRenderer(
|
||||
transformationException,
|
||||
"Transformer",
|
||||
getIndex(),
|
||||
/* rendererFormat= */ null,
|
||||
C.FORMAT_HANDLED,
|
||||
/* isRecoverable= */ false,
|
||||
PlaybackException.ERROR_CODE_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
@ -62,12 +62,14 @@ import org.robolectric.shadows.ShadowMediaCodec;
|
||||
public final class TransformerTest {
|
||||
|
||||
private static final String URI_PREFIX = "asset:///media/";
|
||||
private static final String FILE_VIDEO_ONLY = "mkv/sample.mkv";
|
||||
private static final String FILE_AUDIO_ONLY = "amr/sample_nb.amr";
|
||||
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_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_WITH_ALL_SAMPLE_FORMATS_UNSUPPORTED = "mp4/sample_ac3.mp4";
|
||||
private static final String FILE_AUDIO_UNSUPPORTED_BY_DECODER = "amr/sample_wb.amr";
|
||||
private static final String FILE_AUDIO_UNSUPPORTED_BY_ENCODER = "amr/sample_nb.amr";
|
||||
private static final String FILE_AUDIO_UNSUPPORTED_BY_MUXER = "mp4/sample_ac3.mp4";
|
||||
private static final String FILE_VIDEO_UNSUPPORTED = "vp9/bear-vp9.webm";
|
||||
private static final String FILE_UNKNOWN_DURATION = "mp4/sample_fragmented.mp4";
|
||||
public static final String DUMP_FILE_OUTPUT_DIRECTORY = "transformerdumps";
|
||||
public static final String DUMP_FILE_EXTENSION = "dump";
|
||||
@ -94,7 +96,7 @@ public final class TransformerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_videoOnly_completesSuccessfully() throws Exception {
|
||||
public void startTransformation_videoOnlyPassthrough_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setClock(clock)
|
||||
@ -109,18 +111,40 @@ public final class TransformerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_audioOnly_completesSuccessfully() throws Exception {
|
||||
public void startTransformation_audioOnlyPassthrough_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_ONLY));
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_ENCODER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_audioOnlyTranscoding_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.setTransformationRequest(
|
||||
new TransformationRequest.Builder()
|
||||
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
|
||||
.build())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_ENCODER + ".aac"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -144,6 +168,8 @@ public final class TransformerTest {
|
||||
new Transformer.Builder(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.setTransformationRequest(
|
||||
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_SUBTITLES);
|
||||
|
||||
@ -161,7 +187,7 @@ public final class TransformerTest {
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
|
||||
// Transform first media item.
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
@ -172,7 +198,7 @@ public final class TransformerTest {
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -246,10 +272,11 @@ public final class TransformerTest {
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.setTransformationRequest(
|
||||
new TransformationRequest.Builder()
|
||||
.setAudioMimeType(MimeTypes.AUDIO_AMR_WB) // unsupported encoder MIME type
|
||||
.setAudioMimeType(
|
||||
MimeTypes.AUDIO_AMR_NB) // unsupported by encoder, supported by muxer
|
||||
.build())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformationException exception = TransformerTestRunner.runUntilError(transformer);
|
||||
@ -268,10 +295,10 @@ public final class TransformerTest {
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.setTransformationRequest(
|
||||
new TransformationRequest.Builder()
|
||||
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported encoder MIME type
|
||||
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
|
||||
.build())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_ALL_SAMPLE_FORMATS_UNSUPPORTED);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformationException exception = TransformerTestRunner.runUntilError(transformer);
|
||||
@ -315,15 +342,41 @@ public final class TransformerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_withAllSampleFormatsUnsupported_completesWithError()
|
||||
public void startTransformation_withAudioMuxerFormatUnsupported_completesWithError()
|
||||
throws Exception {
|
||||
Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_ALL_SAMPLE_FORMATS_UNSUPPORTED);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformationException exception = TransformerTestRunner.runUntilError(transformer);
|
||||
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalStateException.class);
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||
assertThat(exception).hasCauseThat().hasMessageThat().contains("audio");
|
||||
assertThat(exception.errorCode)
|
||||
.isEqualTo(TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_withVideoMuxerFormatUnsupported_completesWithError()
|
||||
throws Exception {
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_UNSUPPORTED);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformationException exception = TransformerTestRunner.runUntilError(transformer);
|
||||
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||
assertThat(exception).hasCauseThat().hasMessageThat().contains("video");
|
||||
assertThat(exception.errorCode)
|
||||
.isEqualTo(TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -333,7 +386,7 @@ public final class TransformerTest {
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
transformer.cancel();
|
||||
@ -343,7 +396,7 @@ public final class TransformerTest {
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -357,7 +410,7 @@ public final class TransformerTest {
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
AtomicReference<Exception> exception = new AtomicReference<>();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
||||
@ -376,13 +429,13 @@ public final class TransformerTest {
|
||||
countDownLatch.await();
|
||||
|
||||
assertThat(exception.get()).isNull();
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_ONLY));
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_fromWrongThread_throwsError() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
||||
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
@ -609,6 +662,7 @@ public final class TransformerTest {
|
||||
/* outputBufferSize= */ 10_000,
|
||||
/* codec= */ (in, out) -> out.put(in));
|
||||
ShadowMediaCodec.addDecoder(MimeTypes.AUDIO_AAC, codecConfig);
|
||||
ShadowMediaCodec.addDecoder(MimeTypes.AUDIO_AC3, codecConfig);
|
||||
ShadowMediaCodec.addDecoder(MimeTypes.AUDIO_AMR_NB, codecConfig);
|
||||
ShadowMediaCodec.addEncoder(MimeTypes.AUDIO_AAC, codecConfig);
|
||||
|
||||
@ -632,8 +686,9 @@ public final class TransformerTest {
|
||||
throw new IllegalArgumentException("Format unsupported");
|
||||
}
|
||||
});
|
||||
ShadowMediaCodec.addDecoder(MimeTypes.AUDIO_AC3, throwingCodecConfig);
|
||||
ShadowMediaCodec.addEncoder(MimeTypes.AUDIO_AMR_WB, throwingCodecConfig);
|
||||
|
||||
ShadowMediaCodec.addDecoder(MimeTypes.AUDIO_AMR_WB, throwingCodecConfig);
|
||||
ShadowMediaCodec.addEncoder(MimeTypes.AUDIO_AMR_NB, throwingCodecConfig);
|
||||
ShadowMediaCodec.addEncoder(MimeTypes.VIDEO_H263, throwingCodecConfig);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user