C学习系列之H264解码

C学习系列之H264解码C 学习系列之 H264 解码唠叨一 H264 H265 是什么 二 使用问题 1 H264 解码唠叨最近忙着修改代码 但是遇到比较棘手的问题 修改了底层引用的文件 替换了地址 修改了图标 还是躲不过 H264 H265 的解码问题 作为一位图像处理专业的学生 我也是有点爱莫能助 写文章 记录自己的学习心得 也希望大家能分享一些经验 一 H264 H265 是什么 H 264MPEG 4 第十部分 是由 ITU T 视频编码专家组 VCEG

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


唠叨

最近忙着修改代码,但是遇到比较棘手的问题。修改了底层引用的文件,替换了地址,修改了图标。还是躲不过H264、H265的解码问题。作为一位图像处理专业的学生,我也是有点爱莫能助。写文章,记录自己的学习心得,也希望大家能分享一些经验!


一、H264/H265是什么?

  • H.264
  • H265
    H265就是在H264的基础上,进行优化。
    优点
    1、降码率——编码单位;
    2、块的四叉树分化结构——预测与变化;
    3、传输速度、内容更多更快,存储空间少。










二、使用问题

1.H264解码基础理论

  • 内容
  • 相关术语
    协议中定义三种帧:
    I帧:完整图像帧
    B帧:参考前后图像帧编码生成
    P帧:参考I帧生成
    GOP 画面组:变化不大的图像集,其中M指定I帧与P帧之间的距离;N指定两个I帧之间的距离
    IDR关键帧:为I帧,但是I不一定是关键帧。作为已解码、重新开始的机会,分水岭。












  • 压缩方式
    1、分组:GOP
    2、定义帧:划分为三类帧
    3、预测帧:I帧为基础,I帧预测P帧,I帧与P帧预测B帧
    4、数据传输:I帧与预测差值信息进行存储和传输








  • 分层结构
    1、视频编码(VCL)——视频编码层——视频内容
    2、网口抽象(NAL)——网络提取层——按照一定协议传输数据




2.H264实际应用

//初始化 // 这是解码器输出图像信息 hiH264_DEC_FRAME_S _decodeFrame = new hiH264_DEC_FRAME_S(); // 这是解码器属性信息 hiH264_DEC_ATTR_S decAttr = new hiH264_DEC_ATTR_S(); decAttr.uPictureFormat = 0; decAttr.uStreamInType = 0; /* 解码器最大图像宽高, D1图像(1280x720) */ decAttr.uPicWidthInMB = (uint)width / 16; decAttr.uPicHeightInMB = (uint)height / 16; /* 解码器最大参考帧数: 16 */ decAttr.uBufNum = 16; /* bit0 = 1: 标准输出模式; bit0 = 0: 快速输出模式 */ /* bit4 = 1: 启动内部Deinterlace; bit4 = 0: 不启动内部Deinterlace */ decAttr.uWorkMode = 0x10; //创建、初始化解码器句柄 IntPtr _decHandle = H264Dec.Hi264DecCreate(ref decAttr); //解码结束 bool isEnd = false; int bufferLen = 0x1000; IntPtr pData = Marshal.AllocHGlobal(0xFFFF); //码流段 byte[] buf = new byte[0xFFFF]; int dataLenth = 0; while (!isEnd && !isDispose) {       VideoFrameData frameDataTemp; byte tempByte; int j = 0; bool getData = dataFrameQueue2.TryDequeue(out frameDataTemp); if (getData) {       Array.Copy(frameDataTemp.Data, 0, buf, dataLenth, frameDataTemp.Data.Length); dataLenth += frameDataTemp.Data.Length; //GC.Collect(); //GC.SuppressFinalize(this); } //获取一段码流,积累一定缓存量再解 if (dataLenth >= bufferLen || isStop == 1) {       Marshal.Copy(buf, 0, pData, dataLenth); if (firstDecTimeBh) {       firstDecTimeBh = false; Console.WriteLine("解码前时间:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss:fff")); } int result = -1; result = H264Dec.Hi264DecFrame(_decHandle, pData, (UInt32)dataLenth, 0, ref _decodeFrame, (uint)isStop); dataLenth = 0; //IntPtr _decHandle2 = H264Dec.Hi264DecCreate(ref decAttr); //hiH264_DEC_FRAME_S _decodeFrame2 = new hiH264_DEC_FRAME_S(); //IntPtr pData2 = Marshal.AllocHGlobal(frameDataTemp.DataLenth); //Marshal.Copy(frameDataTemp.Data, 0, pData2, frameDataTemp.DataLenth); //int result2 = 0; //result2 = H264Dec.Hi264DecFrame(_decHandle2, pData2, (UInt32)frameDataTemp.DataLenth, 0, ref _decodeFrame2, (uint)isStop); //if (result2 >= 0) // Console.WriteLine("发现帧"); while (HI_H264DEC_NEED_MORE_BITS != result) {       if (firstDecTimeBf) {       firstDecTimeBf = false; Console.WriteLine("解码后时间:" + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss:fff")); } if (HI_H264DEC_NO_PICTURE == result) {       isEnd = true; break; } if (HI_H264DEC_OK == result)/* 输出一帧图像 */ {       //获取yuv UInt32 tempWid = _decodeFrame.uWidth; UInt32 tempHeig = _decodeFrame.uHeight; UInt32 yStride = _decodeFrame.uYStride; UInt32 uvStride = _decodeFrame.uUVStride; byte[] y = new byte[tempHeig * yStride]; byte[] u = new byte[tempHeig * uvStride / 2]; byte[] v = new byte[tempHeig * uvStride / 2]; Marshal.Copy(_decodeFrame.pY, y, 0, y.Length); Marshal.Copy(_decodeFrame.pU, u, 0, u.Length); Marshal.Copy(_decodeFrame.pV, v, 0, v.Length); _decodeFrame.uDpbIdx = (uint)frameDataTemp.FrameId; MyProcessEvent2(_decodeFrame); //转为yv12格式 //byte[] yuvBytes = new byte[y.Length + u.Length + v.Length]; //Array.Copy(y, 0, yuvBytes, 0, y.Length); //Array.Copy(v, 0, yuvBytes, y.Length , v.Length); //Array.Copy(u, 0, yuvBytes, y.Length + v.Length, u .Length); //更新显示 //this.d3dSource.Render(_decodeFrame.pY, _decodeFrame.pU, _decodeFrame.pV); } /* 继续解码剩余H.264码流 */ result = H264Dec.Hi264DecFrame(_decHandle, IntPtr.Zero, 0, 0, ref _decodeFrame, (uint)isStop); } System.Threading.Thread.Sleep(1); } } /* 销毁解码器 */ H264Dec.Hi264DecDestroy(_decHandle); 
 [DllImport("hi_h264dec_w.dll", EntryPoint = "Hi264DecFrame", CallingConvention = CallingConvention.Cdecl)] public static extern int Hi264DecFrame(IntPtr hDec, IntPtr pStream, uint iStreamLen, ulong ullPTS, ref hiH264_DEC_FRAME_S pDecFrame, uint uFlags); 

使用DllImport来调用hi_h264dec_w.dll解码库中的需要使用到的函数,将码流做图像输出。使用到extern也是可以理解的。

总结

H264解码首先了解解码原理,其次利用已有的解码库对H264结构进行了解,然后利用代码将其实现。

引用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/227946.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午8:09
下一篇 2026年3月16日 下午8:09


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号