Skip to content

fix(android): retry the export with a software encoder when the hardware encoder fails - #14

Merged
thangdevalone merged 1 commit into
thangdevalone:mainfrom
FrikkieSnyman:fix/android-software-encoder-fallback
Oct 15, 2026
Merged

thangdevalone merged 1 commit into
thangdevalone:mainfrom
FrikkieSnyman:fix/android-software-encoder-fallback

Conversation

@FrikkieSnyman

Copy link
Copy Markdown
Contributor

Closes #11.

What

On Android, when the video encoder fails, the export runs once more with a software encoder before the library gives up, and errors carry Media3's details.

  • runTransform tries Media3's default encoder, then, if the ExportException has a video encoder codecInfo (init failure or ERROR_CODE_ENCODING_FAILED mid-export), retries with a DefaultEncoderFactory whose EncoderSelector only returns non-hardware-accelerated encoders. Any other error stops immediately.
  • Errors: ProcessingFailed now reads Transform failed: default: ERROR_CODE_ENCODING_FAILED | <message> | CodecException(errorCode=…, transient=…, recoverable=…, diagnostic=…): … || software_encoder: … instead of Transform failed: Codec exception. The same text goes to logcat under tag VideoProcessor, plus Export used <attempt>:<codec> on success.
  • MediaResult.encoder?: string, "<default|software_encoder>:<ExportResult.videoEncoderName>", set on Android video exports so apps can see which encoder produced a file. iOS leaves it unset. nitrogen/ regenerated with yarn codegen.
  • The transmux flag on runTransform is removed. Both branches already configured the same H.264 encoder path (Media3 transcodes a clipped item regardless), and the retry needs an encoder factory on every path. trimVideo, cropVideo and processVideo keep their current behaviour: no bitrate request for the first two, 4 Mbps for the last.
  • README: encoder on MediaResult and a note on the fallback.

Why

A Samsung SM-A526B (Snapdragon 750G, Android 14, legacy OMX.qcom.video.encoder.avc) rejects some clips on the first surface frame:

GraphicBufferSource: got buffer with new dataSpace #102
OMX-VENC: get_config (dataspace changed): ColorSpace: Recommend 601 for RGBA8888
C2DColorConvert: calcYSize: Format not supported , 6
OMX-VENC: venc_dev: Failed setting color format 7fa30c06
OMX-VENC: ERROR: ETBProxy() failed!  →  OMX_ErrorHardware

Output size (1616x726, 1684x756, 1616x720), portrait vs landscape encoding, colour tags, and Media3's operating-rate/priority hints were each ruled out on the device. c2.android.avc.encoder encodes the same clip at the same size and frame rate in about 7 s for a 10 s range, so the retry turns a hard failure into a slower export. Other clips on the same device still take the hardware path on the first attempt.

Testing

  • yarn typecheck passes. yarn lint reports the same 278 pre-existing prettier errors as main; none are on changed lines.
  • Kotlin compiled through a consumer app's Gradle project (Media3 1.10.1); Swift parsed with swiftc -parse.
  • On the SM-A526B: the failing clip now exports with encoder = "software_encoder:c2.android.avc.encoder" and the logcat line lists the hardware attempt's error; unaffected clips report default:OMX.qcom.video.encoder.avc. Running in production (Relive) as a patch on 2.4.0.
  • Overlaps with feat: add startTime/endTime to compressVideo for single-pass trim + compress #13 only in VideoProcessor.kt and the Nitro spec; both apply cleanly on main and I can rebase whichever lands second.

…are encoder fails

Some hardware encoders reject an export after opening fine: a Samsung
SM-A526B (OMX.qcom.video.encoder.avc) answers the first surface frame of
some clips with OMX_ErrorHardware, which Media3 reports as
ERROR_CODE_ENCODING_FAILED. runTransform now runs once more with an
EncoderSelector limited to non-hardware encoders when the failure comes
from the video encoder, and ProcessingFailed carries Media3's error code
name plus the MediaCodec.CodecException details for every attempt.
MediaResult gains an optional `encoder` ("<attempt>:<codec>") on Android
video exports. The transmux flag is gone: both branches configured the
same H.264 path and the retry needs an encoder factory everywhere.

Closes thangdevalone#11
@thangdevalone
thangdevalone merged commit 4404af0 into thangdevalone:main Oct 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants