Skip to content

AV1 videos bypass transcoding entirely - original file uploaded unmodified #487

Description

@ThatHunky

Note: this is an upstream Telegram-Android defect that Forkgram inherits, not something introduced here. Filing it because Forkgram is actively maintained and could carry a fix ahead of upstream — DrKLO/Telegram has issues disabled, so there is nowhere else to report it in the open.

Summary

AV1 video input bypasses the video conversion pipeline entirely. The original file is uploaded unmodified — no downscale, no transcode to a widely-supported codec — and the failure is completely silent: no error, no compression option, no indication to the user that the file was sent unprocessed.

Consequences:

  • A 4K AV1 clip uploads at full size (~126 MB here) instead of being downscaled to 1080p
  • Recipients without AV1 support get audio with no video
  • Previews/thumbnails are unreliable
  • Uploads are slow, because the full-resolution original is transferred

This is increasingly common in the wild: Pixel "Video Boost" returns AV1, and Pixel 10 exposes AV1 recording in the camera app directly.

Evidence — controlled device capture

Four sends on a Pixel 9 Pro (Tensor G4), same build, Telegram logging enabled throughout. The build emits begin convert … on entry to conversion and compression completed … on success; those are the discriminators.

# Source Res Route Converted? Codec components created Uploaded from
1 AV1 4K share sheet cache/sharing/<original name>
2 HEVC 1080p in-app picker c2.exynos.hevc.decoder + c2.exynos.h264.encoder cache/…mp4 (generated)
3 AV1 4K in-app picker c2.google.av1.decoder only — no encoder /storage/emulated/0/Download/…mp4 (verbatim)
4 HEVC 4K in-app picker c2.exynos.hevc.decoder + c2.exynos.h264.encoder cache/…mp4 (generated)

Runs 3 and 4 are the controlled pair — identical resolution (2160×3840), duration (28.6 s), HDR characteristics (10-bit BT.2020/HLG), source content and entry route. Only the codec differs.

Run 4 (HEVC, 4K) converts correctly:

D tmessages: begin convert /storage/emulated/0/Download/TEST_4K_HEVC_control.mp4
  startTime = -1 avatarStartTime = -1 endTime -1
  rWidth = 1080 rHeight = 1920 rotation = 0
  oWidth = 2160 oHeight = 3840 framerate = 30 bitrate = 6800000 originalBitrate = 0

D tmessages: compression completed time=27387 needCompress=true w=1080 h=1920
  bitrate=6800000 file size=23,8 MB encoder_name=c2.exynos.h264.encoder

4K → 1080p, 128.5 MB → 23.8 MB.

Run 3 (AV1, 4K) does not convert. Upload begins at file_part=0 straight from the file's on-disk location, ~7 s into the capture, with no preceding conversion phase:

D tmessages: debug_uploading: send reqId 9449
  /storage/emulated/0/Download/TEST_4K_AV1_reencoded.mp4 file_part=0 isBig=true

Neither begin convert nor compression completed appears, and no video encoder is instantiated. The single c2.google.av1.decoder runs in PID 1209 (mediaserver) — system thumbnail extraction — not in Telegram's process.

Both entry routes and both resolutions were tested. Route and resolution are excluded; the defect tracks the codec.

Run 3 used a freshly re-encoded AV1 file with a different SHA256 and different decoded-frame MD5 from run 1, ruling out server-side dedup by file_id or content fingerprint.

Why this looks like a gap rather than a policy choice

In MediaCodecVideoConvertor.convertVideoInternal(), conversion is gated on:

boolean needConvertVideo = false;
if (videoIndex >= 0 && !extractor.getTrackFormat(videoIndex)
        .getString(MediaFormat.KEY_MIME).equals(MediaController.VIDEO_MIME_TYPE)) {
    needConvertVideo = true;          // VIDEO_MIME_TYPE = "video/avc"
}
if (needCompress || needConvertVideo) { /* transcode */ } else { /* remux */ }

Any mime other than video/avc should therefore be transcoded — and run 2 confirms this empirically, logging needCompress=false yet converting HEVC → H.264 anyway. So AV1 falling through is inconsistent with the code's evident intent; something upstream of this decides AV1 is not convertible.

Reproduction

  1. Enable logging: Settings → tap the version number ~10× → Debug Menu → Enable Logs. Verify with adb logcat -d | grep tmessages before proceeding — without this every marker is absent and the result is meaningless.
  2. adb logcat -c
  3. Send a 4K AV1 .mp4 (any route), wait for the upload to complete.
  4. adb logcat -d > out.log
  5. Grep for begin convert and compression completed — both absent for AV1, present for an equivalent HEVC/H.264 file.

Secondary: two AV1 playback defects

Independent of the above, from reading TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java on master:

1. A single transient decoder exception permanently blacklists AV1. In onPlayerError():

if (cause.toString().contains("av1") || cause.toString().contains("av01")) {
    MessagesController.getGlobalMainSettings().edit()
        .putBoolean("unsupport_video/av01", true).commit();

supportsHardwareDecoder() reads that flag and returns false for the life of the install — no expiry, no retry, no reset on app upgrade. It then gates thumbnails, playback, and strips AV1 URIs from the quality list. Codec-instance exhaustion from opening several videos at once is enough to trigger it, after which a device with perfectly good hardware AV1 behaves as though it has none. Only recovery is clearing app data. Suggested fix: a failure counter with a threshold plus expiry, invalidated on app version change, and scoped to (mime, resolution, bit depth) rather than the whole codec.

2. Software decoders are never considered. supportsHardwareDecoder() does if (!MediaCodecUtil.isHardwareAccelerated(info, mime)) continue;. Android 10+ mandates a software AV1 decoder (c2.android.av1-dec) and Telegram bundles its own FFmpeg, but neither is used as a fallback — so on devices without hardware AV1 the video track is dropped entirely while audio keeps playing. Suggested fix: keep the hardware check for quality-selection heuristics, but allow software decode below a resolution threshold for the hard gates that currently discard the track.

Also filed upstream

Reported on Telegram's own tracker (the only open channel — DrKLO/Telegram has issues disabled): https://bugs.telegram.org/c/64017

Environment

  • App: Telegram Android 12.9.1 (69792)
  • Device: Google Pixel 9 Pro (Tensor G4, hardware AV1 decode present), Android 17 (API 37)
  • Source files: 4K AV1, yuv420p10le, BT.2020 / HLG (arib-std-b67), from Pixel "Video Boost"
  • Source analysis against DrKLO/Telegram master; note released builds have drifted — the convertVideoInternal original=… log string in current source does not appear in shipping builds, and a logcat line reading Compiler allocated NNMB to compile … convertVideoInternal(…) is an ART JIT message, not a FileLog entry (false positive when grepping).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions