[RTL8735B / AmebaPro2] SC231HAI Sensor Support: Missing iq_sc231h.bin, WDR/HDR Capability, and Hardware Reference Design

Hi Ameba IoT Team / Realtek FAE,

We are evaluating image sensors for an upcoming 1080p security camera project on the RTL8735B (AmebaPro2) platform. We are considering the SmartSens SC231HAI, but during our SDK audit, we identified potential discrepancies regarding IQ tuning files and HDR support that critically affect our component selection and BOM freeze.

SDK Investigation Findings

Inspecting the official SDK ([ GitHub - Ameba-AIoT/ameba-rtos-pro2: Realtek Official IoT Software Development Kit for Ameba Series SoC: (Ameba Pro2) · GitHub ]( GitHub - Ameba-AIoT/ameba-rtos-pro2: Realtek Official IoT Software Development Kit for Ameba Series SoC: (Ameba Pro2) · GitHub )), we found the sensor binary in component/soc/8735b/fwlib/rtl8735b/lib/source/ram/video/voe_bin/:

  • sensor_sc231h.bin exists (3,700 bytes).

  • project/realtek_amebapro2_v0_example/inc/sensor.h defines #define SENSOR_SC231H 0x12 with {1920, 1080, 30}.

  • Issue: iq_sc231h.bin is completely missing from voe_bin/, making SC231H the only sensor candidate in the SDK matrix that lacks an accompanying IQ file.

Sensor Support Matrix Comparison (sensor.h vs. voe_bin/)

Sensor Model Driver FCS IQ (in sensor.h) HDR / WDR Resolution iq_*.bin Status in voe_bin/
SC231H $\checkmark$ - $\checkmark$ - 1920x1080@30 MISSING (iq_sc231h.bin not found)
SC2336 $\checkmark$ $\checkmark$ $\checkmark$ - 1920x1080@30 Present (iq_sc2336.bin)
SC2310 $\checkmark$ - $\checkmark$ $\checkmark$ 1920x1080@30 Present (iq_sc2310.bin)
SC301 $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ 2048x1536@20 Present (iq_sc301.bin)
IMX307 $\checkmark$ - $\checkmark$ $\checkmark$ 1920x1080@30 Present (iq_imx307.bin)
IMX662 $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ 1920x1080@30 Present (iq_imx662.bin)

Technical Questions & FAE Clarification Requested

Since SC231HAI is currently our primary candidate, we kindly request clarification on the following blockers:

  1. [Q1 / B-1] Missing iq_sc231h.bin & IQ Tuning Provision:

    • sensor.h marks IQ as supported ($\checkmark$) for SC231H, but iq_sc231h.bin is missing. How can we obtain the IQ binary for SC231HAI? Is it provided under project NDA, requires a custom request, or is the entry in sensor.h a documentation error?
  2. [Q2 / B-2] IQ Fine-Tuning Service & Lead Time:

    • If iq_sc231h.bin requires custom ISP fine-tuning, does Realtek offer IQ tuning services for SC231HAI, or do you recommend certified 3rd-party tuning vendors? What are the typical lead times and service flows?
  3. [Q3 / B-3] WDR / HDR Capability on SC231HAI:

    • Security applications require WDR for high-contrast backlight environments (e.g., doorways/windows). The SDK matrix shows HDR unsupported (-) for SC231H. Can SC231HAI support hardware WDR/HDR on the RTL8735B VOE engine, or is it strictly limited to Linear Mode (SDR)?
  4. [Q4 / B-4] Recommended 1080p30 WDR Sensor Alternative:

    • If SC231HAI lacks full IQ binary support or WDR capability, which sensor does Realtek officially recommend for 1080p30 + WDR/HDR security applications (e.g., SC2310, IMX307, or IMX662)?
  5. [Q5 / B-5] Hardware Integration & Interface Details:

    • Could you share the reference MIPI CSI-2 lane configuration (1-lane / 2-lane), clock rate, power-up sequencing, and schematic guidelines for SC231HAI on RTL8735B?
  6. [Q6 / B-6] Day/Night Switching & IR-Cut Control:

    • What are the recommended GPIO/PWM control interfaces and reference designs for Day/Night mode switching and IR-Cut filter driving on this platform?

Thank you for your assistance. Your feedback is crucial for our upcoming hardware design freeze.

Hi @Hsu_Shawn,

As shared,

For sensor drivers that do not have a corresponding IQ file, a dummy IQ file is typically used.

We also provide an IQ tuning tool that allows users to customize the IQ binary file based on the image sensor they are using.

Guide: Tuning Guide ENG — AmebaPro2's Documentation v0.1 documentation

An activation key is needed to use the IQ tuning tool, RealCam.

After running RealCam.exe, you should see a pop-up window, click on the dump to generate Realcam_activation.bin and send it to us.

You may let us know if you encounter any issues.

Currently, our SDK supports the SC231H sensor. SC231H currently not yet support HDR. However, HDR support is under development, and we will update the driver and support it once it is ready.

You may refer to the camera bring up guide for more general information and guidance.

  1. In ir_cut.h and ir_ctrl.h, the GPIO/PWM pins above are reference EVB assignments. On your own PCB, any free GPIO can be used for IR-CUT control and any PWM-capable pin for IR LED.
  2. The complete working example is at mmf2_video_example_v1_day_night_change_init.c.

Hi Pammy,

Thank you for the detailed answers — they moved several things forward on our side. Let me confirm what is now closed, and then ask about two items that still block us.

Closed, thank you:

  • IR-CUT and day/night switching. The pointer to ir_cut.h / ir_ctrl.h and to mmf2_video_example_v1_day_night_change_init.c was exactly what we needed, and knowing that any free GPIO works on our own PCB unblocks the hardware layout.

  • Part supply. Understood that RTL8735BDM-VA9-CG is not purchasable, and that RTL8735BDM is stable with no EOL planned within two years and six months’ notice. That is what we needed for the BOM risk assessment.

  • IQ tuning flow. We will run RealCam.exe, generate Realcam_activation.bin and send it over. Please confirm who we should send it to.

One correction on our side: our earlier question about 256 MB DDR3 was based on the assumption that 1080p would not fit in 128 MB. That turned out to be wrong — we now run 1080p30 stably on the 128 MB AMB82-Mini with three encode channels active (main stream, JPEG snapshot, motion detection), with around 52 MB of heap free. So please disregard the 256 MB questions; only the question of whether VOE can address more than 128 MB remains, and it is no longer urgent.

Hi @Hsu_Shawn,

Once you generate Realcam_activation.bin, you may send it to us via private message or email us at AmebaAIoT@realtek.com .

As for HDR support on SC231HAI, I will update you as soon as it is available in the SDK.

Thank you.

Hi Pammy,

Thank you — we will generate Realcam_activation.bin and send it to AmebaAIoT@realtek.com this week.

Two things I would like to pin down, plus one question you may be able to answer straight away.

1. Is SC231HAI the same sensor as SC231H, from the driver’s point of view?

I noticed you wrote “HDR support on SC231HAI”, while the earlier message said the SDK currently supports SC231H. I want to make sure I am not reading more into that than I should, because the answer changes our BOM:

  • Does the existing sensor_sc231h.bin driver work with SC231HAI as-is?
  • If not, when can we expect an SC231HAI driver?

If they are the same part under two names, that closes the question and we will proceed with IQ tuning. If they are different, we need to know before we commit to the sensor.

2. Ethernet design resources — could you tell us where the approval stands?

I realise this needs internal sign-off and I do not want to push you on something outside your control. But I should be straightforward about why I keep coming back to it: PoE Ethernet is the only network interface this product has. Our firmware is well along — ONVIF Profile T now passes 242 of 366 DTT tests — and the hardware side is what we are waiting on. We cannot start PCB layout without the schematic and pin-out guidance.

So rather than asking again for the material itself:

  • Is there anything we can provide to move the approval along — NDA, volume forecast, a project summary?
  • Is there someone else we should be talking to?
  • Even a rough sense of the timeline would help us plan.

3. One question that may not need the full package:

Are there any known pin-multiplexing conflicts between the Ethernet MII pins and the camera pipeline — MIPI CSI-2, sensor I2C, IR-CUT GPIO, and the PWM used for the IR LED?

We are budgeting GPIOs now (IR-CUT, IR LED, and a motorised lens with zoom and focus steppers), so even a partial answer would let us continue planning while the approval is in progress.

Thank you again for your help — the IR-CUT reference and the part-supply confirmation both unblocked real work on our side.

Best regards,
Shawn

Pammy <notifications@ameba.discoursemail.com> 於 2026年8月14日 週五 17:50 寫道:

Hi @Hsu_Shawn,

Yes, they are the same sensor. The name is simply shortened to SC231H in sensor.h. The existing sensor_sc231h.bin driver is compatible with SC231HAI.

We understand your request. The information you provided through the Private User Form is sufficient, and we have escalated it to the relevant department for review. We are currently awaiting their response.

I will follow up with them again and provide you with an update by the end of this week.

There should be no pin conflicts.

  1. Ethernet pins: IC pins #67, #68, #126, and #127 (dedicated pins) must be connected to the RTL8152x PHY.
  2. Sensor use: IC GroupD_0~D_9,D_10~D_13,E_0,A_5
  3. IR cut , IR LED : Can be defined by user
  4. As for motorised lens with zoom and focus steppers, currently we do not have this feature supported.

Reference:
RTL8735B_Datasheet_1_0_Lite.zip (776.2 KB)

Hi Pammy,

How are you?

Thank you — confirming that SC231H and SC231HAI are the same sensor closes that question for us, and we will start IQ tuning. The datasheet was very useful too; we have verified the Ethernet pinout from it (EPHY_TXOP/TXON/RXIP/RXIN on pins 67/126/68/127, with EPHY_LVLDO on 66 and EPHY_HV on 125) and confirmed there is no conflict with the sensor group.

One clarification on that, in case it matters for others: your note said those pins “must be connected to the RTL8152x PHY”. From Table 8 and the pin list, they look like the analogue differential pairs of the SoC’s own Ethernet PHY — so our reading is that they go to a magnetics module and RJ45 directly, with no external PHY chip. Please correct us if that is wrong, because our whole PoE design depends on it.

There is one question we have not asked you directly, and we should have.


1. Can we buy the chip?

We have been told, second-hand, that Realtek reserves IC sales for high-volume customers, because supporting WLAN and BT calibration and certification is not viable at small volumes.

Our product uses no radio at all — no Wi-Fi, no BLE, no antenna, no RF front-end on the board. So there is nothing to calibrate and no NCC or CE radio certification to support. The stated reason does not apply to us.

  • Under those conditions, is chip purchase still subject to a volume threshold?
  • If we can buy, which distributor should we approach, and which part number?

I want to be plain about why this comes first: our firmware is well along — ONVIF Profile T now passes a large majority of the DTT 19.06 suite — and the Ethernet design is settled. But if the chip is not purchasable at our volume, none of that reaches production. We would rather know now than after the PCBs are made.

2. Part number for an IC-based design

The datasheet lists RTL8735BDM/BM in VA3, VL3, VA4 and VL4 variants. You mentioned RTL8735BDM-VA9-CG is not available.

  • Which part number should we design in?
  • What distinguishes BDM from BM, and VA from VL? We assume DM means integrated DDR — the AMB82-Mini appears to use RTL8735BDM-AA4-CG with 128 MB DDR2 — but we would rather confirm than assume.

3. Operating temperature range

