Video Encoding
This chapter covers hardware video encoding of H.264 / H.265 on the RK182X using the MPP framework.
Overall block diagram
Camera / YUV source
↓
Preprocessing (RGA: scaling / cropping / format conversion)
↓ NV12 frames
MPP Encoder (VPU hardware encoding)
↓
Bitstream output (H.264 / H.265 NALUs)
↓
File storage / RTSP streaming / network transmissionThe RK182X VPU supports hardware encoding of H.264 / H.265 at up to 4K@30fps, suitable for camera recording, RTSP streaming, video conferencing, and similar scenarios.
1. Encoding Capability
| Format | Profile | Max resolution | Max frame rate | Max bitrate |
|---|---|---|---|---|
| H.265 / HEVC | Main / Main10 | 4096×2304 | 30 fps | 40 Mbps |
| H.264 / AVC | High Profile | 4096×2304 | 30 fps | 40 Mbps |
2. Complete Encoding C Code Example
Six-step flow: mpp_create → mpp_enc_cfg_init (set resolution/fps/bitrate/GOP) → mpp_init(ENC, codec) → MPP_ENC_SET_CFG → loop (encode_put_frame + encode_get_packet written to file) → flush → clean up.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rockchip/mpp_buffer.h>
#include <rockchip/mpp_frame.h>
#include <rockchip/mpp_packet.h>
#include <rockchip/rk_mpi.h>
#include <rockchip/rk_mpi_cmd.h> /* MPP_ENC_SET_CFG */
#include <rockchip/rk_venc_cfg.h> /* mpp_enc_cfg_* */
#include <rockchip/rk_venc_rc.h> /* MPP_ENC_RC_MODE_* */
#include <rockchip/rk_venc_cmd.h> /* MppEncROICfg / MppEncH264Cfg */
int main(void) {
const RK_U32 width = 1920;
const RK_U32 height = 1080;
const RK_U32 fps = 30;
const RK_U32 bitrate = 4000000;
MppCodingType codec = MPP_VIDEO_CodingAVC;
MPP_RET ret;
MppCtx ctx = NULL;
MppApi *mpi = NULL;
ret = mpp_create(&ctx, &mpi);
if (ret) return ret;
MppEncCfg cfg = NULL;
mpp_enc_cfg_init(&cfg);
mpp_enc_cfg_set_s32(cfg, "prep:width", width);
mpp_enc_cfg_set_s32(cfg, "prep:height", height);
mpp_enc_cfg_set_s32(cfg, "prep:format", MPP_FMT_YUV420SP);
mpp_enc_cfg_set_s32(cfg, "rc:mode", MPP_ENC_RC_MODE_CBR);
mpp_enc_cfg_set_s32(cfg, "rc:bps_target", bitrate);
mpp_enc_cfg_set_s32(cfg, "rc:fps_in", fps);
mpp_enc_cfg_set_s32(cfg, "rc:fps_out", fps);
mpp_enc_cfg_set_s32(cfg, "rc:gop", fps * 2);
/* The coding type is passed as the third argument of the top-level mpp_init;
* there is no MPP_SET_ENC_CODING_TYPE control command
* and no mpi->init (MppApi has no init member)
*
* mpp_init must be called before MPP_ENC_SET_CFG
* (the reverse order aborts on an assertion — see the warning below)
*/
ret = mpp_init(ctx, MPP_CTX_ENC, codec);
if (ret) return ret;
ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg);
if (ret) return ret;
FILE *fp_out = fopen("output.h264", "wb");
if (!fp_out) { perror("fopen"); return -1; }
MppBufferGroup group = NULL;
mpp_buffer_group_get_internal(&group, MPP_BUFFER_TYPE_DRM);
const RK_U32 total_frames = fps * 10;
for (RK_U32 i = 0; i < total_frames; i++) {
MppFrame frame = NULL;
MppBuffer buf = NULL;
mpp_frame_init(&frame);
mpp_frame_set_width (frame, width);
mpp_frame_set_height(frame, height);
mpp_frame_set_fmt (frame, MPP_FMT_YUV420SP);
/* mpp_buffer_get_with_tag takes 5 args (group, &buf, size, tag, caller) */
mpp_buffer_get_with_tag(group, &buf,
width * height * 3 / 2,
"enc_input", __FUNCTION__);
memset(mpp_buffer_get_ptr(buf), 128,
width * height * 3 / 2);
mpp_frame_set_buffer(frame, buf);
mpp_frame_set_pts(frame, (RK_S64)i * 1000 / fps);
mpi->encode_put_frame(ctx, frame);
for (;;) {
MppPacket packet = NULL;
ret = mpi->encode_get_packet(ctx, &packet);
if (ret != MPP_OK || !packet) break;
fwrite(mpp_packet_get_data(packet), 1,
mpp_packet_get_length(packet), fp_out);
mpp_packet_deinit(&packet);
}
mpp_frame_deinit(&frame);
}
/* flush */
mpi->encode_put_frame(ctx, NULL);
for (;;) {
MppPacket packet = NULL;
ret = mpi->encode_get_packet(ctx, &packet);
if (ret != MPP_OK || !packet) break;
fwrite(mpp_packet_get_data(packet), 1,
mpp_packet_get_length(packet), fp_out);
mpp_packet_deinit(&packet);
}
fclose(fp_out);
mpp_buffer_group_put(group);
mpp_enc_cfg_deinit(cfg);
mpp_destroy(ctx);
printf("Encode complete: output.h264\n");
return 0;
}Hard ordering constraint:
MPP_ENC_SET_CFGmust come aftermpp_init(ctx, MPP_CTX_ENC, codec)—mpi->controlcan only recognize encode commands once the context is initialized in ENC mode. The reverse order aborts on an assertion:mpp[7484]: mpp: Assertion mpp->mType == MPP_CTX_ENC failed at mpp_control:1190 mpp[7484]: mpp: Assertion mpp->mEnc failed at mpp_control_enc:1525 mpp[7484]: mpp_enc: mpp_enc_control_v2 found NULL enc mpp[7484]: mpp: command 320001 param 0x55a9c1b0e8 ret -3 MPP_ENC_SET_CFG failed: -3Encoder minimum-parameter limits (measured on VEPU580/581):
- Resolution floor 1280×720: setting 320×240 is rejected and falls back to 1280×720
- Bitrate range 1K ~ 100M: setting 400K, out of range, falls back to 2M
- Default fps 30: setting 15 falls back to 30
Measured fallback log:
mpp_enc: invalid set w:h [320:240] stride [0:0] rotation 0 mpp_enc: restore cfg w:h [1280:720] stride [1280:720] rotation 0 mpp_enc: set prep cfg w:h [1280:720] stride [1280:720] fmt 0 rotate 0 mirror 0 mpp_enc: invalid bit per second (bps) 400000 [0:0] out of range 1K~100M mpp_enc: restore bps to 2000000 [1500000:2500000] mpp_enc: set rc cbr bps [2000000:2500000:1500000] fps [30:1:fix] - [30:1:fix] gop 30 hal_h264e_vepu580: hal_h264e_vepu580_status_check wdg timeout
3. Compiling the Encoder
All VPU encoding capability is encapsulated in librockchip_mpp; linking only needs -lrockchip_mpp.
aarch64-linux-gnu-gcc encode_test.c \
-I/usr/include/rockchip \
-L/usr/lib/aarch64-linux-gnu \
-lrockchip_mpp \
-o encode_test4. API Verification
MPP encode control commands:
grep -E "MPP_ENC_SET_ROI_CFG|MPP_ENC_SET_H264_CFG" /usr/include/rockchip/rk_mpi_cmd.hOutput:
MPP_ENC_SET_ROI_CFG, /* set MppEncROICfg structure */ROI and H264 config structures:
grep -E "MppEncROICfg|MppEncH264Cfg" /usr/include/rockchip/rk_venc_cmd.hOutput:
typedef enum MppEncH264CfgChange_e {
}
MppEncH264CfgChange;
typedef struct MppEncH264Cfg_t {
}
MppEncH264Cfg;
* structure such as MppEncH264Cfg and MppEncJpegCfg. This data
MppEncH264Cfg h264;
typedef struct MppEncROICfg_t {
}
MppEncROICfg;
typedef struct MppEncROICfg0_t {
} MppEncROICfgLegacy;
typedef struct MppEncROICfg2_t {
} MppEncROICfg2;ROI Region and quality fields:
grep -E "MppEncROIRegion|quality" /usr/include/rockchip/rk_venc_cmd.h | head -10Output:
* This is quality and bitrate request from user.
* - paramter quality and qp will not take effect
* - paramter 'quality' define 5 quality levels
* quality - quality parameter, only takes effect in VBR mode
* Mpp provide total 5 quality level:
MppEncRcQuality quality;
* quality config
/* quality config */
* quality factor config
typedef struct MppEncROIRegion_t {buffer with tag function:
grep "mpp_buffer_get_with_tag" /usr/include/rockchip/mpp_buffer.hOutput:
mpp_buffer_get_with_tag(group, buffer, size, MODULE_TAG, __FUNCTION__)
MPP_RET mpp_buffer_get_with_tag(MppBufferGroup group, MppBuffer *buffer, size_t size,Rate control modes:
grep -E "MPP_ENC_RC_MODE_(CBR|VBR|CQP|FIXQP|AVBR)" /usr/include/rockchip/rk_venc_rc.hOutput:
MPP_ENC_RC_MODE_VBR,
MPP_ENC_RC_MODE_CBR,
MPP_ENC_RC_MODE_FIXQP,
MPP_ENC_RC_MODE_AVBR,MppApi encode function definitions:
grep -E "encode_put_frame|encode_get_packet" /usr/include/rockchip/rk_mpi.hOutput:
* encode_put_frame : send video frame to encoder only, async interface
* encode_get_packet: get encoded video packet from encoder only, async interface
MPP_RET (*encode_put_frame)(MppCtx ctx, MppFrame frame);
MPP_RET (*encode_get_packet)(MppCtx ctx, MppPacket *packet);5. Bitrate Control Modes
Four modes, set via mpp_enc_cfg_set_s32(cfg, "rc:mode", ...):
| Mode | Constant | Typical scenario |
|---|---|---|
| Constant bitrate (CBR) | MPP_ENC_RC_MODE_CBR | Live streaming, constrained bandwidth |
| Variable bitrate (VBR) | MPP_ENC_RC_MODE_VBR | Recording storage, quality-first |
| Constant quality (CQP / FIXQP) | MPP_ENC_RC_MODE_FIXQP | Transcoding, post-processing |
| Adaptive (AVBR) | MPP_ENC_RC_MODE_AVBR | Adaptive for complex scenes |
The actual enums in
rk_venc_rc.halso include scenario modes such asSMTRC/SE; choose as needed.
6. ROI High-Quality Encoding
Use MppEncROICfg to set up to N ROI regions, each with x / y / w / h and quality (VBR mode, 1–5, 5 highest), allocating more bitrate to key regions such as faces and license plates.
MppEncROICfg roi_cfg;
memset(&roi_cfg, 0, sizeof(roi_cfg));
roi_cfg.number = 2;
// ROI 1: face region (high quality)
roi_cfg.regions[0].x = 400; roi_cfg.regions[0].y = 200;
roi_cfg.regions[0].w = 200; roi_cfg.regions[0].h = 200;
roi_cfg.regions[0].quality = 5; // VBR mode 1-5, 5 highest
// ROI 2: license plate region
roi_cfg.regions[1].x = 800; roi_cfg.regions[1].y = 600;
roi_cfg.regions[1].w = 300; roi_cfg.regions[1].h = 100;
roi_cfg.regions[1].quality = 5;
mpi->control(ctx, MPP_ENC_SET_ROI_CFG, &roi_cfg);7. Low-Latency Configuration
Zero-latency mode: disable B-frames (GOP=0) + constant bitrate + H.264 CABAC entropy coding, which can push end-to-end latency down to about 33 ms.
// Zero-latency mode (disable B-frames + minimal GOP)
mpp_enc_cfg_set_s32(enc_cfg, "rc:gop", 0); // no B-frames
mpp_enc_cfg_set_s32(enc_cfg, "rc:bps_target", bitrate);
// H.264 encoding presets (must go through MPP_ENC_SET_CFG or another interface)
// Refer to the SDK documentation or example code8. FAQ
| Symptom | Cause | Resolution |
|---|---|---|
MPP_ENC_SET_CFG failed: -3 | mpp_init called after MPP_ENC_SET_CFG | Swap the order: mpp_init first, then control |
restore cfg w:h [1280:720] | Resolution < 1280×720 | Use 1280×720 or above |
bps out of range 1K~100M | Bitrate too low | Set within 1K~100M |
vepu580_status_check wdg timeout | Input is all-gray frames | Feed real YUV420SP data |
output.h264 is 0 bytes | Watchdog timeout or missing flush | Call mpi->encode_put_frame(ctx, NULL) |
9. Next Steps
- MPP Multimedia Framework — multimedia framework overview
- RGA 2D Acceleration — hardware-accelerated preprocessing
- NPU Overview — combining AI inference with video analytics
