H.264视频编码在VC++.Net中的实现

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的输入流为标准的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编码,编码后的数据量将大大减小。我们可以对编码后的数据做相关的进一步处理。

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_type==X264_TYPE_IDR;// || (pic_out.i_type==X264_TYPE_I && coCfg->x264_max_ref_frames==1);
}


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 ){

    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/404164.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React开发(265):ant design InputNumber

## 所有输入价格的地方&#xff0c;都使用InputNumber 组件javascript // formatter 和 parser <InputNumberstyle{{ width: 100% }}value{baseInfo.minRepeatedlyAmount}onChange{(value) > this.handleChangeFormData(value, minRepeatedlyAmount)}formatter{(value) &…

总结一下php5.2.16与apache2.0的C++扩展开发整个过程

开发环境&#xff1a;ubuntu 11&#xff08;虚拟机环境&#xff09; 开发平台&#xff1a; php-5.2.16.tarapache2.0 PHP API 20041225 PHP Extension 20060613 Zend Extension 220060519 说明一下为什么要用这么旧的版本&#xff0c;没原因&#xff0c;因为公司官方服务器是…

TCP/IP ---封装与分用

封装 当应用程序用T C P传送数据时&#xff0c;数据被送入协议栈中&#xff0c;然后逐个通过每一层直到被当作一串比特流送入网络。其中每一层对收到的数据都要增加一些首部信息&#xff08;有时还要增加尾部信息&#xff09;&#xff0c;该过程如图1 - 7所示。T C P传给I P的数…

深入了解crc32算法

From: http://blog.csdn.net/isadream/article/details/2072760 由于项目需要&#xff0c;解决一个流媒体文件的crc32校验码。网上查了很多的资料&#xff0c;发现了此校验码和生成多项式以及算法本身都有关系。对于不同类型的文件所使用的多项式以及算法不同&#xff0c;对于不…

React开发(271):UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated e

原因&#xff1a;没有进行promise的差错处理 解决方案&#xff1a;加一个catch语句 .catch(err > {console.log(err);})

远程计算机需要网络级别身份验证,而您的计算机不支持该验证,请联系您的系统管理员或者技术人员来获得帮助...

故障&#xff1a;“远程计算机需要网络级别身份验证&#xff0c;而您的计算机不支持该验证&#xff0c;请联系您的系统管理员或者技术人员来获得帮助” 故障症状&#xff1a;当您使用Windows XP“远程桌面连接”工具去连接Windows Vistas或Windows Server 2008的远程桌面、终端…

CRC32算法详细推导(1)

From: http://blog.csdn.net/sparkliang/article/details/5671510 CRC算法详解&#xff08;1&#xff09; 作为blog再次发出来&#xff0c;详细描述一下CRC32算法的推导过程。 CRC 算法的数学基础 CRC 算法的数学基础就不再多啰嗦了&#xff0c;到处都是&#xff0c;简单提一…

前端javascript面试题目录汇总

【JS】 [js] 请使用js实现一个秒表计时器的程序 [js] 模拟 localStorage 时如何实现过期时间功能 [js] 请使用js实现商品的自由组合&#xff0c;并说说你的思路 [js] js中的undefined和 ReferenceError: xxx is not defined 有什么区别&#xff1f; [js]JavaScript Number…

React开发(272):try...catch..捕获

//通过接口获取listhandleSearchList async (url) > {try {const res await url();if (res.data && res.data.length > 0) {this.setState({thirdList: res.data,showThird: true,tabName: ,});}} catch (error) {}};

CRC32算法详细推导(2)

From: http://blog.csdn.net/sparkliang/article/details/5671977 CRC算法详解&#xff08;2&#xff09; 初见 Table-Driven 变换到上面的方法后&#xff0c;我们离 table-driven 的方法只有一步之遥了&#xff0c;我们知道一个字节能表示的正整数范围是 0~255&#xff0c;步…

iOS UIWebView加载网页、文件、HTML

UIWebView是用来加载加载网页数据的一个框架.UIWebView可以用来加载pdf,word,doc,等等文件,生成webview 有两种方法&#xff0c;1、通过storyboard 拖拽 2、通过alloc init 来初始化创建webview&#xff0c;下列文本中 _webView.dataDetectorTypes UIDataDetectorTypeAll; 是识…

nginx的upstream模块安装

下载连接&#xff1a;wget http://code.google.com/p/nginx-upstream-jvm-route/downloads/detail?namenginx-upstream-jvm-route-0.2.tar.gz&can1&q/nginx-upstream-jvm-route-0.2.tar.gz nginx_upstream_jvm_route 是一个 Nginx 的扩展模块&#xff0c;用来实现基于…

前端面试题Vue-cli目录汇总

【Vue-cli】 [vue-cli]vue-cli3你有使用过吗&#xff1f;它和2.x版本有什么区别&#xff1f; [vue-cli]vue-cli默认是单页面的&#xff0c;那要弄成多页面该怎么办呢 [vue-cli]不用vue-cli&#xff0c;你自己有搭建过vue的开发环境吗&#xff1f;流程是什么&#xff1f; [v…

CRC32算法详细推导(3)

From:http://blog.csdn.net/sparkliang/article/details/5671543 CRC32算法详细推导&#xff08;3&#xff09; 郁闷的位逆转 看起来我们已经得到 CRC-32 算法的最终形式了&#xff0c;可是、可是在实际的应用中&#xff0c;数据传输时是低位先行的&#xff1b;对于一个字节 …

WebService的学习

这篇文章不错&#xff0c;直接转了 http://blog.csdn.net/terryzero/article/details/5976638#comments 转载于:https://www.cnblogs.com/zhilu-doc/p/5291927.html

linux 用户行为审计

根据公司需求&#xff0c;整理了一个linux用户审计的脚本&#xff0c;现和大家分享&#xff01; 具体步骤如下&#xff1a; 一&#xff1a;配置调试 1.创建用户审计文件存放目录和审计日志文件 &#xff1b; mkdir -p /var/log/usermonitor/ 2.创建用户审计日志文件&#xff1…

前端面试题vue-element汇总

【Vue-element】 [vue-element] ElementUI是怎么做表单验证的&#xff1f;在循环里对每个input验证怎么做呢&#xff1f; [vue-element] 你有二次封装过ElementUI组件吗&#xff1f; [vue-element] ElementUI怎么修改组件的默认样式&#xff1f; [vue-element]ElementUI的穿…

每天一点Swift(五)控制器的生命周期和SizeClass

字数358 阅读19 评论0 喜欢0 初始化init-->awakeFromNib--> prepare a segue --> SB去设置outlets --> viewDidLoad 1. viewDidLoad 在viewDidLoad中&#xff0c;outlets已经被设置&#xff1b;但是几何位置&#xff08;bounds&#xff09;并没有被设置 viewDidLoa…

h264 I帧的判断

From:http://blog.csdn.net/dxpqxb/article/details/13289205 H264数据的NALU 头的格式如图2 所示&#xff1a; F&#xff1a;forbidden_zero_bit.1 位&#xff0c;如果有语法冲突&#xff0c;则为 1。当网络识别此单元存在比特错误时&#xff0c;可将其设为 1&#xff0c;以便…

前端面试题node.js汇总

【NodeJs】 [NodeJs] 你有使用过npx吗&#xff1f;它主要解决什么问题&#xff1f; [NodeJs] 如何使用nodejs对base64进行编解码&#xff1f; [NodeJs] npm提供了哪些钩子&#xff1f;各有什么作用&#xff1f; [NodeJs] 如果发现node_modules中有个模块代码有bug&#xff…