We could not find a temperature specification in the Lite datasheet. The figures we have found elsewhere disagree:

  • The AMB82-Mini user guide states −20 °C to +85 °C “from the main chip point of view”
  • A third-party RTL8735 module datasheet states 0 °C to +60 °C

The second is presumably a module limitation rather than the SoC’s.

  • What is the specified operating and storage temperature range for RTL8735BDM?
  • Is there an industrial-grade variant?

Security cameras are installed outdoors and in semi-outdoor locations — entrances, carports, stairwells. A 0 °C lower bound would rule out several of our target markets, so this affects which part we commit to.

4. HDR / WDR timing

Now that SC231H and SC231HAI are confirmed to be the same part, the question is more specific: when do you expect HDR support for this sensor to land in the SDK? Even a rough quarter would help. Backlit scenes are exactly where WDR matters for a security camera, and if the schedule is far out we need to consider a different sensor before releasing the BOM.


We appreciate you following up on the Ethernet approval — we will watch for your update this week.

Best regards,
Shawn H Hsu

Hi @Hsu_Shawn,

Documents have been shared with you privately.

The RTL8735B has a built-in Fast Ethernet PHY (FEPHY) — so those pins are indeed the analog differential pairs (TX±, RX±) of the SoC’s own PHY.

No external PHY chip (like RTL8152x) needed. The RTL8152x is a USB-to-Ethernet controller — it would be used if you were adding Ethernet via the USB host port, not the native Ethernet pins.

We will contact and discuss with you on this.

You can find the IQ bin for SC321HAI here. This supports HDR.

iq_sc231h.zip (7.8 KB)

The bin file will also be included in the open-source SDK. In the meantime, if you need to perform any testing, you can use this bin file instead of the dummy IQ bin.

[RTL8735B] 1080p MJPEG on CH0 — runtime hal_video_open failure, and whether 1080p30 is reachable at all

Date: 2026-08-27 (revision 2 of the 2026-08-24 enquiry) Hardware: AMB82-mini (RTL8735B) Arduino SDK: AmebaPro2 4.1.0 VOE: RTL8735B_VOE_1.6.8.0 / Sensor RTL8735B_VOE_1.5.7.0 To: Pammy (Realtek FAE)


0. What changed since the 2026-08-24 enquiry

The first version of this enquiry said twelve ONVIF mandatory tests were failing on this path. That is no longer the situation, and the question has become sharper rather than going away.

We have since moved the ONVIF JPEG tests onto a second media profile backed by a boot-time JPEG channel (CH1, 1280x720, measured 30.2 fps). Those tests now pass. What remains is the part no workaround reaches:

  • CH0 cannot produce JPEG at runtime at all (§2), and
  • CH0’s boot-time 1080p JPEG runs at ~6.8 fps (§5), which is below what we can ship.

So the enquiry is now two questions rather than one:

  1. Why does the runtime switch fail, and is it supposed to work? (§2, §6.1, §6.2)
  2. Is 1080p30 MJPEG reachable on this SoC at all? (§5, §6.4)

:warning: Question 2 is the one that decides the product. We have set an internal acceptance criterion: JPEG streaming is offered only if it can run at 1080p30. If the RTL8735B cannot reach that, we will restrict JPEG to GetSnapshotUri and stop offering JPEG video streaming entirely. A clear “no” is as useful to us as a “yes” — it lets us close the question and remove the feature.


1. Summary

With one unchanged firmware build:

  • Boot path — CH0 configured as JPEG before videoInit() → 1080p MJPEG streams successfully.
  • Runtime path — CH0 switched from H.264 to JPEG while running → hal_video_open fails:
VOE command 0x206 fail ret 0xff
VOE_OPEN_CMD command fail 98600800
hal_video_open fail ret=98600800, group=3

Runtime switching between H.264 and H.265 using the same function works perfectly (28–29 fps). The failure is specific to JPEG.


2. The two execution paths

2.1 Boot path — :green_circle: succeeds

Camera.configVideoChannel(CHANNEL, config);   // config._encoder = VIDEO_JPEG
Camera.videoInit();
Camera.channelBegin(CHANNEL);

cores/ambpro2/video_drv.c → cameraOpen():

video_control(p_priv, CMD_VIDEO_SET_PARAMS, &video_params);
mm_module_ctrl(p, MM_CMD_SET_QUEUE_LEN,    fps * 3);
mm_module_ctrl(p, MM_CMD_INIT_QUEUE_ITEMS, MMQI_FLAG_DYNAMIC);
if (JPEG) mm_module_ctrl(p, CMD_VIDEO_SNAPSHOT, 0);
// CMD_VIDEO_APPLY is issued by channelBegin() -> cameraStart()

Result: 1920x1080 MJPEG on port 554. ffmpeg decodes 34 frames in 5 s (~6.8 fps). No hal_video_open failure in the serial log.

2.2 Runtime path — :red_circle: fails

Camera.configVideoChannel(CHANNEL, config);   // config._encoder = VIDEO_JPEG
Camera.setQLen(CHANNEL, fps * 3);
Camera.snapshotCtrl(CHANNEL, 0);              // added to match cameraOpen()
Camera.updateVideoParams(CHANNEL);

cameraUpdateParams():

mm_module_ctrl(p, CMD_VIDEO_STREAM_STOP, stream_id);
mm_module_ctrl(p, CMD_VIDEO_SET_PARAMS,  &video_params);
mm_module_ctrl(p, CMD_VIDEO_APPLY,       stream_id);

Result: hal_video_open fail ret=98600800, group=3. The encoder never opens → rtp_o_mjpeg_handler is never invoked → zero RTP packets. ffmpeg reports codec mjpeg, unspecified size.

2.3 The parameters are identical

Field-by-field, captured from the same build on both paths:

Boot:    enc=2 (VIDEO_JPEG)  res=6 (VIDEO_FHD)  1920x1080  fps=30  bps=2097152
Runtime: enc=2               res=6              1920x1080  fps=30  bps=2097152

