/////////////////// int init_decoder() { int ret; xvid_gbl_init_t xvid_gbl_init; xvid_dec_create_t xvid_dec_create; /* Reset the structure with zeros */ memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t)); memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t)); /*------------------------------------------------------------------------ * XviD core initialization *----------------------------------------------------------------------*/ XDIM = 0 ; YDIM = 0 ; FORMAT = 0 ; CSP = XVID_CSP_BGR; BPP = 3; dec_handle = NULL ; mp4_buffer = NULL ; out_buffer = NULL ; mp4_ptr = NULL ; /* Version */ xvid_gbl_init.version = XVID_VERSION; /* Assembly setting */ xvid_gbl_init.cpu_flags = 0; // use assembly optimized xvid_gbl_init.debug = 0 ; // set debug level 0, no debug output xvid_global(NULL, 0, &xvid_gbl_init, NULL);//XVID 初始化 /*------------------------------------------------------------------------ * XviD encoder initialization *----------------------------------------------------------------------*/ /* Version */ xvid_dec_create.version = XVID_VERSION; /* * Image dimensions -- set to 0, xvidcore will resize when ever it is * needed */ xvid_dec_create.width = 0;//解码后图像的宽度 如果事先已经知道 那么这里就填写 否则设置0 xvid_dec_create.height = 0;//解码后图像的高度 如果事先已经知道 那么这里就填写 否则设置0 ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL);//创建xvid 解码实例 dec_handle = xvid_dec_create.handle;////将创建的句柄 赋值 给 dec_handle return(ret); } ////////////////////////////////////////////////////////////////// int decode_one_frame(unsigned char *istream, unsigned char *ostream, int istream_size, xvid_dec_stats_t *xvid_dec_stats) { int ret; xvid_dec_frame_t xvid_dec_frame; /* Reset all structures */ memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t)); memset(xvid_dec_stats, 0, sizeof(xvid_dec_stats_t)); /* Set version */ xvid_dec_frame.version = XVID_VERSION; xvid_dec_stats->version = XVID_VERSION; /* No general flags to set */ xvid_dec_frame.general = 0; /* Input stream */ xvid_dec_frame.bitstream = istream;//待解码的数据 xvid_dec_frame.length = istream_size;//待解码数据的长度 /* Output frame structure */ xvid_dec_frame.output.plane[0] = ostream;//解码完成后 存放原始视频流的缓冲区 xvid_dec_frame.output.stride[0] = XDIM*BPP;//步长 即一行像素所占的空间大小 xvid_dec_frame.output.csp = CSP;//输出时 采用的色场空间 这里 XVID_CSP_BGR 即采用RGB ret = xvid_decore(dec_handle, XVID_DEC_DECODE, &xvid_dec_frame, xvid_dec_stats);//ret 值 解码前 帧的长度 return(ret); } ///调用方式 do { /* Decode frame */ used_bytes = decode_one_frame(mp4_ptr, out_buffer, useful_bytes, &xvid_dec_stats); /* Resize image buffer if needed */ if(xvid_dec_stats.type == XVID_TYPE_VOL)//如果输入一帧包含 VOL 重新获得 输出图像的宽度和高度 { /* Check if old buffer is smaller */ if(XDIM*YDIM < xvid_dec_stats.data.vol.width*xvid_dec_stats.data.vol.height) { /* Copy new witdh and new height from the vol structure */ XDIM = xvid_dec_stats.data.vol.width; YDIM = xvid_dec_stats.data.vol.height; /* Free old output buffer*/ if(out_buffer) free(out_buffer); /* Allocate the new buffer */ out_buffer = (unsigned char*)malloc(XDIM*YDIM*4);//动态调整 输出流 存储空间的大小 if(out_buffer == NULL) goto free_all_memory; } } /* Update buffer pointers */ if(used_bytes > 0) { mp4_ptr += used_bytes; useful_bytes -= used_bytes; } } while (xvid_dec_stats.type <= 0 && useful_bytes > MIN_USEFUL_BYTES); /* 显示图像信息*/ draw_image(out_buffer) ;
2 Xvid编解码 实践
关于编码器输入格式设置:
其中 en->width 图像采集时的宽度(以像素为单位)
switch( input->format )
{
case FORMAT_RAW_BGR24:
xvid_enc_frame.input.csp = XVID_CSP_BGR;
xvid_enc_frame.input.stride[0] = en->width * 3;
break;
case FORMAT_RAW_UYVY:
xvid_enc_frame.input.csp = XVID_CSP_UYVY;
xvid_enc_frame.input.stride[0] = en->width * 2;
break;
case FORMAT_RAW_YUY2:
xvid_enc_frame.input.csp = XVID_CSP_YUY2;
xvid_enc_frame.input.stride[0] = en->width * 2;
break;
}
解码器输出格式设置:
switch( output->format )
{
case FORMAT_RAW_BGR24:
xvid_dec_frame.output.stride[0] = m_width*3;
xvid_dec_frame.output.csp =XVID_CSP_BGR;
break;
case FORMAT_RAW_YUY2:
xvid_dec_frame.output.csp = XVID_CSP_YUY2;
xvid_dec_frame.output.stride[0]= en->width * 2;
break;
}
特别注意的是:
在xvid 中stride 步长与 视频格式有密切格式 一旦设置错误导致 编解码异常终止。
xvid使用小技巧:
(1)解决:使用xvid编解码rtp传输directshow 播放远程视频时开始会出现绿屏但可以看到图像轮廓,在经过几秒后正常
很可能的一个原因是 关键帧丢失 方法:
减小关键帧的间隔
/* Maximum key frame interval */ //最大I帧(关键帧)间隔,一般设置成帧数的10倍
xvid_enc_create.max_key_interval = 1;//(int)-1; //--default 10s
(2)(获得编码后 帧长度)
ret = xvid_encore(m_enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,&xvid_enc_stats);
m_enc_frame_length=xvid_enc_stats.length;//编码获得的帧长度