目录
[HEVC 错误之一](#HEVC 错误之一)
[Codec type or id mismatches](#Codec type or id mismatches)
[HEVC 错误之二](#HEVC 错误之二)
[Failed to set config: -6](#Failed to set config: -6)
[软件帧(System Memory Frame)](#软件帧(System Memory Frame))
[DRM PRIME 帧(DMA-Buf Frame)](#DRM PRIME 帧(DMA-Buf Frame))
[buffersink输出 NV12(软件帧)](#buffersink输出 NV12(软件帧))
[buffersink输出 DRM_PRIME(硬件帧)](#buffersink输出 DRM_PRIME(硬件帧))
[1) 创建filter,包括buffersrc,filter,以及buffersink](#1) 创建filter,包括buffersrc,filter,以及buffersink)
[2) 设置input即buffersrc的frame上下文](#2) 设置input即buffersrc的frame上下文)
3) 设置output的格式 设置output的格式)
[eglCreateImageKHR failed](#eglCreateImageKHR failed)
链接库文件查看
实际编译时链接的静态库文件。
root@kylin:~# g++ -o main main.cpp \
> -I/opt/ffmpeg-6.1/include \
> -L/opt/ffmpeg-6.1/lib \
> -lavfilter -lavformat -lavcodec -lswresample -lswscale -lpostproc -lavutil \
> -lrockchip_mpp -lrga -lz -llzma -lbz2 -lm \
> -lEGL -lGLESv2 -ldrm -lgbm \
> -lpthread -lstdc++ -std=c++11 \
> -Wl,--trace 2>&1 | grep -E "libav(codec|format|util)"
/opt/ffmpeg-6.1/lib/libavformat.a
/opt/ffmpeg-6.1/lib/libavcodec.a
/opt/ffmpeg-6.1/lib/libavutil.a
HEVC 错误之一
Codec type or id mismatches
./main test.mp4 output.hevc
FFmpeg version: fb515155ca
avcodec version: 3940198
[hevc_rkmpp @ 0x558c9c7e20] Codec type or id mismatches
avcodec_open2 failed
打印输出为:
Stream codec_type: 0
Stream codec_id: 27
测试文件信息
ffprobe test.mp4
ffprobe version 4.2.2-1rk5 Copyright (c) 2007-2019 the FFmpeg developers
built with gcc 9 (Kylin 9.3.0-10kylin5k0.5)
configuration: --prefix=/usr --extra-version=1rk5 --toolchain=hardened --libdir=/usr/lib/aarch64-linux-gnu --incdir=/usr/include/aarch64-linux-gnu --arch=arm64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-libdrm --enable-librga --enable-rkmpp --enable-version3 --disable-libopenh264 --disable-vaapi --disable-vdpau --disable-decoder=h264_v4l2m2m --disable-decoder=vp8_v4l2m2m --disable-decoder=mpeg2_v4l2m2m --disable-decoder=mpeg4_v4l2m2m --enable-shared --disable-doc
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libavresample 4. 0. 0 / 4. 0. 0
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
creation_time : 2012-03-13T08:58:06.000000Z
encoder : HandBrake 0.9.6 2012022800
Duration: 00:00:10.03, start: 0.000000, bitrate: 629 kb/s
Chapter #0:0: start 0.000000, end 10.000000
Metadata:
title : Chapter 1
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, smpte170m/smpte170m/bt709), 320x176, 300 kb/s, 25 fps, 25 tbr, 90k tbn, 180k tbc (default)
Metadata:
creation_time : 2012-03-13T08:58:06.000000Z
encoder : JVT/AVC Coding
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)
Metadata:
creation_time : 2012-03-13T08:58:06.000000Z
Stream #0:2(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s
Metadata:
creation_time : 2012-03-13T08:58:06.000000Z
Stream #0:3(und): Data: bin_data (text / 0x74786574), 0 kb/s
Metadata:
creation_time : 2012-03-13T08:58:06.000000Z
[h264_rkmpp @ 0x55aba55250] Rga alloc buffer[device:/dev/dma_heap/system-uncached-dma32 size:268435456] successfully.
解决方法
// ❌ 删掉这行,不要复制
// avcodec_parameters_to_context(encodec_ctx, video_stream->codecpar);
// ✅ 全部手动设置
encodec_ctx->width = 640;
encodec_ctx->height = 360;
encodec_ctx->pix_fmt = AV_PIX_FMT_NV12;
encodec_ctx->time_base = av_make_q(1, 25);
encodec_ctx->framerate = av_make_q(25, 1);
encodec_ctx->bit_rate = 2000000;
或者如下修改,此种修改更能体现出根因。
avcodec_parameters_to_context(encodec_ctx, video_stream->codecpar);
// 关键:覆盖编解码器 ID 和类型
encodec_ctx->codec_id = encodec->id; // 改成 HEVC
encodec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
// 其他参数按需修改
encodec_ctx->width = 640;
encodec_ctx->height = 360;
encodec_ctx->pix_fmt = AV_PIX_FMT_NV12;
这里avcodec_parameters_to_context(encodec_ctx, video_stream->codecpar);的作用是配置编码的参数,例如格式、码率等。本测试命令的入参文件为264格式编码,输出为265编码。
video_stream->codecpar 为输入文件264的参数配置,和编码265的不一致,故而报错了。
HEVC 错误之二
Failed to set config: -6
./main /home/kylin/1600120060fps.ts output.hevc
Stream codec_type: 0
Stream codec_id: 173
[hevc_rkmpp @ 0x55ae1bc440] Failed to set config: -6
avcodec_open2 failed
测试文件信息
ffprobe /home/kylin/1600120060fps.ts
Stream #0:0[0x100]: Video: hevc (Main) (HEVC / 0x43564548), yuvj420p(pc), 1600x1200, 60 fps, 60 tbr, 90k tbn, 60 tbc
265的文件。
调试开关
av_log_set_level(AV_LOG_DEBUG);
代码种增加上述后,可以打开debug信息输出,具体信息如下:
mpegts @ 0x5589f80a40] After avformat_find_stream_info() pos: 0 bytes read:1881072 seeks:4 frames:32
Stream codec_type: 0
Stream codec_id: 173
[hevc @ 0x5589fcdc70] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x5589fcdc70] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x5589fcdc70] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x5589fcdc70] Decoding VPS
[hevc @ 0x5589fcdc70] Main profile bitstream
[hevc @ 0x5589fcdc70] Decoding SPS
[hevc @ 0x5589fcdc70] Main profile bitstream
[hevc @ 0x5589fcdc70] Decoding VUI
[hevc @ 0x5589fcdc70] Decoding PPS
Supported pixel formats: gray yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p nv12 nv21 nv16 nv24 yuyv422 yvyu422 uyvy422 rgb24 bgr24 rgba rgb0 bgra bgr0 argb 0rgb abgr 0bgr drm_prime
[hevc_rkmpp @ 0x5589fcc440] Rate Control mode is set to CBR
[hevc_rkmpp @ 0x5589fcc440] Bitrate Target/Min/Max is set to 0/0/0
[hevc_rkmpp @ 0x5589fcc440] QP Init/Max/Min/Max_I/Min_I is set to 26/48/0/48/0
[hevc_rkmpp @ 0x5589fcc440] Profile is set to MAIN
[hevc_rkmpp @ 0x5589fcc440] Level is set to 0
[hevc_rkmpp @ 0x5589fcc440] Failed to set config: -6
avcodec_open2 failed
Bitrate Target/Min/Max is set to 0/0/0 比特率是 0,硬件编码器不接受这个值
解决方法
encodec_ctx->bit_rate = 2000000;
帧的分类
以下由AI汇总,实测也准确。
| 类别 | FFmpeg 格式标识 | 数据存在哪里 | CPU 能否直接读 | 典型用途 |
|---|---|---|---|---|
| 软件帧 | AV_PIX_FMT_YUV420P、NV12、BGRA... |
系统内存(RAM) | ✅ 可以 | 软解、滤镜处理、编码输入 |
| DRM_PRIME 帧 | AV_PIX_FMT_DRM_PRIME |
DMA-Buf(内核管理的物理连续内存) | ❌ 不能直接读(可 mmap) | 硬解输出、zero-copy 显示 |
| 通用硬件帧 | AV_PIX_FMT_NONE + hw_frames_ctx |
GPU/VPU 设备内存 | ❌ 不能 | VAAPI、CUDA、Vulkan 等框架 |
| RGA 硬件帧 | AV_PIX_FMT_NONE + hw_frames_ctx |
RGA 专用内存/MPP buffer | ❌ 不能 | scale_rkrga 滤镜的输入输出 |
| EGLImage 帧 | 非 FFmpeg 概念 | GPU 显存(通过 EGLImageKHR 引用) | ❌ 不能 | OpenGL ES 纹理、渲染 |
软件帧(System Memory Frame)
最普通的帧,像素存在 frame->data[0/1/2] 指向的内存里。
cpp
frame->format == AV_PIX_FMT_NV12; // 或 YUV420P、BGRA 等
frame->data[0]; // Y 平面指针
frame->data[1]; // UV 平面指针
特点:CPU 随便读写,但数据量大时内存带宽压力大。
DRM PRIME 帧(DMA-Buf Frame)
硬件解码器直接把数据写到 DMA-Buf 里,FFmpeg 用 AVDRMFrameDescriptor 描述它:
frame->format == AV_PIX_FMT_DRM_PRIME;
AVDRMFrameDescriptor* desc = (AVDRMFrameDescriptor*)frame->data[0];
desc->objects[0].fd; // DMA-Buf 文件描述符
desc->layers[0].format; // fourcc,如 NV12、NV16
特点:
-
CPU 不能直接读 像素(除非
mmap) -
可以零拷贝送给 DRM/KMS、EGL、Wayland、V4L2
-
hevc_rkmpp解码器默认输出这种帧
验证编码器支持的帧格式
std::cout << "=== Check if encoder supports DRM_PRIME ===" << std::endl;
const enum AVPixelFormat *pix_fmts = encodec->pix_fmts;
if (pix_fmts) {
bool supports_drm = false;
for (int i = 0; pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
std::cout << av_get_pix_fmt_name(pix_fmts[i]) << " ";
if (pix_fmts[i] == AV_PIX_FMT_DRM_PRIME) supports_drm = true;
}
std::cout << std::endl;
std::cout << "Supports DRM_PRIME: " << (supports_drm ? "✅ YES" : "❌ NO") << std::endl;
}
输出格式如下:
Supported pixel formats: gray yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p nv12 nv21 nv16 nv24 yuyv422 yvyu422 uyvy422 rgb24 bgr24 rgba rgb0 bgra bgr0 argb 0rgb abgr 0bgr drm_prime
| 分类 | 说明 | 对应像素格式 |
|---|---|---|
| 系统内存帧 (System Memory) | 数据在普通 RAM,CPU 可直接访问 | AV_PIX_FMT_YUV420P、AV_PIX_FMT_NV12、AV_PIX_FMT_RGB24 等 |
| 硬件内存帧 (Hardware Memory) | 数据在 GPU/显存/专用硬件内存,CPU 不能直接访问 | AV_PIX_FMT_DRM_PRIME、AV_PIX_FMT_CUDA、AV_PIX_FMT_VAAPI、AV_PIX_FMT_VDPAU、AV_PIX_FMT_D3D11、AV_PIX_FMT_MEDIACODEC 等 |
在 FFmpeg 中,一个帧的完整类型由 AVFrame->format 这个字段决定,它是一个 enum AVPixelFormat 枚举值。
cpp
// 示例
frame->format = AV_PIX_FMT_YUV420P; // 软件帧
frame->format = AV_PIX_FMT_DRM_PRIME; // 硬件帧
frame->format = AV_PIX_FMT_CUDA; // NVIDIA 硬件帧
硬件帧之间的转换流程
解码 → 硬件帧(DRM_PRIME) → hwupload → 硬件滤镜(scale_rkrga) → hwdownload → 软件帧(NV12) → 编码
↑ ↑
数据留在显存 下载回内存
滤镜链
解码帧 → buffersrc → hwupload → scale_rkrga → buffersink → 输出帧(NV12)
↑
这里强制输出 NV12
buffersink输出 NV12(软件帧)
解码 → buffersrc → hwupload → scale_rkrga → hwdownload → buffersink → NV12(软件帧)
↑
pix_fmts = {NV12}
buffersink输出 DRM_PRIME(硬件帧)
解码 → buffersrc → hwupload → scale_rkrga → buffersink → DRM_PRIME(硬件帧)
↑
pix_fmts = {DRM_PRIME}
落实到具体代码上的差异:
软件帧
硬件帧
enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE};
av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
//滤镜链里面删除hwdownload
const char *filter_descr = "hwupload,scale_rkrga=w=640:h=360:format=nv12";
滤镜链
总体浏览
BOM Management and PCB | Mermaid Chart

| 组件 | 全称 | 角色 | 说明 |
|---|---|---|---|
| 解码输出 | frame |
数据源 | 解码器解出来的原始帧(可能是 YUV、NV12 或 DRM_PRIME) |
| buffersrc | Buffer Source | 入口 | 滤镜图的"入口",把解码帧"喂"进滤镜图 |
| 滤镜链 | Filter Chain | 处理 | 中间的处理环节(缩放、格式转换、硬件上传/下载等) |
| buffersink | Buffer Sink | 出口 | 滤镜图的"出口",从滤镜图"取"出处理后的帧 |
| 编码输入 | filt_frame |
数据消费者 | 从 buffersink 取出的帧,喂给编码器 |
代码示例RGA出硬件帧
1) 创建filter,包括buffersrc,filter,以及buffersink
const AVFilter* buffersrc = avfilter_get_by_name("buffer");
const AVFilter* buffersink = avfilter_get_by_name("buffersink");
AVFilterInOut* outputs = avfilter_inout_alloc();
AVFilterInOut* inputs = avfilter_inout_alloc();
char filter_descr[256];
AVBufferRef* hw_frames_ctx = nullptr;
AVHWFramesContext* frames_ctx = nullptr;
AVBufferSrcParameters* params = nullptr;
AVFilterContext* scale_ctx = nullptr;
snprintf(filter_descr, sizeof(filter_descr),
"scale_rkrga=w=%d:h=%d:format=bgra",
dst_width, dst_height);
std::cout << "Filter: " << filter_descr << std::endl;
filter_graph = avfilter_graph_alloc();
if (!filter_graph || !outputs || !inputs) {
ret = AVERROR(ENOMEM);
goto end;
}
snprintf(args, sizeof(args),
"video_size=%dx%d:pix_fmt=%d:time_base=1/90000",
src_width, src_height, AV_PIX_FMT_DRM_PRIME);
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
args, NULL, filter_graph);
if (ret < 0) goto end;
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
NULL, NULL, filter_graph);
if (ret < 0) goto end;
// enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE};
av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
ret = avfilter_graph_parse_ptr(filter_graph, filter_descr,
&inputs, &outputs, NULL);
if (ret < 0) {
std::cout << "avfilter_graph_parse_ptr failed" << std::endl;
goto end;
}
2) 设置input即buffersrc的frame上下文
hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
if (!hw_frames_ctx) {
ret = AVERROR(ENOMEM);
goto end;
}
frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data;
frames_ctx->format = AV_PIX_FMT_DRM_PRIME;
frames_ctx->sw_format = AV_PIX_FMT_NV12;
frames_ctx->width = src_width;
frames_ctx->height = src_height;
frames_ctx->initial_pool_size = 16;
ret = av_hwframe_ctx_init(hw_frames_ctx);
if (ret < 0) {
std::cout << "av_hwframe_ctx_init failed" << std::endl;
goto end;
}
params = av_buffersrc_parameters_alloc();
params->format = AV_PIX_FMT_DRM_PRIME;
params->width = src_width;
params->height = src_height;
params->time_base = av_make_q(1, 90000);
params->hw_frames_ctx = av_buffer_ref(hw_frames_ctx);
ret = av_buffersrc_parameters_set(buffersrc_ctx, params);
av_free(params);
if (ret < 0) goto end;
3) 设置output的格式
enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE};
av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
帧流转代码
// 1. 解码输出 (AVFrame *frame)
avcodec_receive_frame(decodec_ctx, frame);
// 2. 推入 buffersrc (入口)
av_buffersrc_write_frame(buffersrc_ctx, frame);
// 3. 滤镜链处理 (自动)
// hwupload,scale_rkrga=w=640:h=360:format=nv12
// 4. 从 buffersink 取出 (出口)
av_buffersink_get_frame(buffersink_ctx, filt_frame);
// 5. 编码输入
avcodec_send_frame(encodec_ctx, filt_frame);
context
hw_frames_ctx
hw_frames_ctx 是 硬件帧池的描述符,它描述了一块已经分配好的硬件内存池。
struct AVHWFramesContext {
AVBufferRef *device_ctx; // 指向哪个硬件设备
enum AVPixelFormat format; // 硬件帧格式 (DRM_PRIME/CUDA/VAAPI...)
enum AVPixelFormat sw_format; // 对应的软件格式 (NV12/YUV420P...)
int width, height; // 帧大小
int initial_pool_size; // 内存池大小
// ...
};
上述帧ctx流程
解码器 → hw_frames_ctx A (1600x1200)
↓
scale_rkrga → 创建 hw_frames_ctx B (480x360) ← 新池子!
↓
编码器 → 又创建或使用另一个
加上 上面章节中,不设置input的frame上下文,则在采用硬件帧时报如下错误:
Encoder pix_fmt before open: nv12 (23)
args: video_size=1600x1200:pix_fmt=179:time_base=1/90000:pixel_aspect=0/1
avfilter_graph_parse_ptr success
Found scale_rkrga filter, setting hw_device_ctx
nb_filters: 3
+----------+
| in |default--[0x0 0:0 ?]--Parsed_scale_rkrga_0:default
| (buffer) |
+----------+
+--------------+
Parsed_scale_rkrga_0:default--[0x0 0:0 ?]--default| out |
| (buffersink) |
+--------------+
+----------------------+
in:default--[0x0 0:0 ?]--default| Parsed_scale_rkrga_0 |default--[0x0 0:0 ?]--out:default
| (scale_rkrga) |
+----------------------+
[Parsed_scale_rkrga_0 @ 0x556c292370] No hw context provided on input
[Parsed_scale_rkrga_0 @ 0x556c292370] Failed to configure output pad on Parsed_scale_rkrga_0
avfilter_graph_config failed
init_filters failed
jie 总体而言,此部分功能类似于分配一个内存缓冲池,用于解码端和滤镜端共享处理此帧,而不用拷贝。假设我们自己来实现,也要实现一组buffer及对应的管理。作为解码线程输出帧的存放地,并唤醒RGA线程来消费这一帧,而这共享的buffer管理就可以理解为hw_frames_ctx。
如果不配置此ctx,则默认为软件帧。
解码器类型错误
错误提示:
[hevc @ 0x55879ffd50] Error parsing NAL unit #1.
Error while sending a packet to the decoder
解决方法:
主要从流里获取的解码器可能不对,这里直接指定。
// ❌ 注释掉原来的
// ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decodec, 0);
// if (ret < 0) {
// av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
// return ret;
// }
// ✅ 手动指定硬件解码器
decodec = avcodec_find_decoder_by_name("hevc_rkmpp");
if (!decodec) {
std::cout << "hevc_rkmpp not found" << std::endl;
return -1;
}
// 找到视频流索引
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
return ret;
}
video_stream_index = ret;
video_stream = fmt_ctx->streams[video_stream_index];
硬件帧送入编码
基于目前的配置,采用RGA直出的硬件帧给编码器,最终落盘到文件的数据没有视频。将RGA输出的硬件帧通过下面接口先转换成软件帧则OK。
av_hwframe_transfer_data(sw_frame, filt_frame, 0);
格式转换
滤镜链参数BGRA
//修改滤镜连参数
scale_rkrga=w=%d:h=%d:format=bgra",
eglCreateImageKHR failed
故障报错及采用的配置参数,注意此时的格式参数写死为: BGRA8888
eglCreateImageKHR failed eglCreateImageKHR failed eglCreateImageKHR failed
EGLint attribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_LINUX_DRM_FOURCC_EXT, BGRA8888,
EGL_DMA_BUF_PLANE0_FD_EXT, fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, offset,
EGL_DMA_BUF_PLANE0_PITCH_EXT, pitch,
EGL_NONE
};
实际解码RGA输出的格式
// 在 display_drm_frame 中,desc 里已经有格式信息
AVDRMFrameDescriptor* desc = (AVDRMFrameDescriptor*)frame->data[0];
// ✅ 直接使用 desc 里的四字节格式
uint32_t fourcc = desc->layers[0].format;
std::cout << "DRM fourcc: " << std::hex << fourcc << std::dec << std::endl;
DRM fourcc: 34325241
0x34 = '4'
0x32 = '2'
0x52 = 'R'
0x41 = 'A'
→ "42RA" 倒过来是 "AR24" → ARGB8888
格式不对,因而导入就不对了嘛。所以整条链路要确认好格式,而如果做通用型的,则动态获取,不要写死啦。
系统资源查看
watch -n 1 cat /sys/kernel/debug/rkrga/load
推流搭建
VLC
vlc /home/kylin/1600120060fps.ts --input-repeat=-1 --sout '#rtp{dst=192.168.1.61,port=8554,sdp=rtsp://192.168.1.61:8554/live}'
客户端链接的时候,总是报:461 Unsupported Transport 表示 FFmpeg 和 VLC 的传输协商失败。
mediamtx
https://github.com/bluenviron/mediamtx/releases/tag/v1.20.0
./mediamtx &
ffmpeg -re -i /home/kylin/1600120060fps.ts \
-c copy -f rtsp rtsp://127.0.0.1:8554/live
如果用 -re 推流,ffmpeg 会按文件原始时间戳发送,延迟测量会更准确。
如果推流端没有 -re,文件会以最快速度推流,延迟测量不准确
打印时间戳的推流命令
ffmpeg -re -i /home/kylin/1600120060fps.ts \
-c copy -f rtsp rtsp://127.0.0.1:8554/live \
-debug_ts 2>&1 | grep -E "demuxer|pts"
线程使用scale_rga接口
在主进程中运行上述代码流程,完全没有问题。
而如果把拉流、解码、scale_rga处理放到一个线程中则报如下错误。而采用Timer则也可以正常运行。
Filter: scale_rkrga=w=1920:h=1080:format=bgra
rga_api version 1.10.1_[10]
Filter graph configured successfully
RgaBlit(1507) RGA_BLIT fail: 无效的参数
RgaBlit(1508) RGA_BLIT fail: 无效的参数
handl-fd-vir-phy-hnd-format[0, 68, (nil), (nil), 0, 2560]
rect[0, 0, 1600, 1200, 1792, 1200, 2560, 0]
f-blend-size-rotation-col-log-mmu[2560, 0, 0, 0, 0, 0, 1]
handl-fd-vir-phy-hnd-format[0, 335, (nil), (nil), 0, 768]
rect[0, 0, 1440, 1080, 1440, 1814, 768, 0]
f-blend-size-rotation-col-log-mmu[768, 0, 0, 0, 0, 0, 1]
[Parsed_scale_rkrga_0 @ 0x7f9c045db0] RGA blit failed: -22
RgaBlit(1507) RGA_BLIT fail: 无效的参数
RgaBlit(1508) RGA_BLIT fail: 无效的参数
handl-fd-vir-phy-hnd-format[0, 59, (nil), (nil), 0, 2560]
rect[0, 0, 1600, 1200, 1792, 1200, 2560, 0]
f-blend-size-rotation-col-log-mmu[2560, 0, 0, 0, 0, 0, 1]
handl-fd-vir-phy-hnd-format[0, 335, (nil), (nil), 0, 768]
rect[0, 0, 1440, 1080, 1440, 1814, 768, 0]
f-blend-size-rotation-col-log-mmu[768, 0, 0, 0, 0, 0, 1]
[Parsed_scale_rkrga_0 @ 0x7f9c045db0] RGA blit failed: -22
RgaBlit(1507) RGA_BLIT fail: 无效的参数
RgaBlit(1508) RGA_BLIT fail: 无效的参数
handl-fd-vir-phy-hnd-format[0, 223, (nil), (nil), 0, 2560]
rect[0, 0, 1600, 1200, 1792, 1200, 2560, 0]
f-blend-size-rotation-col-log-mmu[2560, 0, 0, 0, 0, 0, 1]
handl-fd-vir-phy-hnd-format[0, 335, (nil), (nil), 0, 768]
rect[0, 0, 1440, 1080, 1440, 1814, 768, 0]
总结
1) 硬件帧直接进编码器的可行性。
2) scale_rga 在线程操作中的局限性。
3) 拉流对服务端的兼容性。