The parameters are not the difference. The call sequence is.


3. :red_circle: The buffer arithmetic does not add up — and this is our strongest clue

video_open() (video_api.c, around the “jpeg max size = NV12 size” comment):

jpeg_out_buf_size  = (enc_in_w * enc_in_h * 3) / 2;   // 1920x1080 -> 3,110,400
jpeg_out_rsvd_size = jpeg_out_buf_size;

video_get_buffer_info() reports, on every measurement we have taken, on both the succeeding and the failing path:

out_buf  = 2,097,152
out_rsvd =   393,216

required by video_open()     3,110,400
reported by get_buffer_info  2,097,152
difference                   ~1 MB

:warning: The requirement exceeds the reported allocation by roughly 1 MB, yet the boot path succeeds. Either the boot path obtains memory from somewhere video_get_buffer_info() does not report, or the requirement is not enforced on that path.

A third formula is involved: video_buf_calc() sizes the allocation at boot as (w*h)/8 + bps, which for our parameters is 259,200 + 2,097,152. That matches neither of the numbers above.

We cannot reconcile these three formulas, and we believe the answer to this question is also the answer to §5.

:pushpin: Note: our first enquiry listed “insufficient encoding buffer” as a ruled-out hypothesis because the reported value is identical on both paths. We now think that was the wrong conclusion to draw — identical reported values are consistent with the reporting function not covering the allocation that actually matters.


4. Hypotheses we have ruled out, with measurements

# Hypothesis Measurement / result
1 Bitrate too low 2 MB → 4 MB; the boot path failed as well. Reverted.
2 Single JPEG encoder restriction During a successful boot path, CH2 (snapshot=1, JPEG) runs at the same time without issue.
3 CH1 occupying the VOE Pulled CH1 (port 555) with ffmpeg for 84 s at 30 fps; CH0 still failed on the runtime switch. Since then CH1 also carries a G.711 audio track and the result is unchanged.
4 Resolution overhead Reduced to 720p; still 0 fps.
5 StreamIO stack Added 64 KB setStackSize() to the MISO. Since then the audio pipeline was rebuilt as SIMO + MISO (two G.711 encoders). No change either time.
6 Audio track interference Removed the G.711 track from port 554. No change.
7 Queue not rebuilt Moved MM_CMD_SET_QUEUE_LEN + MM_CMD_INIT_QUEUE_ITEMS to before CMD_VIDEO_APPLY. No change.
8 Missing CMD_VIDEO_SNAPSHOT(0) Called explicitly, execution confirmed in the serial log. No change.
9 Different ctrl entry point Disassembled mm_module_ctrl: for cmd > 6 it fetches ctx->module->control and ctx->priv directly, which is functionally equivalent to video_control(p_priv, ...).

:warning: “Insufficient encoding buffer” appeared on this list in our first enquiry. It has been moved to §3 as an open question, for the reason given there.


5. :red_circle: The frame rate we can reach on the path that DOES work

Even on the boot path, which opens successfully:

1920x1080 MJPEG, measured with ffmpeg over a fixed 5-second window
  34 decoded frames in 5 s  =  6.8 fps

For context:

ONVIF DTT's streaming tests require   7 frames within 1000 ms
Our reference device (AXIS FA51)      advertises 1920x1080 @ 30 fps JPEG
Our CH1 at 1280x720                   measured 30.2 fps

6.8 fps is below the certification threshold and far below the reference device. Our own product criterion is 1080p30.

Observation we cannot explain: 1280x720 at 30 fps is 27.6 Mpixel/s. 1920x1080 at 6.8 fps is 14.1 Mpixel/s — half the pixel throughput of the configuration that works. This does not look like a raw encoder-throughput limit, which is why we suspect it is related to §3.


6. Questions

6.1 Error code

  • What is the exact meaning of ret=0x98600800 (group=3, “Driver”)? video_get_error_group() extracts the group as error_id >> 27 & 0xF, but we do not have the mapping table for error IDs.
  • For VOE command 0x206 fail ret 0xff — is there a defined meaning for return value 0xff under 0x206 (VOE_OPEN_CMD)?

6.2 Runtime encoder switching

  • Does the RTL8735B VOE support changing an active channel from H.264 to JPEG at runtime?
  • If yes — what steps are required beyond cameraUpdateParams() (STREAM_STOP → SET_PARAMS → APPLY)?
  • If no — what is the recommended sequence? video_close() then video_open(), or must the VOE module be re-initialised?

6.3 JPEG buffer allocation

  • How do these three relate?
video_open()       (w * h * 3) / 2   = 3,110,400
video_buf_calc()   (w * h) / 8 + bps = 2,356,352
get_buffer_info()  reports             2,097,152

  • Does JPEG require memory reserved during initial boot that a runtime reconfiguration cannot obtain?
  • CMD_VIDEO_SET_VOE_HEAP is present but commented out in cores/ambpro2/video_drv.c. Is that the intended mechanism for raising the output buffer above 3,110,400, and what value should be used for 1080p JPEG?

6.4 :bullseye: The question that decides the product

Can the RTL8735B produce 1920x1080 MJPEG at 30 fps at all?

  • If yes — what VOE heap size, buffer configuration and channel layout does it require? We currently run CH0 (main), CH1 (MJPEG), CH2 (snapshot), CH3 (motion detection input, VGA RGB @ 10 fps), with roughly 41–60 MB free.
  • If no — what is the realistic maximum for 1080p MJPEG on this SoC?

:warning: We are asking for a number, not a workaround. Our product criterion is 1080p30; a clear “not achievable” lets us drop JPEG video streaming and keep only GetSnapshotUri, which is all ONVIF Profile T actually requires (§7.19). We would rather close the question than keep engineering around it.

mmf2_video_example_v3_init.c uses V3_FPS = 5, V3_BPS = 2*1024*1024, V3_CHANNEL = 2 — if 5 fps is the intended design point for JPEG on this part, please say so directly.


