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关闭就好了