君正x2000音视频多路编码实现

准备资料

一、硬件资源

可以看到x2000是拥有2个ISP模块的。

选择通过ISP模块时,camera 设备节点名为 mscaler。

  • 开启单摄时为 mscaler0 或 mscaler1,对应的是 sensor0 或 sensor1;
  • 开启双摄时为 mscaler0 和 mscaler1,分别对应 sensor0 和 sensor1;
  • 每个mscaler支持3个 channel,故完整的设备名为 mscalerx-chx.

mscaler0-ch0 表示isp0,通道0的设备节点。

从框图看,sensor0和sensor1都有对应的独立ISP,以我的开发板为例,RGB摄像头接的是MIPI-CSI 1,即对应的设备节点为mscaler1,可以利用mscaler1-ch0和mscaler1-ch1实现一个双通道编码应用。

二、编码节点

X2000将vpu分为felix和helix两部分:

  • felix是h264解码,包括:流解析器、运动补偿、反量化、IDCT和De-block engines的功能。
  • helix是h264编码、JPEG压缩和解压缩。

三、设计需求

  • 设计两个通道,分别为主码流和子码流。
  • 主码流参数:1080p@30fps,H264编码,以文件形式保存;
  • 子码流参数:720p@30fps,H264编码,以文件形式保存;

四、设计思路

再回到数据流框图

也就是说,sensor的mipi数据通过,VIC单元控制送如ISP模块,再通过Mscaler节点输出,因此只需要从对应的Mscaler节点拿到sensor数据,然后送给/dev/video1编码器节点进行编码即可。

五、代码实现

参考君正给的SDK内的demo加以修改,路径:ingenic/x2000/libisp/src/demo/

ISP格式配置——

/* isp格式配置 */
static struct frame_image_format output_fmt_main = {
    .width              = 1920,
    .height             = 1080,
    .pixel_format       = CAMERA_PIX_FMT_NV12,

    .scaler.enable      = 0,
    .scaler.width       = 0,
    .scaler.height      = 0,

    .frame_nums         = 2,
};

static struct frame_image_format output_fmt_sub = {
    .width              = 1280,
    .height             = 720,
    .pixel_format       = CAMERA_PIX_FMT_NV12,

    .scaler.enable      = 0,
    .scaler.width       = 0,
    .scaler.height      = 0,

    .frame_nums         = 2,
};

ISP初始化——

参考这个流程图

static int init_isp_camera(char * isp_cam_path, struct frame_image_format * pformat, struct camera_info * info)
{
    int ret;
    int fd;

    fd = isp_open(isp_cam_path);
    if (fd < 0) {
        fprintf(stderr, "isp open failed\n");
        return -1;
    }

    ret = isp_get_sensor_info(fd, info);
    if (ret < 0) {
        fprintf(stderr, "isp get sensor info failed\n");
        goto close_isp;
    }

    if (pformat->width != 0 || pformat->height != 0)
        pformat->scaler.enable = 1;

    pformat->scaler.width = pformat->width ? pformat->width : info->width;
    pformat->scaler.height = pformat->height ? pformat->height : info->height;

    pformat->width = pformat->scaler.width;
    pformat->height = pformat->scaler.height;

    ret = isp_set_format(fd, pformat);
    if (ret < 0) {
        fprintf(stderr, "isp set format failed\n");
        goto close_isp;
    }

    ret = isp_requset_buffer(fd, pformat);
    if (ret < 0) {
        fprintf(stderr, "isp set request buffer failed\n");
        goto close_isp;
    }

    isp_get_info(fd, info);

    ret = isp_mmap(fd, info);
    if (ret < 0)
        goto free_isp_buffer;

    ret = isp_power_on(fd);
    if (ret < 0)
        goto free_isp_buffer;

    ret = isp_stream_on(fd);
    if (ret < 0)
        goto power_off_isp;

    return fd;

power_off_isp:
    isp_power_off(fd);
free_isp_buffer:
    isp_free_buffer(fd);
close_isp:
    isp_close(fd, info);

    return -1;
}

