昇腾venc编码只能编码yuv420sp,不能使用yuvj420p和yuv420p
收藏回复举报
昇腾venc编码只能编码yuv420sp,不能使用yuvj420p和yuv420p
t('forum.solved') 已解决
发表于2024-09-14 10:27:07
0 查看

核心问题

使用ffmpeg拉流并解码后,将AVFrame解码后的yuvj420p数据发送给venc编码失败

我的尝试

更换编码格式

将HI_PIXEL_FORMAT_YUV_PLANAR_420换为HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420,即yuv420p格式换为420sp格式,并将avframe中的数据转换为yuv420sp格式后,成功编码,推测不是通道配置问题

将avframe中的yuvj420p数据改为yuv420p数据,采用HI_PIXEL_FORMAT_YUV_PLANAR_420格式,依旧失败

报错内容

[ERROR][/root/workspace/ascend-dvpp-rtsp-encode/src/Dvpp_encode.cpp:175]  hi_mpi_venc_send_frame failed,error=A0088008

代码参数

int Dvpp_encode::dvpp_init()
{
    hi_s32 ret = 0;
    ret = hi_mpi_sys_init();
    if (ret != HI_SUCCESS)
    {
        ERROR_LOG("hi_mpi_sys_init failed ret:%x", ret);
        return -1;
    }
    hi_venc_chn chn = 0;
    hi_venc_chn_attr attr{};
    memset(&attr, 0, sizeof(hi_venc_chn_attr));
    attr.venc_attr.type = HI_PT_H264;
    attr.venc_attr.profile = 0;
    attr.venc_attr.max_pic_width = 640;
    attr.venc_attr.max_pic_height = 640;
    attr.venc_attr.pic_width = 640;
    attr.venc_attr.pic_height = 640;
    attr.venc_attr.buf_size = 640 * 640 * 3;
    attr.venc_attr.is_by_frame = HI_TRUE;
    attr.rc_attr.rc_mode = HI_VENC_RC_MODE_H264_VBR;
    attr.rc_attr.h264_vbr.gop = 30;
    attr.rc_attr.h264_vbr.stats_time = 1;
    attr.rc_attr.h264_vbr.src_frame_rate = 25;
    attr.rc_attr.h264_vbr.dst_frame_rate = 25;
    attr.rc_attr.h264_vbr.max_bit_rate = 4000;
    attr.gop_attr.gop_mode = HI_VENC_GOP_MODE_NORMAL_P;
    attr.gop_attr.normal_p.ip_qp_delta = 3;
    ret = hi_mpi_venc_create_chn(chn, &attr);
    if (ret != 0)
    {
        ERROR_LOG("hi_mpi_venc_create_chn failed");
        return -1;
    }

    // 5.通知编码器启动接收输入数据
    hi_venc_start_param recv_param{};
    recv_param.recv_pic_num = -1;
    ret = hi_mpi_venc_start_chn(chn, &recv_param);

    return 0;
}
int Dvpp_encode::enc(yuv_block &yuv)
{
    int ret;

    hi_venc_chn chn = 0;
    hi_video_frame_info frame{};
    memset(&frame, 0, sizeof(hi_video_frame_info));
    frame.mod_id = HI_ID_VENC;

    frame.v_frame.width = 640;
    frame.v_frame.height = 640;
    frame.v_frame.field = HI_VIDEO_FIELD_FRAME;
    // frame.v_frame.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
    frame.v_frame.pixel_format = HI_PIXEL_FORMAT_YUV_PLANAR_420;
    // frame.v_frame.pixel_format = HI_PIXEL_FORMAT_RGB_888;
    frame.v_frame.video_format = HI_VIDEO_FORMAT_LINEAR;
    frame.v_frame.compress_mode = HI_COMPRESS_MODE_NONE;
    // 预留参数
    //  frame.v_frame.dynamic_range = HI_DYNAMIC_RANGE_SDR8;
    //  frame.v_frame.color_gamut = HI_COLOR_GAMUT_BT709;


// 输入数据没问题,检测过了,是device数据且步长为640,320,320
    frame.v_frame.virt_addr[0] = yuv.data[0];
    frame.v_frame.virt_addr[1] = yuv.data[1];
    frame.v_frame.virt_addr[2] = yuv.data[2];
    frame.v_frame.width_stride[0] = yuv.linesize[0];
    frame.v_frame.width_stride[1] = yuv.linesize[1];
    frame.v_frame.width_stride[2] = yuv.linesize[2];
    
    
    

    unsigned int idx = 0;
    /*是否使能slice_temporal_mvp_enabled_flag语法(表示帧间预测是否使用时域MV(MotionVector)预测),
    取值范围如下,但仅H265协议下该参数生效:
0:slice_temporal_mvp_enabled_flag为True,表示使用时域MV预测。
1:slice_temporal_mvp_enabled_flag为False,表示不使用时域MV预测。*/
    frame.v_frame.frame_flag = 1;
    // VENC编码场景下,针对每一帧设置该参数时,按照帧的顺序,该参数值需递增且为偶数,例如,第一帧时该参数值设置为2,第二帧时该参数值设置为4,以此类推。
    frame.v_frame.time_ref = idx * 2;
    // 图像时间戳。
    frame.v_frame.pts = idx * 30;
    idx++;

    ret = hi_mpi_venc_send_frame(chn, &frame, 1000);
    if (ret != 0)
    {
        ERROR_LOG("hi_mpi_venc_send_frame failed,error=%X", ret);
        return -1;
    }
    else
    {
        INFO_LOG("hi_mpi_venc_send_frame %d success", idx - 1);
    }
    int32_t epollFd = 0;
    int32_t fd = hi_mpi_venc_get_fd(0);
    // 预留字段,传入正数
    ret = hi_mpi_sys_create_epoll(1, &epollFd);
    if (ret != 0)
    {
        ERROR_LOG("hi_mpi_sys_create_epoll failed");
        return -1;
    }
    hi_dvpp_epoll_event event;
    event.events = HI_DVPP_EPOLL_IN;
    event.data = (void *)(unsigned long)(fd);
    ret = hi_mpi_sys_ctl_epoll(epollFd, HI_DVPP_EPOLL_CTL_ADD, fd, &event);

    int32_t eventCount = 0;
    // 编码完成前,会超时阻塞在这里,一旦完成,才会往下执行
    ret = hi_mpi_sys_wait_epoll(epollFd, &event, 3, 1000, &eventCount);
    if (ret != 0)
    {
        ERROR_LOG("hi_mpi_sys_wait_epoll failed");
        return -1;
    }
    hi_venc_chn_status stat;
    ret = hi_mpi_venc_query_status(chn, &stat);

    INFO_LOG("当前帧的码流包个数=%d", stat.cur_packs);

    hi_venc_stream stream;
    stream.pack_cnt = stat.cur_packs;
    stream.pack = new hi_venc_pack[stream.pack_cnt];
    ret = hi_mpi_venc_get_stream(chn, &stream, 1000);
    if (ret != 0)
    {
        ERROR_LOG("hi_mpi_venc_get_stream failed");
        return -1;
    }

    for (int i = 0; i < stream.pack_cnt; i++)
    {
        std::string out_path = std::to_string(i) + ".h264";
        FILE *fp = fopen(out_path.c_str(), "wb");                   // 打开文件用于写入二进制数据
        fwrite(stream.pack[i].addr, 1, stream.pack[i].len * 2, fp); // 写入数据到文件
        std::cout << "sucess" << std::endl;
        fclose(fp);

        char cmd[500];
        sprintf(cmd, "ffmpeg -i %s -c:v mjpeg %d.jpg", out_path.c_str(), i);

        system(cmd);
    }
    // 8.释放输入内存和输出码流
    ret = hi_mpi_venc_release_stream(chn, &stream);
    delete[] stream.pack;

    return 0;
}

我要发帖子