Skip to content

feat: video decoders and their abilities in /stats.json (#88 probe) - #137

Merged
compot-dev merged 2 commits into
v2from
feat/decoder-info
Oct 13, 2026
Merged

compot-dev merged 2 commits into
v2from
feat/decoder-info

Conversation

@compot-dev

Copy link
Copy Markdown
Collaborator

First step of #88: /stats.json gets decoders — for each video decoder of the device: name, type, hardware (Android 10+), adaptive (FEATURE_AdaptivePlayback: a new size mid-stream without reconfiguring), max_instances and the declared fps_1080p. Built once (CodecInfo).

This tells whether a shared key-frame decoder (one instance per codec feeding several cells, #88) is possible on a device: the AG-216 limits H.265 to 4 instances, and the approach needs adaptive playback (or a flush per camera) and setOutputSurface. Also useful in device reports.

@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. First stats request can stall the UI ✓ Resolved
Description
debugDevice() calls CodecInfo.videoDecoders() synchronously while debugSnapshot() normally
runs it on the UI thread. On the first /stats.json request, codec-list construction and capability
queries can delay that thread; the one-second snapshot timeout does not interrupt the work, and its
fallback may start a second probe.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[1335]

+        m.put("decoders", CodecInfo.videoDecoders());
Evidence
The snapshot posts debugState() to the main looper, and that method starts with debugDevice().
The added entry invokes synchronous codec enumeration before the UI task can finish; the timeout
path also calls debugDevice().

android/app/src/main/java/com/openipc/decoder/Decoder.java[1293-1311]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1317-1319]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1333-1335]
android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-55]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The first stats snapshot performs synchronous codec probing on the UI thread, where a slow probe can stall it beyond the snapshot timeout.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1293-1311]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1333-1336]
- android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-66]
## Recommended Fix
Build the decoder inventory on a background thread and have UI-thread snapshot assembly read only an already available result or an explicit pending state. Do not run the probe on the UI thread when the result is absent.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. One codec error hides later decoders ✓ Resolved
Description
videoDecoders() catches a failure in outer enumeration but still assigns the accumulated out
list to cached. If a codec's getSupportedTypes() throws, the loop stops before visiting later
codecs, and every subsequent /stats.json response returns that permanently partial list.
Code

android/app/src/main/java/com/openipc/decoder/CodecInfo.java[R63-65]

+        } catch (RuntimeException ignored) {
+        }
+        cached = out;
Evidence
getSupportedTypes() is outside the per-type catch, so its exception reaches the outer catch and
exits both loops. The method then caches the entries collected before the error, and its early
return prevents another scan.

android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-39]
android/app/src/main/java/com/openipc/decoder/CodecInfo.java[57-66]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1333-1335]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An exception outside per-type capability inspection ends enumeration and permanently caches an incomplete decoder inventory.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-39]
- android/app/src/main/java/com/openipc/decoder/CodecInfo.java[57-66]
## Recommended Fix
Isolate failures that can be attributed to one codec so enumeration can continue. If the list-wide scan fails, record the failure and leave the cache unset so a later request can retry rather than presenting a partial list as complete.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Working JPEG decoders go unreported 🐞 Bug ≡ Correctness
Description
videoDecoders() builds its inventory exclusively from MediaCodecList entries. On the documented
AG-216 case, playback can use a vendor JPEG decoder by name even when Android omits video/jpeg
from that list, so the new stats omit a decoder the app can use.
Code

android/app/src/main/java/com/openipc/decoder/CodecInfo.java[R34-35]