7. Diagnostic material available on request

  • Full serial logs, boot-path success vs runtime failure, same build
  • stream_fps.ps1 output (ffmpeg decoded-frame counts over a fixed window)
  • Complete ONVIF DTT 19.06 reports (366 tests)
  • Individual serial logs for each ruled-out experiment
  • A minimal reproducible sketch

8. Current status

Initialising CH0 as JPEG at boot works, but it is not usable as a product workaround for two separate reasons:

  1. ONVIF SetVideoEncoderConfiguration requires runtime switching, and
  2. even the working path only reaches 6.8 fps at 1080p.

We have routed the ONVIF JPEG tests to a boot-time 720p JPEG channel as an interim measure. That satisfies the test tool but does not meet our product criterion, so the decision on whether to keep JPEG video streaming at all is waiting on §6.4.


Appendix — unrelated observation, low priority

Please treat this as a separate item; it is not part of the enquiry above and should not delay a reply to §6.

If CH1 and CH2 are stopped at the same time, the VOE stops responding entirely:

VOE command wait ACK timeout
hal_video_open ret=ffffffff group=15

After this, even H.264 channels cannot be opened. Are there constraints on which combinations of channels may be stopped while others remain active?

Hi @Hsu_Shawn, you may refer to the operating and storage temperature range below according to the datasheets and EVB user guide. They can be downloaded from RealMCU Download Center .There is no known industrial-grade variant available to our knowledge.

source: ameba_datasheet_rtl8735b_v1.0 (IC datasheet)


source: RTL8735BDM-A20-N04_Module_Datasheet_V1.3_2025 (module datasheet)


source: AMB82-Mini_Hardware_User_Guide_0V4_20260206 (AMB82-mini EVB User Guide)

Thank you.

Hi @Hsu_Shawn,

[6.1] Error code

ret=0x98600800 indicates that video_open() failed at the driver layer. This return value corresponds to the ERR_ID_DRV_VIDEO_INVALID_CROP_SIZE error.

However, we are unable to share the mapping table at this time as it contains confidential information. If you encounter any similar errors in the future, feel free to let us know, and we will be happy to assist you in identifying the issue.

VOE_OPEN_CMD does more than just open a handle. It asks the VOE firmware side to set up and start the entire video stream, including the sensor, ISP, encoder, and stream buffers. If any part of that setup fails, VOE returns 0xff.
Some common reasons:

  1. Channel already open — the engine refuses to create a stream on a channel that’s already running.
  2. The codec, resolution, FPS, or stream format combination is not supported. For example, the requested H264/JPEG/YUV combination may not work with the selected sensor.
  3. Sensor/ISP not ready at open — The sensor may have failed to initialize, have an I2C/IQ/FCS problem, or already be used by another feature such as USB UVC.
  4. VOE engine not properly booted / firmware mismatch — The VOE engine may not have booted correctly.
  5. Not enough memory for the encoder/stream buffers in the VOE heap.

[6.2] Runtime encoder switching

  • Runtime codec switching is possible. I have tried it on ameba-rtos-pro2. You may refer to the patch below and the newly written code for codec changing is under CODEC_CHANGE_TEST case in param_change_test function.

    mmf2_video_example_v1_param_change_init.zip (4.2 KB)

    Guide:
    While the stream is playing, using AT command PCT= , then click Send.
    Command Format: PCT=07, {codec}

    Supported Commands:
    PCT=07,0 (H.265)
    PCT=07,1 (H.264)
    PCT=07,2 (MJPEG)
    PCT=07,6 (H.265+JPEG)
    PCT=07,7 (H.264+JPEG)

    When a PCT= command is received, the board performs the following sequence automatically, the camera stays on, Wi-Fi stays connected, no reboot required:

    Step 1 — PAUSE
    Step 2 — STOP ENCODER
    Step 3 — UPDATE PARAMS
    Step 4 — RECONFIGURE RTSP
    Step 5 — VOE HEAP RESIZE
    Step 6 — RESTART

    After the switch completes (typically under 1 second), reconnect VLC to the same RTSP URL the stream will resume in the new codec.

    Some limitation I encountered while looking at this feature, FHD MJPEG (PCT=2 at 1920×1080)
    Switching to MJPEG at FHD resolution (1920×1080) via runtime codec change: You will see warnings like VOE CH0 JPG buff full (queue/used/out/rsvd) 19/128KB. The current SDK API does not provide a way to resize the JPEG buffer during a runtime codec switch. For this part, do let me clarify with respective team to see if its the limitation.

[6.3] JPEG buffer allocation

  • video_buf_calc: compute the total heap size in video_voe_presetting()
  • out_buf_size in video_open(): buffer size needed by encoder
  • jpeg_out_buf_size in video_open(): jpeg max size, which is size of a NV12

Reconfiguration during runtime for MJPEG can be obtained, recalculation of VOE heap size is needed, you may refer to video_buf_calc() in video_api.c for the calculation of VOE heap size ameba-rtos-pro2/component/video/driver/RTL8735B/video_api.c at main · Ameba-AIoT/ameba-rtos-pro2

CMD_VIDEO_SET_VOE_HEAP is commented out as VOE heap size calculation was done in cameraConfig() before calling cameraOpen()

Questions
1. May I know which camera sensor was used for the evaluation? Was it the JXF37?
2. If you are using MJPEG, is FHD resolution a mandatory requirement for your application?

Hi Pammy,
Thank you for the reply.
Re: [6.2] Runtime encoder switching / [6.3] JPEG buffer allocation

Date: 2026-08-31 To: Pammy (Realtek FAE) From: Shawn (Surpedia, AMB82-mini ONVIF Profile T)


Thank you — the patch answered two things we had been unable to determine

