山东工艺美术学院网站建设公司,wordpress调用栏目,网站开发产品规划要求,美的公司网站建设的目的From: http://blog.csdn.net/xwchen/article/details/5052981 引言#xff1a;H.264编码技术是俱乐部在过去一段时间内研究的一个方向,对该编码技术进行过实际的开发和应用#xff0c;并取得了很大的收获。下面将重点介绍H.264视频编码在VC.Net中的实现。 1. H.264编码的介…From: http://blog.csdn.net/xwchen/article/details/5052981 引言H.264编码技术是俱乐部在过去一段时间内研究的一个方向,对该编码技术进行过实际的开发和应用并取得了很大的收获。下面将重点介绍H.264视频编码在VC.Net中的实现。 1. H.264编码的介绍 H.264是一种视频高压缩技术全称是MPEG-4 AVC用中文说是“活动图像专家组-4的高等视频编码”或称为MPEG-4 Part10。它是由国际电信标准化部门ITU-T和规定MPEG的国际标准化组织ISO/国际电工协会IEC共同制订的一种活动图像编码方式的国际标准格式。由于H.264在制定时就充分考虑了多媒体通信对视频编解码的各种要求并借鉴了H系列和MPEG系列视频标准的研究成果因而具有明显的优势。H.264作为最新的国际建议标准在IP视频监控系统中有着重要的意义。它与目前的Mpeg4和H.263编码相比较优势表现在以下几个方面 1) 压缩率和图像质量方面 H.264通过对传统的帧内预测、帧间预测、变换编码和熵编码等算法的改进来进一步提高编码效率和图像质量。在相同的重建图像质量下H.264比H.263节约50左右的码率比Mpeg4节约35左右。 2) 网络适应性方面 H.264支持不同网络资源下的分级编码传输从而获得平稳的图像质量。H.264能适应于不同网络中的视频传输网络亲和性好。H.264的基本系统无需使用版权具有开放的性质能很好地适应IP和无线网络的使用这对目前的因特网传输多媒体信息、移动网中传输宽带信息等都具有重要的意义。 3) 抗丢包和抗误码方面 H.264具有较强的抗误码特性可适应丢包率高、干扰严重的信道中的视频传输。 实际应用中实时性和较好的图像质量较低的网络带宽占用以及带宽适应能力是监控系统的主要考虑因素。H.264 相比较以前的视频编码标准主要在网络接口友好性和高的压缩性能上有了很大的提高。综合以上因素在本系统中采用H.264作为视频数据的编码方式。 2. H.264编码的实现原理 1) 量化 H. 264为了提高码率控制的能力, 量化步长的变化的幅度控制在12.5 %左右, 而不是以不变的增幅变化。变换系数幅度的归一化被放在反量化过程中处理以减少计算的复杂性。为了强调彩色的逼真性,对色度系数采用了较小量化步长。 2) 运动补偿 宏块划分方式: H. 264 支持形状不等的宏块划分 其划分方法有: 16×16 16×8 8×16 8×8 8×4 4×8 4×4. 这种更小的、更多形状的的宏块划分更切合图形中实际运动物体的形状 改善运动补偿的精度 更好的实现运动隔离 提高图像质量和编码效率. 搜索精度: H. 264 支持1/4 和1/8 精度的运动补偿 使用一个6 抽头滤波器从整像素样本的到1/2 像素样本 用线性插值获得1/4 像素样本 用8 抽头滤波器实现1/8 像素精度。 多参考帧模式: H. 264 在对周期性的运动或背景切换进行预测时 多参考帧可以提供更好的预测效果。 3) 帧内预测 4) 变换编码 5) 熵编码 3 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的输入流为标准的YUV420的图像子采样格式。因此在编码前需要将RGB颜色空间转换为YUV的颜色空间。实现的函数调用有InitLookupTable用于初始化色彩空间转换 RGB2YUV420int x_dim, int y_dim, unsigned char *bmp, unsigned char *yuv, int flip用于实际的转换。由于人眼的生理特性经过图像子采样后实际的图像大小已经减小为采样前的1.5个样本点即减小了一半的数据量。 2) 设置H.264编码参数 使用x264_param_defaultx264_param_t *param对当前需要编码的图像参数进行设置。包括数据帧数量param .i_frame_total、采样图像的长宽度和高度param .i_widthparam .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_allocx264_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( param ); 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( param ) ) NULL ) { return false; } /* Create a new pic */ 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); memcpy(m_Pic.img.plane[2], pInData param.i_width * param.i_height * 5 / 4, param.i_width * param.i_height / 4); m_Pic.i_pts (int64_t)param.i_frame_total * param.i_fps_den; static x264_picture_t pic_out; x264_nal_t *nal NULL; int i_nal, i; if( m_Pic ) { m_Pic.i_type X264_TYPE_AUTO; m_Pic.i_qpplus1 0; } //TraceTime(x264_encoder_encode begin); if( x264_encoder_encode( h, nal, i_nal, m_Pic, pic_out ) 0 ) { return; } //TraceTime(x264_encoder_encode end); int nOutCanUse nOutLen; nOutLen 0; for( i 0; i i_nal; i ) { int i_size 0; if( ( i_size x264_nal_encode( pOutBuf nOutLen, nOutCanUse, 1, nal[i] ) ) 0 ) { nOutLen i_size; nOutCanUse - i_size; } } nKeyFrame pic_out.i_typeX264_TYPE_IDR;// || (pic_out.i_typeX264_TYPE_I coCfg-x264_max_ref_frames1); } void CVideoEncoderX264::Flush(void) { x264_picture_t pic_out; x264_nal_t *nal; int i_nal, i; int i_file 0; if( x264_encoder_encode( h, nal, i_nal, NULL, pic_out ) 0 ){ } }