主码流实现——

void * main_stream_thread(void * arg)
{
    struct v4l2_h264_encoder_config config;
    struct frame_info frame_info;
    int res = 0;
    int frame_cnt = 0;
    int output_size = 0;

    menc_cfg_main.isp_path = malloc(20);
    menc_cfg_main.output_file_path = malloc(20);
    menc_cfg_main.encoder_path = malloc(20);

    memmove(menc_cfg_main.output_file_path, "output00", 9);
    memmove(menc_cfg_main.isp_path, "/dev/mscaler1-ch0", 18);
    memmove( menc_cfg_main.encoder_path, "/dev/video1", 12);

    menc_cfg_main.camera_fd = -1;
    menc_cfg_main.output_file_fd = -1;

    memset(&config, 0, sizeof(struct v4l2_h264_encoder_config));

    menc_cfg_main.camera_fd = init_isp_camera(menc_cfg_main.isp_path, &output_fmt_main, &menc_cfg_main.camera_info);
    if (menc_cfg_main.camera_fd < 0) {
        fprintf(stderr, "Init isp camera failed\n");
        goto exit;
    }

    config.video_path = menc_cfg_main.encoder_path;
    config.width = output_fmt_main.width;
    config.height = output_fmt_main.height;
    config.line_length = menc_cfg_main.camera_info.line_length;
    config.input_fmt = menc_cfg_main.camera_info.data_fmt;
    config.gop_size = 10;
    config.bitrate = 400000;

    menc_cfg_main.encoder = v4l2_h264_encoder_open(&config); 
    if (!menc_cfg_main.encoder) {
        fprintf(stderr, "Uanble to open v4l2 h264 encoder\n");
        res = -1;
        goto close_isp_cam;
    }

    menc_cfg_main.output_file_fd = open(menc_cfg_main.output_file_path, O_RDWR | O_CREAT | O_TRUNC);
    if ( menc_cfg_main.output_file_fd < 0) {
        fprintf(stderr, "open file %s error.\n", menc_cfg_main.output_file_path);
        goto close_encoder;
    }

    while (1)
    {
        res = isp_dqbuf_wait(menc_cfg_main.camera_fd, &frame_info);
        if (res){
            fprintf(stderr, "isp_dqbuf_waitopen file %s error.\n");
            goto close_file;
        }

        if (frame_cnt == 5){
            v4l2_h264_encoder_set_keyframe(menc_cfg_main.encoder);
        }

        void *mem = v4l2_h264_encoder_work_by_phy_mem(menc_cfg_main.encoder, frame_info.vaddr, frame_info.paddr, &output_size);
        if (!mem) {
            fprintf(stderr, "V4l2 h264 encode work failed, ret : %d, %p\n", res, mem);
            res = -1;
            goto close_file;
        }

        isp_put_frame(menc_cfg_main.camera_fd, frame_info.vaddr);

        write(menc_cfg_main.output_file_fd, mem, output_size);

        if (frame_cnt++ >= 120){
            break;
        }
    }

    fprintf(stderr, "frame_cnt:%d\r\n",frame_cnt);

close_file:
    close(menc_cfg_main.output_file_fd);
close_encoder:
    v4l2_h264_encoder_close(menc_cfg_main.encoder);
close_isp_cam:
    deinit_isp_camera(menc_cfg_main.camera_fd, &menc_cfg_main.camera_info);
exit:
    menc_cfg_main.camera_fd = -1;

    fprintf(stderr, "main_stream_thread exit\r\n");
}

 子码流实现——

void * sub_stream_thread(void * arg)
{
    struct v4l2_h264_encoder_config config;
    struct frame_info frame_info;
    int res = 0;
    int frame_cnt = 0;
    int output_size = 0;

    menc_cfg_sub.isp_path = malloc(20);
    menc_cfg_sub.output_file_path = malloc(20);
    menc_cfg_sub.encoder_path = malloc(20);

    memmove(menc_cfg_sub.output_file_path, "output01", 9);
    memmove(menc_cfg_sub.isp_path, "/dev/mscaler1-ch1", 18);
    memmove( menc_cfg_sub.encoder_path, "/dev/video1", 12);

    menc_cfg_sub.camera_fd = -1;
    menc_cfg_sub.output_file_fd = -1;

    memset(&config, 0, sizeof(struct v4l2_h264_encoder_config));

    menc_cfg_sub.camera_fd = init_isp_camera(menc_cfg_sub.isp_path, &output_fmt_sub, &menc_cfg_sub.camera_info);
    if (menc_cfg_sub.camera_fd < 0) {
        fprintf(stderr, "Init isp camera failed\n");
        goto exit;
    }

    config.video_path = menc_cfg_sub.encoder_path;
    config.width = output_fmt_sub.width;
    config.height = output_fmt_sub.height;
    config.line_length = menc_cfg_sub.camera_info.line_length;
    config.input_fmt = menc_cfg_sub.camera_info.data_fmt;
    config.gop_size = 10;
    config.bitrate = 400000;

    menc_cfg_sub.encoder = v4l2_h264_encoder_open(&config); 
    if (!menc_cfg_sub.encoder) {
        fprintf(stderr, "Uanble to open v4l2 h264 encoder\n");
        res = -1;
        goto close_isp_cam;
    }

    menc_cfg_sub.output_file_fd = open(menc_cfg_sub.output_file_path, O_RDWR | O_CREAT | O_TRUNC);
    if ( menc_cfg_sub.output_file_fd < 0) {
        fprintf(stderr, "open file %s error.\n", menc_cfg_sub.output_file_path);
        goto close_encoder;
    }

    while (1)
    {
        res = isp_dqbuf_wait(menc_cfg_sub.camera_fd, &frame_info);
        if (res){
            fprintf(stderr, "isp_dqbuf_waitopen file %s error.\n");
            goto close_file;
        }

        if (frame_cnt == 5){
            v4l2_h264_encoder_set_keyframe(menc_cfg_sub.encoder);
        }

        void *mem = v4l2_h264_encoder_work_by_phy_mem(menc_cfg_sub.encoder, frame_info.vaddr, frame_info.paddr, &output_size);
        if (!mem) {
            fprintf(stderr, "V4l2 h264 encode work failed, ret : %d, %p\n", res, mem);
            res = -1;
            goto close_file;
        }

        isp_put_frame(menc_cfg_sub.camera_fd, frame_info.vaddr);

        write(menc_cfg_sub.output_file_fd, mem, output_size);

        if (frame_cnt++ >= 120){
            break;
        }
    }

    fprintf(stderr, "frame_cnt:%d\r\n",frame_cnt);

close_file:
    close(menc_cfg_sub.output_file_fd);
close_encoder:
    v4l2_h264_encoder_close(menc_cfg_sub.encoder);
close_isp_cam:
    deinit_isp_camera(menc_cfg_sub.camera_fd, &menc_cfg_sub.camera_info);
exit:
    menc_cfg_sub.camera_fd = -1;

    fprintf(stderr, "sub_stream_thread exit\r\n");
}

main函数实现——

int main(void)
{
    int res = 0;

    signal(SIGINT, signal_handler);

    res = pthread_create(&main_stream_thread_id, NULL, main_stream_thread, NULL);
    if(res != 0){
        printf("main stream pthread create failed.\r\n");
    }

    res = pthread_create(&sub_stream_thread_id, NULL, sub_stream_thread, NULL);
    if(res != 0){
        printf("sub stream pthread create failed.\r\n");
    }

    while (1)
    {
        sleep(1);
    }

    fprintf(stderr, "exit.\n");

    return 0;
}

板端执行——

 输出名为output00和output01的两个h264文件

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值