mmf2_video_example_v1_param_change_init.c gave us video_voe_presetting_by_params(), which is the runtime counterpart of the cameraConfig() heap calculation we had been looking for. That also explains why CMD_VIDEO_SET_VOE_HEAP is commented out — it is not the mechanism, and we had been treating its absence as the blocker.

The CODEC_CHANGE_TEST sequence also showed us something we had missed:

c

if (new_type == VIDEO_JPEG) {
    video_v1_params.fps = 5;
    video_v1_params.gop = 5;
}

Our own runtime switch keeps 30 fps when moving to MJPEG. We have been chasing hal_video_open ret=0x98600800 on that path for two weeks and had eliminated ten hypotheses; the frame rate was not among them. We will test this.


Your two questions

1. Which sensor?

SC231HAI, not JXF37.

2. Is FHD mandatory for MJPEG in our application?

Yes. 1920×1080 is a product requirement for the MJPEG stream, not a preference. Our acceptance criterion is 1080p at 30 fps.

We record this plainly because we would rather you scope the question correctly than have us appear flexible and then come back later: if the SDK cannot resize the JPEG buffer during a runtime codec switch at 1920×1080, that is a hard constraint for this product rather than an inconvenience.


What we have measured, in case it helps your discussion with the team

Boot-time FHD MJPEG works; runtime switching to it does not.

1920x1080 JPEG, configured at boot     works, measured 6.8 fps
1920x1080 JPEG, runtime switch         hal_video_open ret=0x98600800
1280x720  JPEG, configured at boot     works, measured 30.2 fps (CH1)

The arithmetic we had derived before your reply, for what it is worth:

video_open() out_buf reported   2,097,152
jpeg_need for 1920x1080          3,110,400

That gap is consistent with what you describe as the missing runtime resize.

Two questions this raises for us, if the team can comment:

  1. With video_voe_presetting_by_params() recalculating the heap, is the 1920×1080 MJPEG limitation in the JPEG buffer specifically, or in the total VOE heap? The VOE CH0 JPG buff full (queue/used/out/rsvd) 19/128KB message you saw suggests the former.
  2. Is there a supported way to reserve the FHD-sized JPEG buffer at boot and keep it across a runtime codec switch, even at the cost of that memory being held while H.264/H.265 is active? For our product that trade is acceptable — we would rather lose the memory than lose the resolution.

Separately: a defect in rtsp_transport_init()

We reported this on 2026-08-28 (FAE_RTSP_TRANSPORT_INIT_20260828.md) and mention it again only because it is likely to affect other Profile T customers.

component/network/rtsp/rtsp_api.c:

c

