h.264的编码过程
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
H.264编码算法的实现
在H.264编码具体实现过程中,采用了目前国际上应用最广泛的开源编码器X.264作为实现的基础。X.264和JM系列编码器、T.264编码器相比有着优秀的性能和出色效果。由于X.264没有提供直接的开发API,所以在本系统中的编码部分重新封装了X.264的编码API,便于软件系统的设计和使用。以下是本系统中H.264编码的具体实现过程:
1) RGB和YUV颜色空间的转换
在系统中通过Logitech摄像头获得的视频数据为RGB24格式,但是X.264的输入流为标准的YUV(4:2:0)的图像子采样格式。因此,在编码前需要将RGB颜色空间转换为YUV的颜色空间。实现的函数调用有InitLookupTable()用于初始化色彩空间转换;
RGB2YUV420(int x_dim, int y_dim, unsigned char *bmp, unsigned char *yuv, int flip);用于实际的转换。由于人眼的生理特性,经过图像子采样后,实际的图像大小已经减小为采样前的1.5个样本点,即减小了一半的数据量。
2) 设置H.264编码参数
使用x264_param_default(x264_param_t *param)对当前需要编码的图像参数进行设置。包括数据帧数量(param .i_frame_total)、采样图像的长宽度和高度(param .i_width,param .i_height)、视频数据比特率(param .rc.i_bitrate) 、视频数据帧率(param .i_fps_num)等参数进行设置,以完成编码前预设置。
3) 初始化编码器
将上步中的设置作为编码器初始化的参数,
x264_t*x264_encoder_open ( x264_param_t *param )。如果初始化失败将返回NULL,在这里需要对编码器初始化结果进行处理。
4) 分配编码空间
如果编码器初始化成功,则需要为本次处理分配内存空间
Void x264_picture_alloc(x264_picture_t *pic, int i_csp, int i_width, int i_height)。
5) 图像编码
将以上步骤初始化后的数据作为编码输入,使用下面的方法进行编码:
int x264_encoder_encode( x264_t *h,x264_nal_t **pp_nal, int
*pi_nal,x264_picture_t *pic_in,x264_picture_t *pic_out );
6) 资源回收
编码完成后,需要回收系统资源和关闭编码器,使用以下函数调用实现回收。
void x264_picture_clean( x264_picture_t *pic );
void x264_encoder_close( x264_t *h );
至此,完成了H.264编码,编码后的数据量将大大减小。我们可以对编码后的数据做相关的进一步处理。
4 H.264编码算法的完整源代码
文件:VideoEncoderX264.h
class CVideoEncoderX264 :
{
public:
CVideoEncoderX264(void);
~CVideoEncoderX264(void);
virtual bool Connect(CVideoEnDecodeNotify* pNotify, const CVideoEnDecodeItem& Item);
virtual void Release(void);
virtual void Encode(BYTE* pInData, int nLen, BYTE* pOutBuf, int& nOutLen, int& nKeyFrame);
private:
x264_picture_t m_Pic;
x264_t *h;
x264_param_t param;
void Flush(void);
};
文件:VideoEncoderX264.cpp
bool CVideoEncoderX264::Connect(CVideoEnDecodeNotify* pNotify, const CVideoEnDecodeItem& Item)
{
CBase::Connect(pNotify, Item);
ParseSize(Item.m_stSize);
x264_param_default( ¶m );
param.i_threads = 1;
param.i_frame_total = 0;
param.i_width = m_nWidth;
param.i_height = m_nHeight;
param.i_keyint_min = Item.m_nKeyInterval;
param.i_keyint_max = Item.m_nKeyInterval * 10;
param.i_fps_num = Item.m_nFps;*/
param.i_log_level = X264_LOG_NONE;
if( ( h = x264_encoder_open( ¶m ) ) == NULL )
{
return false;
}
x264_picture_alloc( &m_Pic, X264_CSP_I420, param.i_width, param.i_height );
return true;
}
void CVideoEncoderX264::Release(void)
{
Flush();
x264_picture_clean( &m_Pic );
x264_encoder_close( h );
CBase::Release();
}
void CVideoEncoderX264::Encode(BYTE* pInData, int nLen, BYTE* pOutBuf, int& nOutLen, int& nKeyFrame)
{
if(nLen != param.i_width * param.i_height * 3)
return;
param.i_frame_total ++;
memcpy(m_Pic.img.plane[0], pInData, param.i_width * param.i_height); memcpy(m_Pic.img.plane[1], pInData + param.i_width * param.i_height, param.i_width * param.i_height / 4);