Check the MIME types Media3Engine hands Transformer, and the claim above them
Both tables decide what codec ends up in the user's file, and neither was exercised. Point H265 at VIDEO_H264 and every hardware HEVC export writes H.264 into a file the user asked to be H.265: Transformer does as told, the export succeeds, and the only symptom is a codec nobody chose. One arm carried an assertion rather than a value -- "Never reached: only an Encode plan consults this, and COPY/NONE are not Encode" -- which is a claim about callers parked in a branch of a callee. It is true, and nothing checked it, so it would have gone on reading as true after it stopped being. Proved instead: CopyPlanner answers both codecs before the Encode branch and its fallback draws from ContainerCapabilities.encodableVideo, which contains neither, so a sweep over every spec the planner can be handed asserts no Encode plan carries COPY or NONE. Counters guard the sweep, because `as? Encode ?: let` asserts nothing at all for a Drop or Copy plan. The audio sibling claim did not survive intact. "MP3 and FLAC have no Android encoder; the router routes them to FFmpeg" is true and incomplete: one rule, `audioEncode !in MEDIA3_AUDIO`, diverts Vorbis by identical logic, so three of the six encodable codecs never reach the table. VORBIS -> AUDIO_VORBIS is a correct mapping for a request Transformer is never given. The arm stays -- a right answer in unreachable code costs nothing -- and the comment now says so. The tables are asked of the router's decisions rather than of its codec sets, because the comments claim behaviour and a set can be right while the rule reading it is wrong. Both move to an internal companion object so a JVM test can reach them without constructing an engine, which would start a real HandlerThread to answer an enum lookup; #57's precedent, and the JVM test source set is a friend of main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,31 +138,6 @@ class Media3Engine(private val context: Context) : HardwareTranscoder {
|
||||
.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Media3 encodes only H.264 and H.265 of the codecs this app offers.
|
||||
*
|
||||
* VP8/VP9/AV1 targets never reach here — the router sends them to FFmpeg because
|
||||
* `Transformer.setVideoMimeType` rejects them — so anything unexpected returns null and lets
|
||||
* Transformer pick, rather than silently substituting H.265 the way the old mapping did.
|
||||
*/
|
||||
private fun videoMimeTypeFor(codec: VideoCodec): String? = when (codec) {
|
||||
VideoCodec.H264 -> MimeTypes.VIDEO_H264
|
||||
VideoCodec.H265 -> MimeTypes.VIDEO_H265
|
||||
// Never reached: only an Encode plan consults this, and COPY/NONE are not Encode.
|
||||
VideoCodec.COPY, VideoCodec.NONE -> null
|
||||
VideoCodec.VP8, VideoCodec.VP9, VideoCodec.AV1 -> null
|
||||
}
|
||||
|
||||
private fun audioMimeTypeFor(codec: AudioCodec): String? = when (codec) {
|
||||
AudioCodec.AAC -> MimeTypes.AUDIO_AAC
|
||||
AudioCodec.OPUS -> MimeTypes.AUDIO_OPUS
|
||||
AudioCodec.VORBIS -> MimeTypes.AUDIO_VORBIS
|
||||
AudioCodec.PCM -> MimeTypes.AUDIO_RAW
|
||||
AudioCodec.COPY, AudioCodec.NONE -> null
|
||||
// MP3 and FLAC have no Android encoder; the router routes them to FFmpeg.
|
||||
AudioCodec.MP3, AudioCodec.FLAC -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls export progress on the Transformer's own thread.
|
||||
*
|
||||
@@ -192,7 +167,57 @@ class Media3Engine(private val context: Context) : HardwareTranscoder {
|
||||
thread.quitSafely()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
/**
|
||||
* The progress interval, and the two enum-to-MIME tables.
|
||||
*
|
||||
* The tables are pure functions of a codec enum, so they sit here rather than on the instance:
|
||||
* a JVM test can then exercise every arm without constructing an engine, which would start a
|
||||
* real [HandlerThread] to answer a lookup. `internal` rather than `private` for the reason
|
||||
* `MainActivity`'s `Destination` records — the JVM test source set is a friend of `main`, so
|
||||
* these stay invisible to anything outside the module.
|
||||
*/
|
||||
internal companion object {
|
||||
const val PROGRESS_INTERVAL_MS = 250L
|
||||
|
||||
/**
|
||||
* Media3 encodes only H.264 and H.265 of the codecs this app offers.
|
||||
*
|
||||
* VP8/VP9/AV1 targets never reach here — the router sends them to FFmpeg because
|
||||
* `Transformer.setVideoMimeType` rejects them — so anything unexpected returns null and
|
||||
* lets Transformer pick, rather than silently substituting H.265 as the old mapping did.
|
||||
*/
|
||||
internal fun videoMimeTypeFor(codec: VideoCodec): String? = when (codec) {
|
||||
VideoCodec.H264 -> MimeTypes.VIDEO_H264
|
||||
VideoCodec.H265 -> MimeTypes.VIDEO_H265
|
||||
// Never reached, and no longer only asserted: `Media3EngineMimeTypesTest` drives
|
||||
// `CopyPlanner` over every spec it can be handed and shows that no Encode plan carries
|
||||
// either, which is what turns "COPY/NONE are not Encode" into a checked claim.
|
||||
VideoCodec.COPY, VideoCodec.NONE -> null
|
||||
VideoCodec.VP8, VideoCodec.VP9, VideoCodec.AV1 -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* Media3 encodes AAC, Opus and PCM. Three arms below are dead, not two.
|
||||
*
|
||||
* The comment this replaces named MP3 and FLAC as the exceptions, which reads as though
|
||||
* every other arm were live. **Vorbis is not.** A single router rule diverts every audio
|
||||
* codec outside {AAC, Opus, PCM} to FFmpeg, and Vorbis is outside it, so
|
||||
* `VORBIS -> AUDIO_VORBIS` names a MIME type Transformer is never actually asked for.
|
||||
*
|
||||
* The arm stays because the mapping is correct — deleting a right answer out of
|
||||
* unreachable code buys nothing — but it is an entry waiting on a routing change rather
|
||||
* than a live one. `Media3EngineMimeTypesTest` routes all six encodable codecs and asserts
|
||||
* which three arrive, so if that set moves, the disagreement fails rather than surprises.
|
||||
*/
|
||||
internal fun audioMimeTypeFor(codec: AudioCodec): String? = when (codec) {
|
||||
AudioCodec.AAC -> MimeTypes.AUDIO_AAC
|
||||
AudioCodec.OPUS -> MimeTypes.AUDIO_OPUS
|
||||
AudioCodec.VORBIS -> MimeTypes.AUDIO_VORBIS
|
||||
AudioCodec.PCM -> MimeTypes.AUDIO_RAW
|
||||
AudioCodec.COPY, AudioCodec.NONE -> null
|
||||
// MP3 and FLAC have no Android encoder at any API level, so the router sends them to
|
||||
// FFmpeg before an encoder is ever asked for.
|
||||
AudioCodec.MP3, AudioCodec.FLAC -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user