struct rtsp_transport *transport = &rtsp_ctx->transport[0];
for (int i = 0; i < RTSP_MAX_STREAM_NUM; i++) {
    transport += i;                 /* accumulates: visits 0, 1, 3, 6, 10 ... */

At the shipped RTSP_MAX_STREAM_NUM of 2 this happens to visit exactly [0] and [1] and is invisible. ONVIF Profile T §7.13 makes metadata streaming mandatory, which needs a third stream, so any customer raising that constant gets an uninitialised transport[2] and an out-of-bounds write into the struct rtsp_session that follows the array.

Suggested fix is one line:

c

transport = &rtsp_ctx->transport[i];

Status, for context

We are pursuing ONVIF Profile T certification with DTT 19.06. Metadata streaming and IPv4/IPv6 multicast are now working; the remaining open items on our side are the FHD MJPEG question above and a small number of unrelated tests.

Thank you again for the patch — it was the specific thing we could not have derived from the public SDK.
Best regards,

Shawn

Hi @Hsu_Shawn,

I have edited the previous message and added the answer for [6.1].

[6.1] Error code

ret=0x98600800 indicates that video_open() failed at the driver layer. This return value corresponds to the ERR_ID_DRV_VIDEO_INVALID_CROP_SIZE error.

However, we are unable to share the mapping table at this time as it contains confidential information. If you encounter any similar errors in the future, feel free to let us know, and we will be happy to assist you in identifying the issue.

VOE_OPEN_CMD does more than just open a handle. It asks the VOE firmware side to set up and start the entire video stream, including the sensor, ISP, encoder, and stream buffers. If any part of that setup fails, VOE returns 0xff.
Some common reasons:

  1. Channel already open — the engine refuses to create a stream on a channel that’s already running.
  2. The codec, resolution, FPS, or stream format combination is not supported. For example, the requested H264/JPEG/YUV combination may not work with the selected sensor.
  3. Sensor/ISP not ready at open — The sensor may have failed to initialize, have an I2C/IQ/FCS problem, or already be used by another feature such as USB UVC.
  4. VOE engine not properly booted / firmware mismatch — The VOE engine may not have booted correctly.
  5. Not enough memory for the encoder/stream buffers in the VOE heap.

In the SDK’s default JPEG flow, JPEG is primarily intended for snapshot-type usage rather than continuous streaming. The JPEG path keeps a buffer roughly corresponding to one NV12 frame at the configured resolution. If the JPEG callback holds the buffer for too long—for example, while writing the image to storage—the JPEG buffer can become full.

The JPEG buffer-full condition can also be improved by:

  • increasing the JPEG buffer size, or
  • lowering the JPEG quality level (qlevel) to reduce the encoded frame size.

If continuous MJPEG streaming is required, a queue-based mechanism similar to the H.264 path may be more appropriate. But for this particular JPEG streaming flow has not been extensively validated.

The maximum achievable frame rate would also ultimately be limited by the sensor’s supported FPS.

At this point, we do not have confirmation of an officially supported SDK mechanism that reserves an FHD-sized JPEG buffer at boot and guarantees that the same allocation is retained across runtime H.264/H.265/JPEG codec switches. The current SDK flow recalculates/reconfigures the required memory according to the active video parameters.

Let me look into it and get back to you.

RTL8735B Technical Clarification List v6

2026-09-04 | AMB82-mini ONVIF Profile T Camera Follow-up v5 (2026-09-02) Response Review

Thank you for the responses in the previous round.

All four questions in v5 received clear answers. Two of these answers directly altered our design direction:

  • 0x98600800 = ERR_ID_DRV_VIDEO_INVALID_CROP_SIZE — This answer overturned our two-week-old assumption of “insufficient VOE heap.”

  • Five possible causes for VOE_OPEN_CMD 0xff.

  • Confirmation that there is no official, supported mechanism to retain the FHD JPEG buffer across encoder switches.

  • Out-of-bounds write in rtsp_transport_init() (your team indicated this will be addressed in a follow-up reply).

Question 1 :red_circle: Actual Trigger Conditions for INVALID_CROP_SIZE

1.1 Symptom

Using the exact same set of resolution parameters yields opposite results at two different execution points:

  • Scenario A (Boot time):

    cameraOpen(1920x1080, VIDEO_JPEG)

    :green_circle: Success: Streams continuously (measured at 6.8 fps).

  • Scenario B (Runtime switch):

    Executes video_voe_release() $\rightarrow$ video_voe_presetting_by_params() $\rightarrow$ cameraOpen(1920x1080, VIDEO_JPEG).

    :red_circle: ret = 0x98600800 (ERR_ID_DRV_VIDEO_INVALID_CROP_SIZE).

:pushpin: According to your explanation in the last round, 0x98600800 indicates an invalid crop size. However, since the width and height are identical between Scenario A and Scenario B, the issue does not stem from the dimensions themselves.

1.2 Questions for Clarification

  1. Does the valid range for cropping depend on the current state of the ISP or sensor?

  2. In a runtime switching sequence, is it necessary to reset the ROI or other crop-related configurations prior to calling cameraOpen()?

  3. Below is our current switching sequence. Are there any missing steps?

    1. Stop StreamIO for the target channel

    2. cameraStop / channelClose

    3. video_voe_release()

    4. video_voe_presetting_by_params() (Confirmed necessary by your team previously)

    5. cameraOpen(new params)

  4. Apart from video_get_error_group(), are there any APIs available to retrieve more detailed error descriptions? (We understand that error code lookup tables are proprietary; we are asking if an executable runtime query interface exists.)

1.3 :warning: What We Already Understand (Not Part of This Question)

Your team noted in the previous round:

“The JPEG path keeps a buffer roughly corresponding to one NV12 frame at the configured resolution.”

:pushpin: A 1080p NV12 frame requires:

$$1920 \times 1080 \times 1.5 = 3,110,400 \text{ bytes}$$

This matches the jpeg_need 3110400 entry observed in our logs. We previously interpreted this figure as “insufficient VOE heap,” but we now understand it is an intrinsic design requirement of the JPEG path to allocate one NV12 frame. That point is clear and requires no further explanation.

:red_circle: What we want to clarify in this question is: Assuming sufficient memory is available, why does calling cameraOpen() with identical resolution parameters succeed at boot time, but fail with INVALID_CROP_SIZE after a runtime re-configuration?

1.4 Purpose of This Clarification

:warning: This limitation currently blocks our dynamic resolution switching functionality. Our workaround is fixing CH0 to a combined VIDEO_H264_JPEG encoder to avoid runtime switching, but this compromises our runtime flexibility.

Question 2 :yellow_circle: Long-term Risks of Continuous MJPEG Streaming

2.1 Statement from Last Round

“In the SDK’s default JPEG flow, JPEG is primarily intended for snapshot-type usage rather than continuous streaming. … If continuous MJPEG streaming is required, a queue-based mechanism similar to the H.264 path may be more appropriate. But for this particular JPEG streaming flow has not been extensively validated.”

2.2 Current Setup

  • CH2 (1280x720, VIDEO_JPEG, snapshot=0, target 15 fps setting):

    $\rightarrow$ StreamIO $\rightarrow$ RTSP Server 3 (Port 556)

    Measured output: Sustained, stable 22.8 fps over several hours of continuous operation without anomalies.

:red_circle: :warning: This stream serves as the backbone for our ONVIF Profile T certification — approximately twenty DTT test items pass through it.

2.3 Questions for Clarification

  1. What are the specific risks associated with “not extensively validated”? Are there known failure modes, such as:

    • Buffer leaks over extended runtimes?

    • Buffer overflows caused by specific visual content (e.g., high detail or rapid scene changes)?

    • Resource contention when running concurrently with other active channels?

  2. Is there a recommended upper limit regarding the relationship between qlevel and fps?

    • Your team suggested that we can “lower qlevel to reduce encoded frame size.” Under 720p / 15 fps conditions, what is the recommended range for qlevel?
  3. Is it normal for the measured frame rate to exceed the configured value?

    “The maximum achievable frame rate would also ultimately be limited by the sensor’s supported FPS.”

    • Configured: VideoSetting(VIDEO_HD, 15, VIDEO_JPEG, 0)

    • Measured: 22.8 fps (counted via FFmpeg decode over a continuous 5-second window).

    • Questions:

      • Is the fps parameter in VideoSetting treated as a hard ceiling or a target nominal rate for VIDEO_JPEG?

      • Does fps only govern ISP sampling rate, while the JPEG encoder outputs frames as fast as it processes them?

      • Does this discrepancy indicate a misunderstanding of a specific configuration parameter on our end?

        :pushpin: This affects our resource budgeting — if actual output can exceed the configured setting, our buffer and bandwidth planning must be derived from empirical maximums rather than nominal parameter settings.

  4. If we transition to a queue-based mechanism (similar to the H.264 path), are there reference implementations or sample code available?

  5. Is this JPEG streaming path suitable for mass production?

    • If your team advises against using it in production, we must adjust our certification strategy promptly — as Profile T requires valid MJPEG test paths.

2.4 Urgency

:warning: We are about to enter pre-mass-production reliability testing (burn-in testing). If this path carries known long-term risks, we need to design stress tests specifically around it or transition to an alternative architecture immediately.

Reference: Current Channel Configuration

  • CH0 (1920x1080, VIDEO_H264_JPEG / VIDEO_HEVC_JPEG, snapshot=1):

    $\rightarrow$ RTSP 554 (NVR Main Stream) + /snapshot (1080p JPEG)

  • CH1 (1280x720, VIDEO_H264):

    $\rightarrow$ RTSP 555 + WebSocket Preview (TLS)

  • CH2 (1280x720, VIDEO_JPEG, snapshot=0):

    $\rightarrow$ RTSP 556 (ONVIF Certification Stream)

  • CH3 (640x480, VIDEO_RGB):

    $\rightarrow$ Motion Detection

  • System Status: Free Heap: 31.5 MB | Main Loop Latency: 19–20 ms

:pushpin: Note: Utilizing the dual VIDEO_H264_JPEG encoder on CH0 allows H.264 to use the output queue while JPEG uses the snapshot callback concurrently. This solved our earlier constraint of fitting four requirements into three hardware encoder channels.

Contact & Diagnostics

If serial logs or reproduction procedures are required, we can provide:

  • Full UART logs (including VOE initialization and context surrounding errors)

  • Comparative side-by-side logs for Scenarios A and B

  • Current channel configuration code and StreamIO binding logic

Question 1
Although both calls use the same 1920x1080, VIDEO_JPEG parameters, the important difference is the ISP/camera state at the time cameraOpen() is called.

At boot time, the camera starts from a clean state. The sensor and ISP are freshly initialized, with no previous ROI, crop, or scaling configuration affecting the new stream. Therefore, the 1920x1080 JPEG configuration can be opened successfully.

During a runtime switch, however, video_voe_release() does not fully reset the ISP/camera configuration. From the source code, it mainly releases the VOE video buffers. This means that ISP-related state from the previous stream, such as ROI or scaling configuration, may still be present when the next cameraOpen() is executed.

The valid crop range depends on the current ISP/sensor state.

During video_open(), the SDK determines the reference input area against which the requested encoder size is validated.

video_api.c
If ROI is not enabled, the reference is the current sensor resolution:

origin_width  = isp_info.sensor_width;
origin_height = isp_info.sensor_height;

If ROI is enabled, the reference becomes the active ROI region:

origin_width  = v_stream->roi.xmax - v_stream->roi.xmin;
origin_height = v_stream->roi.ymax - v_stream->roi.ymin;

Therefore, depending on the current ISP configuration, the reference area may be:

  • the current sensor resolution;
  • the active ROI region, if ROI is enabled; or
  • an existing scaling/crop state from the previous video configuration.

The requested encoder input size is then validated against this reference area.

As a result, the same requested resolution can produce different results if the ISP state is different when cameraOpen() is called.

For example:

  • At boot: the reference is the freshly initialized sensor area, so 1920x1080 is valid.
  • During runtime reconfiguration: the ISP may still reflect a previous ROI or scaling state, so the same 1920x1080 request may be validated against a different reference area.

The flow:
CMD_VIDEO_STREAM_STOP → CMD_VIDEO_SET_PARAMS → video_voe_release() → video_voe_presetting_by_params() → CMD_VIDEO_APPLY

No, there is no runtime API that returns a detailed error description. video_get_error_group() is the entire executable query surface.

Questions:

Could you help confirm the following so that we can reproduce the same condition more accurately?

  1. Which codec are you switching from, and which codec are you switching to?
  2. Which video channel is being switched?
  3. Are the other video channels, especially CH0, still running during the switch?
  4. Are use_roi or jpeg_crop_parm enabled for the affected channel?
  5. Could you share the exact video_params_t configuration before and after the switch?
  6. Are you testing using Arduino SDK or FreeRTOS SDK?

Thank you.

Question 2 (Reply on behalf of @KevinKL)
Currently, JPEG is primarily used for snapshots. Although the SDK is designed to support JPEG streaming, stability testing at this stage has mainly focused on H.264 streaming, and JPEG streaming has not yet undergone comprehensive validation under mass-production conditions. Therefore, if the you plan to deploy this feature in mass production, we recommend conducting further stability verification based on the actual use case and operating conditions.
Valid qlevel: 0-9

For 720p/15 fps MJPEG recommendation:

  • qlevel 5–6 for ONVIF Profile T (good quality at moderate bitrate) — this is the vendor default and a safe middle.
  • qlevel 3–4 if bandwidth-limited (roughly ~40–60% of the q5 frame size).
  • Avoid qlevel 8–9 for continuous streaming — it inflates frame size 2–3× vs q5, triples RTP packet count. Reserve 8–9 for one-shot snapshots.

There is no documented qlevel&fps coupling; fps is gated by the ISP/queue, not by qlevel. Lowering qlevel only helps if bandwidth/queue depth is the bottleneck — it lowers per-frame bytes so more frames can be pushed per second, but it does not unblock a processing bottleneck.

Is measured fps > configured fps normal? — Yes, and it’s expected here
For the JPEG path, fps is a target/nominal rate, not a hard ceiling.

  1. No rate controller for JPEG. video_rc_init() is only called when codec & (CODEC_HEVC|CODEC_H264) (video_api.c:2336-2342). JPEG is open-loop — it encodes every ISP-delivered frame. There is no RC loop to drop frames to hit a target, unlike H.264.
  2. isp_fps is left unbound. In video_open, the ISP fps is only copied from fps when out_mode == MODE_SYNC || MODE_EXT (video_api.c:2121-2123).
  3. hal_video_set_fps(fps, ch) is always called (video_api.c:2119), but with no RC and isp_fps=0, the encoder runs at effectively the sensor native rate, bounded by queue/network backpressure.

So the fps value is used for timestamp/VOE accounting, not frame gating on this path.