普希金的笔

普希金的笔

0个粉丝

5

问答

0

专栏

0

资料

普希金的笔  发布于  2025-09-04 16:26:13
采纳率 0%
5个问答
392

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]

bus_id:3

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

我来回答
回答4个
时间排序
认可量排序

UncleRoderick

59个粉丝

16

问答

4

专栏

20

资料

UncleRoderick 2025-09-04 17:35:05
认可1

试试用yuvplayer这种软件直接看看

普希金的笔
普希金的笔   回复   UncleRoderick  2025-09-04 18:15:31
0

试过了,还是花屏,但使用ffplay播放视频编码画面正常

ღ过客᭄ꦿ࿐

0个粉丝

16

问答

3

专栏

6

资料

ღ过客᭄ꦿ࿐ 2025-10-11 16:30:32
认可0

给你个建议,直接保存vframe中的视频数据到文件就行;不用按y u v存这样比较麻烦;
你可以试试直接保存vframe中的视频数据到文件,播放有没有问题,如果有问题就是你的存储方式有问题

fc

0个粉丝

0

问答

0

专栏

1

资料

fc 2025-10-21 19:29:55
认可0

能确定yuv的格式吗,vpss如果输出是私有格式的yuv送给后级enc,然后enc可以正常编码 h26x 码流

或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区