- 收藏
- 点赞
- 分享
- 举报
hi 3516dv保存 VPSS 处理后的图像数据文件,使用ffplay查看却花屏
我想要保存 VPSS 处理后的图像数据,查看相关图像数据进行处理或者查询。
我在sample_vio_start_vpss这个函数里添加了两条分别保存chn0和chn1处理后的数据并写了两个函数save_nv12和save_rgb24来将其保存为文件,并记录开发板使用时的打印信息,最终成功生成了相关文件,但在虚拟机上使用ffplay命令查看,出现了花屏,这个是为什么,要怎么解决。
以下提供了相关代码和开发板虚拟机打印的信息:
td_s32 sample_vio_start_vpss(ot_vpss_grp grp, sample_vpss_cfg *vpss_cfg) {
td_s32 ret;
sample_vpss_chn_attr vpss_chn_attr = {0};
(td_void)memcpy_s(&vpss_chn_attr.chn_attr[0],
sizeof(ot_vpss_chn_attr) * OT_VPSS_MAX_PHYS_CHN_NUM,
vpss_cfg->chn_attr,
sizeof(ot_vpss_chn_attr) * OT_VPSS_MAX_PHYS_CHN_NUM);
if (g_vio_sys_cfg.vpss_fmu[grp] == OT_FMU_MODE_WRAP) {
vpss_chn_attr.chn0_wrap = TD_TRUE;
}
(td_void)memcpy_s(vpss_chn_attr.chn_enable,
sizeof(vpss_chn_attr.chn_enable),
vpss_cfg->chn_en,
sizeof(vpss_chn_attr.chn_enable));
vpss_chn_attr.chn_array_size = OT_VPSS_MAX_PHYS_CHN_NUM;
ret = sample_common_vpss_start(grp, &vpss_cfg->grp_attr, &vpss_chn_attr);
if (ret != TD_SUCCESS) return ret;
if (vpss_cfg->nr_attr.enable == TD_TRUE) {
if (ss_mpi_vpss_set_grp_3dnr_attr(grp, &vpss_cfg->nr_attr) != TD_SUCCESS) {
goto stop_vpss;
}
}
if (g_vio_sys_cfg.vpss_fmu[grp] == OT_FMU_MODE_OFF) {
const ot_low_delay_info low_delay_info = { TD_TRUE, 200, TD_FALSE };
if (ss_mpi_vpss_set_chn_low_delay(grp, 0, &low_delay_info) != TD_SUCCESS) {
goto stop_vpss;
}
} else if (g_vio_sys_cfg.vpss_fmu[grp] == OT_FMU_MODE_DIRECT) {
if (ss_mpi_vpss_set_chn_fmu_mode(grp, OT_VPSS_DIRECT_CHN, g_vio_sys_cfg.vpss_fmu[grp]) != TD_SUCCESS) {
goto stop_vpss;
}
if (ss_mpi_vpss_enable_chn(grp, OT_VPSS_DIRECT_CHN) != TD_SUCCESS) {
goto stop_vpss;
}
}
if (g_vio_sys_cfg.mode_type != OT_VI_ONLINE_VPSS_ONLINE) {
ot_gdc_param gdc_param = {
.in_size = g_vb_param.vb_size,
.cell_size = OT_LUT_CELL_SIZE_16
};
if (ss_mpi_vpss_set_grp_gdc_param(grp, &gdc_param) != TD_SUCCESS) {
goto stop_vpss;
}
}
ot_video_frame_info vframe;
ret = ss_mpi_vpss_get_chn_frame(grp, OT_VPSS_CHN0, &vframe, 1000);//保存chn0的数据
if (ret == TD_SUCCESS) {
char path[128];
snprintf(path, sizeof(path), "/mnt/nfs/vpss_grp%d_chn0_frm0.nv12", grp);
save_nv12(path, &vframe);
ss_mpi_vpss_release_chn_frame(grp, OT_VPSS_CHN0, &vframe);
}
ret = ss_mpi_vpss_get_chn_frame(grp, OT_VPSS_CHN1, &vframe, 1000);//保存chn1的数据
if (ret == TD_SUCCESS) {
char nv12_path[128], rgb_path[128];
snprintf(nv12_path, sizeof(nv12_path), "/mnt/nfs/vpss_grp%d_chn1_frm0.nv12", grp);
snprintf(rgb_path, sizeof(rgb_path), "/mnt/nfs/vpss_grp%d_chn1_frm0.rgb", grp);
save_nv12(nv12_path, &vframe);
save_rgb24(rgb_path, &vframe);
ss_mpi_vpss_release_chn_frame(grp, OT_VPSS_CHN1, &vframe);
}
return TD_SUCCESS;
stop_vpss:
sample_common_vpss_stop(grp, vpss_cfg->chn_en, OT_VPSS_MAX_PHYS_CHN_NUM);
return TD_FAILURE;
}
函数:
* 将 vframe 的 NV12 / NV21 平面保存为 .nv12 文件(若输入是 NV21 会在写入时把 VU -> UV) */
td_void save_nv12(const char *filename, const ot_video_frame_info *vframe)
{
if (!filename || !vframe) return;
FILE *fp = fopen(filename, "wb");
if (!fp) {
printf("[save_nv12] fopen %s failed: %s\n", filename, strerror(errno));
return;
}
td_u32 w = vframe->video_frame.width;
td_u32 h = vframe->video_frame.height;
td_u32 y_stride = vframe->video_frame.stride[0];
td_u32 c_stride = vframe->video_frame.stride[1];
int pix_fmt = (int)vframe->video_frame.pixel_format; /* sdk enum */
td_u32 chroma_h = (h + 1) / 2;
printf("[save_nv12] file=%s w=%u h=%u stride_y=%u stride_c=%u pix_fmt=%d\n",
filename, w, h, y_stride, c_stride, pix_fmt);
size_t y_bytes = (size_t)y_stride * h;
size_t c_bytes = (size_t)c_stride * chroma_h;
td_u8 *y_addr = (td_u8 *)ss_mpi_sys_mmap(vframe->video_frame.phys_addr[0], y_bytes);
td_u8 *c_addr = (td_u8 *)ss_mpi_sys_mmap(vframe->video_frame.phys_addr[1], c_bytes);
if (y_addr == MAP_FAILED || y_addr == NULL) {
printf("[save_nv12] mmap Y failed\n");
if (y_addr && y_addr != MAP_FAILED) ss_mpi_sys_munmap(y_addr, y_bytes);
if (c_addr && c_addr != MAP_FAILED) ss_mpi_sys_munmap(c_addr, c_bytes);
fclose(fp);
return;
}
if (c_addr == MAP_FAILED || c_addr == NULL) {
printf("[save_nv12] mmap C failed\n");
ss_mpi_sys_munmap(y_addr, y_bytes);
fclose(fp);
return;
}
/* 写 Y 平面 — 每行只写 width 个字节(跳过 stride 的 pad)*/
for (td_u32 i = 0; i < h; i++) {
size_t written = fwrite(y_addr + (size_t)i * y_stride, 1, w, fp);
if (written != w) {
printf("[save_nv12] fwrite Y row %u wrote %zu/%u\n", i, written, (size_t)w);
break;
}
}
/* 写 UV 平面 — 注意 SDK 可能给出的是 NV12(UV) 或 NV21(VU) */
/* NV12: OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420 (U first)
NV21: OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420 (V first) */
int is_nv21 = (pix_fmt == (int)OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420);
/* 临时缓冲(宽度一行)用于 NV21 -> 转换到 UV 顺序 */
uint8_t *tmp_row = NULL;
if (is_nv21) {
tmp_row = malloc(w);
if (!tmp_row) {
printf("[save_nv12] malloc tmp_row failed\n");
ss_mpi_sys_munmap(y_addr, y_bytes);
ss_mpi_sys_munmap(c_addr, c_bytes);
fclose(fp);
return;
}
}
for (td_u32 r = 0; r < chroma_h; r++) {
td_u8 *src = c_addr + (size_t)r * c_stride;
if (!is_nv21) {
/* NV12,直接写 width 个字节(U V U V ...) */
size_t written = fwrite(src, 1, w, fp);
if (written != w) {
printf("[save_nv12] fwrite C row %u wrote %zu/%u\n", r, written, (size_t)w);
break;
}
} else {
/* NV21 (V U),需要每对交换为 U V 写入 */
for (td_u32 j = 0; j < w; j += 2) {
/* 输入: src[j] = V, src[j+1] = U -> 输出希望 U,V */
td_u8 v = src[j];
td_u8 u = src[j + 1];
tmp_row[j] = u;
tmp_row[j + 1] = v;
}
size_t written = fwrite(tmp_row, 1, w, fp);
if (written != w) {
printf("[save_nv12] fwrite swapped C row %u wrote %zu/%u\n", r, written, (size_t)w);
break;
}
}
}
if (tmp_row) free(tmp_row);
ss_mpi_sys_munmap(y_addr, y_bytes);
ss_mpi_sys_munmap(c_addr, c_bytes);
fclose(fp);
printf("[save_nv12] saved ok: %s\n", filename);
}
/* 将 NV12/NV21 转为 RGB24 并保存为 .rgb(每像素3字节,RGB24) */
td_void save_rgb24(const char *filename, const ot_video_frame_info *vframe)
{
if (!filename || !vframe) return;
FILE *fp = fopen(filename, "wb");
if (!fp) {
printf("[save_rgb24] fopen %s failed: %s\n", filename, strerror(errno));
return;
}
td_u32 w = vframe->video_frame.width;
td_u32 h = vframe->video_frame.height;
td_u32 y_stride = vframe->video_frame.stride[0];
td_u32 c_stride = vframe->video_frame.stride[1];
int pix_fmt = (int)vframe->video_frame.pixel_format;
td_u32 chroma_h = (h + 1) / 2;
printf("[save_rgb24] file=%s w=%u h=%u stride_y=%u stride_c=%u pix_fmt=%d\n",
filename, w, h, y_stride, c_stride, pix_fmt);
size_t y_bytes = (size_t)y_stride * h;
size_t c_bytes = (size_t)c_stride * chroma_h;
td_u8 *y_addr = (td_u8 *)ss_mpi_sys_mmap(vframe->video_frame.phys_addr[0], y_bytes);
td_u8 *c_addr = (td_u8 *)ss_mpi_sys_mmap(vframe->video_frame.phys_addr[1], c_bytes);
if (y_addr == MAP_FAILED || y_addr == NULL) {
printf("[save_rgb24] mmap Y failed\n");
if (y_addr && y_addr != MAP_FAILED) ss_mpi_sys_munmap(y_addr, y_bytes);
if (c_addr && c_addr != MAP_FAILED) ss_mpi_sys_munmap(c_addr, c_bytes);
fclose(fp);
return;
}
if (c_addr == MAP_FAILED || c_addr == NULL) {
printf("[save_rgb24] mmap C failed\n");
ss_mpi_sys_munmap(y_addr, y_bytes);
fclose(fp);
return;
}
int is_nv21 = (pix_fmt == (int)OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420);
for (td_u32 i = 0; i < h; i++) {
td_u8 *y_row = y_addr + (size_t)i * y_stride;
td_u8 *c_row = c_addr + (size_t)(i / 2) * c_stride;
for (td_u32 j = 0; j < w; j++) {
td_u8 Y = y_row[j];
td_u8 U, V;
if (!is_nv21) {
/* NV12: U,V order in chroma: [U0 V0][U1 V1]... */
U = c_row[(j & ~1) + 0];
V = c_row[(j & ~1) + 1];
} else {
/* NV21: V,U order: [V0 U0][V1 U1]... */
V = c_row[(j & ~1) + 0];
U = c_row[(j & ~1) + 1];
}
/* YUV -> RGB (BT.601) 使用整数近似可以更快,也可以用浮点 */
int C = (int)Y - 16;
int D = (int)U - 128;
int E = (int)V - 128;
/* 使用常见的固定点系数组(避免大量浮点) */
int R = (298 * C + 409 * E + 128) >> 8;
int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
int B = (298 * C + 516 * D + 128) >> 8;
if (R < 0) R = 0; else if (R > 255) R = 255;
if (G < 0) G = 0; else if (G > 255) G = 255;
if (B < 0) B = 0; else if (B > 255) B = 255;
uint8_t out[3] = { (uint8_t)R, (uint8_t)G, (uint8_t)B };
fwrite(out, 1, 3, fp);
}
}
ss_mpi_sys_munmap(y_addr, y_bytes);
ss_mpi_sys_munmap(c_addr, c_bytes);
fclose(fp);
printf("[save_rgb24] saved ok: %s\n", filename);
}
这是开发板打印的信息:
~ # ./mpp_mo
Sample VIO Start!
vi vpss mode list:
(0) VI_ONLINE_VPSS_ONLINE, FMU OFF
(1) VI_ONLINE_VPSS_OFFLINE, FMU OFF
(2) VI_OFFLINE_VPSS_OFFLINE, FMU DIRECT
(3) VI_OFFLINE_VPSS_OFFLINE, FMU OFF
please select mode:
1
[MPP] Version: [HI3519DV500_MPP_V2.0.2.0 B050 Release], Build Time[Dec 20 2024, 16:23:07]
linear mode
vi_pipe:0,== os04a10 24Mclk 4M30fps(MIPI) 12bit linear init success! ==
ISP Dev 0 running !
[INFO] VPSS配置:CHN0=1080P YUV,CHN1=640x640 YUV
[save_nv12] file=/mnt/nfs/vpss_grp0_chn0_frm0.nv12 w=2688 h=1520 stride_y=2688 stride_c=2688 pix_fmt=38
[save_nv12] saved ok: /mnt/nfs/vpss_grp0_chn0_frm0.nv12
[save_nv12] file=/mnt/nfs/vpss_grp0_chn1_frm0.nv12 w=640 h=640 stride_y=640 stride_c=640 pix_fmt=38
[save_nv12] saved ok: /mnt/nfs/vpss_grp0_chn1_frm0.nv12
[save_rgb24] file=/mnt/nfs/vpss_grp0_chn1_frm0.rgb w=640 h=640 stride_y=640 stride_c=640 pix_fmt=38
[save_rgb24] saved ok: /mnt/nfs/vpss_grp0_chn1_frm0.rgb
[sample_vio_start_venc_and_vo]-70: [INFO] VPSS grp=0 -> VENC chn=0 绑定成功
start vo dhd0.
mipi intf sync = 23
———————-press enter key to exit!———————-
Sample VIO Exit!
~ #
这是虚拟机记录的信息:
lubancat@ubuntu:~/mnt/nfs$ ls -l
total 177576
-rw-rw-r— 1 lubancat lubancat 121 Jul 18 01:39 helloworld.c
-rwxrwxr-x 1 lubancat lubancat 3205400 Sep 2 01:41 mpp_enc
-rwxrwxr-x 1 lubancat lubancat 3209496 Sep 4 01:00 mpp_mo
-rw-r—r— 1 lubancat lubancat 164286633 Sep 2 01:06 stream_chn0.h265
-rw-rw-r— 1 lubancat lubancat 0 Aug 12 20:05 test_from_server.txt
-rwxrwxr-x 1 lubancat lubancat 3143544 Aug 12 20:50 venc_4mp_demo
-rw-r——- 1 lubancat lubancat 6128640 Sep 4 01:00 vpss_grp0_chn0_frm0.nv12
-rw-r——- 1 lubancat lubancat 614400 Sep 4 01:00 vpss_grp0_chn1_frm0.nv12
-rw-r——- 1 root root 1228800 Sep 4 01:01 vpss_grp0_chn1_frm0.rgb
lubancat@ubuntu:~/mnt/nfs$ ffplay -f rawvideo -pixel_format nv12 -video_size 640x640 -framerate 30 vpss_grp0_chn1_frm0.nv12
ffplay version 4.2.7-0ubuntu0.1 Copyright (c) 2003-2022 the FFmpeg developers
built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
configuration: —prefix=/usr —extra-version=0ubuntu0.1 —toolchain=hardened —libdir=/usr/lib/x86_64-linux-gnu —incdir=/usr/include/x86_64-linux-gnu —arch=amd64 —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-nvenc —enable-chromaprint —enable-frei0r —enable-libx264 —enable-shared
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
[rawvideo @ 0x7f761c000bc0] Estimating duration from bitrate, this may be inaccurate
Input #0, rawvideo, from ‘vpss_grp0_chn1_frm0.nv12’:
Duration: 00:00:00.03, start: 0.000000, bitrate: 147457 kb/s
Stream #0:0: Video: rawvideo (NV12 / 0x3231564E), nv12, 640x640, 147456 kb/s, 30 tbr, 30 tbn, 30 tbc
33.10 M-V: -0.000 fd= 0 aq= 0KB vq= 0KB sq= 0B f=0/0
lubancat@ubuntu:~/mnt/nfs$ ls
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片
-
2019-07-08 09:21:28
-
2025-11-11 17:09:01
-
2017-01-20 14:16:46
-
2017-01-20 14:50:52
-
2019-11-25 18:36:13
-
2017-03-01 17:04:08
-
2019-01-11 11:09:35
-
2018-12-27 09:28:26
-
2016-12-01 14:50:16
-
2018-06-07 09:34:52
-
2020-09-24 14:56:53
-
2017-08-15 11:28:28
-
2018-12-12 17:26:34
-
2018-07-26 13:47:15
-
2020-07-10 12:15:14
-
2018-12-26 15:06:23
-
2014-01-02 11:32:38
-
2019-11-08 09:45:01
-
2019-07-09 10:17:13
-
5hisi3516cv610 + gc4336p 夜晚很模糊
-
5AIISP(功能演示,SC4336P为BGGR,强制转RGGB,会导致颜色异常)
-
5rv1106使用luckfox的SDK,设备树和驱动都写好了,结果设备文件没有生成
-
5海思3516cv610中如何进行SD卡升级,根据官方文档操作,烧录进板子时,走的默认uboot,没有执行uboot升级。
-
5G610Q-IPC-38E 夜晚很暗 有什么办法解决吗 已经补光了
-
10转换模型时,SoC版本里没显示hi3516cv610芯片
-
5hisi3516cv610 使用 yolov8n 模型训练 要如何提高 这里识别的是人
-
10有人在海思平台接过SC035HGS吗
-
5关于hi3519dv500,以SD卡虚拟 U 盘操作
-
5ss928 sample_venc代码移植到openEuler24.03上执行报错 [sample_comm_vi_start_dev]-1068: vi set dev attr failed wi
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明

微信扫码分享
QQ好友