+            for (MediaCodecInfo ci : new MediaCodecList(MediaCodecList.ALL_CODECS)
+                    .getCodecInfos()) {
Evidence
The new inventory only iterates codec-list entries. The JPEG playback path explicitly documents a
vendor decoder omitted from that list, selects it as a fallback, and attempts to create it by name.

android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-40]
android/app/src/main/java/com/openipc/decoder/JpegCodec.java[25-35]
android/app/src/main/java/com/openipc/decoder/JpegCodec.java[95-125]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new inventory excludes a vendor JPEG decoder that playback can select by name when the platform codec list omits it.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-66]
- android/app/src/main/java/com/openipc/decoder/JpegCodec.java[25-35]
- android/app/src/main/java/com/openipc/decoder/JpegCodec.java[95-125]
## Recommended Fix
Account for the by-name JPEG fallback in decoder reporting once its usability is confirmed. Report unavailable capabilities as unavailable rather than inventing values, and ensure an inventory cached before playback can reflect a subsequently confirmed decoder.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can turn these tips off under Display > Comment parts

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
Comment thread android/app/src/main/java/com/openipc/decoder/CodecInfo.java Outdated
Comment on lines +34 to +35
for (MediaCodecInfo ci : new MediaCodecList(MediaCodecList.ALL_CODECS)
.getCodecInfos()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Working jpeg decoders go unreported 🐞 Bug ≡ Correctness

videoDecoders() builds its inventory exclusively from MediaCodecList entries. On the documented
AG-216 case, playback can use a vendor JPEG decoder by name even when Android omits video/jpeg
from that list, so the new stats omit a decoder the app can use.
Agent Prompt
## Issue description
The new inventory excludes a vendor JPEG decoder that playback can select by name when the platform codec list omits it.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/CodecInfo.java[29-66]
- android/app/src/main/java/com/openipc/decoder/JpegCodec.java[25-35]
- android/app/src/main/java/com/openipc/decoder/JpegCodec.java[95-125]

## Recommended Fix
Account for the by-name JPEG fallback in decoder reporting once its usability is confirmed. Report unavailable capabilities as unavailable rather than inventing values, and ensure an inventory cached before playback can reflect a subsequently confirmed decoder.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@compot-dev

Copy link
Copy Markdown
Collaborator Author

Qodo review — decisions:

  1. First stats request can stall the UI — fixed: CodecInfo.warmUp() builds the list on a background thread at start; /stats.json shows "decoders": "loading" until it is ready, never building it on the UI thread.
  2. One codec error hides later decoders — fixed: errors are caught per codec; a failure of the list itself is not cached.
  3. Working JPEG decoders go unreported — not taken: on the AG-216 the by-name JPEG decoder cannot be created (Failed to initialize …, error 0xfffffffe, feat: hardware MJPEG decoding through MediaCodec where available (#132, single view) #135), so there is nothing usable to report; this list shows what the platform exposes, which is what device reports need.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Qodo review — decisions:

  1. First stats request can stall the UI — fixed: CodecInfo.warmUp() builds the list on a background thread at start; /stats.json shows "decoders": "loading" until it is ready, never building it on the UI thread.
  2. One codec error hides later decoders — fixed: errors are caught per codec; a failure of the list itself is not cached.
  3. Working JPEG decoders go unreported — not taken: on the AG-216 the by-name JPEG decoder cannot be created (Failed to initialize …, error 0xfffffffe, feat: hardware MJPEG decoding through MediaCodec where available (#132, single view) #135), so there is nothing usable to report; this list shows what the platform exposes, which is what device reports need.

Your decisions are consistent with the current diff:

  • finding 1: Addressed. warmUp() performs discovery on a daemon background thread, while /stats.json returns "loading" until the cached result is available.
  • finding 2: Addressed. Failures are isolated per codec, and failures creating the overall codec list leave the cache unset for a later retry.
  • finding 3: Reasonably declined based on the documented AG-216 behavior: if the by-name JPEG decoder cannot actually be created, reporting it as an available decoder would be misleading. The stats now intentionally represent codecs exposed by MediaCodecList, not every decoder name attempted by playback.

No review or finding-management action was taken.

@compot-dev

Copy link
Copy Markdown
Collaborator Author

Device check (Aceline-1, 60b44fd): /stats.json lists 18 video decoders (hardware Allwinner AVC 16 instances, HEVC 4, all adaptive; software c2/OMX.google up to 32), ui_thread ok. Finding 3 stays declined as explained above: a by-name decoder is reported nowhere unless it can be created, and on the AG-216 it cannot.

@compot-dev
compot-dev merged commit 1d4a179 into v2 Oct 13, 2026
4 checks passed
@compot-dev
compot-dev deleted the feat/decoder-info branch October 13, 2026 14:21
compot-dev added a commit that referenced this pull request Oct 15, 2026
compot-dev added a commit that referenced this pull request Oct 15, 2026
feat: video decoders and their abilities in /stats.json (#88 probe)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant