UVC网络摄像头(三) X264

本文介绍了使用X264进行网络摄像头视频编码的步骤,包括编码器初始化、YUV数据转换、编码过程以及编码器的关闭。重点指出V4L2采集的422数据需转换为420格式才能进行编码,并且在编码过程中,可能需要填充多帧数据才能开始成功编码。
摘要由CSDN通过智能技术生成

X264部分代码

1.编码器初始化

int Init_x264(int width,int height,Encoder *encode)
{
    encode->pNals = NULL;  
    encode->pHandle = NULL;  
    encode->pPic_in = (x264_picture_t*)malloc(sizeof(x264_picture_t));  
    encode->pPic_out = (x264_picture_t*)malloc(sizeof(x264_picture_t)); 
    encode->pParam = (x264_param_t*)malloc(sizeof(x264_param_t)); 

    x264_param_default(encode->pParam);  
    /*******基本参数*****************/
    encode->pParam->i_width   = width;                          //图像宽度
    encode->pParam->i_height  = height;                         //图像高度
    encode->pParam->i_threads  = X264_SYNC_LOOKAHEAD_AUTO;      //并行编码,X264_SYNC_LOOKAHEAD_AUTO为自动选择
    encode->pParam->i_frame_total = 0;                          //编辑图像的总帧数,不确定就为0
    encode->pParam->i_csp       =   X264_CSP_I420;              //输入图像格式
    //encode->pParam->i_log_level  = X264_LOG_DEBUG;        //调试模式,将编码的信息显示在logcat上

    /*******编码流参数*************/
    encode->pParam->i_keyint_max = 10;                          //DIR帧最大间隔数
    encode->pParam->i_bframe  = 5;                              //相关图像间P帧的数目
    encode->pParam->b_open_gop  = 0; 
    encode->pParam->i_bframe_pyramid = 0;                       //允许部分b帧为参考帧
    encode->pParam->rc.i_qp_constant=0; 

    /******码率控制参数***************/
    encode->pParam->rc.i_qp_max=0;                              //允许的最大量化值      
    encode->pParam->rc.i_qp_min=0;                              //允许的最小量化值
    //encode->pParam->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; 
    encode->pParam->rc.i_bitrate       = m_nBitrate
    //encode->pParam->rc.i_rc_method = X264_RC_ABR;             //参数i_rc_method表示码率控制,CQP(恒定质量),CRF(恒定码率),ABR(平均码率) 

    /********fps参数***********/
    encode->pParam->i_fps_den  = 1;                             //时间基数(1s)
    encode->pParam->i_fps_num  = 30;                            //帧率(30帧)
    encode->pParam->b_vfr_input = 0;                            // 使用timebase和时间戳做码率控制 0:只使用fps做码率控制  
    encode->pParam->i_timebase_den = encode->pParam->i_fps_num; //
    encode->pParam->i_timebase_num = encode->pParam->i_fps_den; //
    encode->pParam->b_repeat_headers = 1;                       //重复SPS/PPS 放到关键帧前面:I帧前都附加SPS、PPS

    x264_param_apply_profile(encode->pParam, x264_profile_names[0]);    /**应用刚才设置的参数**/
                                                                         //x264_profile_names数组定义如下:static const char * const x264_profile_names[] =   
                                                                        //{ "baseline", "main", "high", "high10", "high422", "high444", 0 };
    encode->pHandle=x264_encoder_open(encode->pParam);                  //根据设置参数打开对应的编码器
    x264_picture_init(encode->pPic_out);                                //初始化输出的缓存
    x264_picture_alloc(encode->pPic_in,encode->pParam->i_csp,encode->pParam->i_width, encode->pParam->i_height); 

    encode->pPic_in->i_pts=0;

    return 0;
}

2.转换

由于V4L2采集的数据是422的数据,这里放入编码器前面先转换成420的,不然编码不了(可以用yuvplayer之类的工具看采集的原始视屏)

int Yuv422toYuv420(int width,int hight,char *yuy2,char *yuv420)
{
    memset(yuv420,0,sizeof(char)*width*hight*3/2);
    char *u = yuv420+hight*width;
    char *v = u+hight*width/4;
    int i=0,j=0;

    for (i = 0; i <hight/2;i++) {
        char *src_l1=(yuy2+width*2*2*i);
        char *src_l2=(src_l1+width*2);
        char *y_l1=yuv420+width*2*i;
        char *y_l2=y_l1+width;
        for(j=0;j<width/2;j++)
        {
            *y_l1++=src_l1[0];
            *u++=src_l1[1];
            *y_l1++=src_l1[2];
            *v++=src_l1[3];
            *y_l2++=src_l2[0];
            *y_l2++=src_l2[2];
            src_l1+=4;
            src_l2+=4;
        }
    }
    return 0;
}

3.编码

编码器内部的具体过程我没详细看过,但是要先要填充一定数量的帧数据才能开始编码并不是放一帧数据马上编码这一帧,放进去了一帧数据但是得到的NAL貌似是前面的帧数据,我调试的时候要放20帧的数据才能开始成功编码,所以如果不在放入数据而要得到编码器里面缓存的数据的话要进行flush encoder

/************参数********************
    char * yuv420   :一帧数据的起始地址
    int width       :一帧图像的宽度    
    int hight       :一帧图像的高度
    Encoder *encode :自定义的结构体(包含初始化后的内容)
    char *h264      :编码结果的缓存地址
    int *h264_size  :编码一帧图像数据长度的缓存地址
**************************************/


int Encode_go(char * yuv420,int width,int hight,Encoder *encode,char *h264,int *h264_size)  
{  

    int ret;   
    int j;  
    int iNal   = 0; 
    char *p_out=h264;
    char *p_in=yuv420;

    //清空
    memset(p_out,0,sizeof(char)*width*hight*3);
    memset(h264_size,0,sizeof(int));        

    //把要转得到的yuv420数据中的Y、U、V,填充进去
    memcpy(encode->pPic_in->img.plane[0],p_in,width*hight);                             
    memcpy(encode->pPic_in->img.plane[1],p_in+width*hight,width*hight/4);
    memcpy(encode->pPic_in->img.plane[2],p_in+width*hight*5/4,width*hight/4);

    //编码
    ret = x264_encoder_encode(encode->pHandle, &(encode->pNals), &iNal,encode->pPic_in, encode->pPic_out);
    if (ret< 0){  
        printf("Error encode.\n");  
        return -1;  
        }  
    //printf("Succeed encode frame: %5d\n",encode->pPic_in->i_pts); 

    //取出编码好的数据
    for (j = 0; j < iNal; ++j){  
        memcpy(p_out,encode->pNals[j].p_payload,encode->pNals[j].i_payload);
        p_out+=encode->pNals[j].i_payload;
        (*h264_size)+=encode->pNals[j].i_payload;
        //fwrite(encode->pNals[j].p_payload,1,encode->pNals[j].i_payload,file);          //把数据写到.h264文件里面,可以将得到的文件用VLC播放
    }  
    //printf("Succeed encode h264_size: %d\n",(*h264_size));                            //打印得到的数据长度
    //encode->pPic_in->i_pts ++; 

    /*************flush encoder**********
    while(1){  
        ret = x264_encoder_encode(encode->pHandle, &(encode->pNals), &iNal, NULL,encode->pPic_out);  
        if(ret==0){  
            break;  
        }  
        printf("Flush 1 frame.\n");  
        for (j = 0; j < iNal; ++j){  
            memcpy(p_out,encode->pNals[j].p_payload,encode->pNals[j].i_payload);
            p_out+=encode->pNals[j].i_payload;
            (*h264_size)+=encode->pNals[j].i_payload;  
            }  
        }  
    ***************/
    return 0;  
}

这个函数是调用一次编码一帧图像

4.关闭编码器

关闭编码器,释放空间

int Close_x264(Encoder *encode)
{
    x264_picture_clean(encode->pPic_in);  
    x264_encoder_close(encode->pHandle);  
    encode->pHandle = NULL;  

    free(encode->pPic_in);  
    free(encode->pPic_out);  
    free(encode->pParam);  
    return 0;
}

结尾

开始调用1,然后不断调用2、3,完了调用4关闭就好了

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值