zoukankan      html  css  js  c++  java
  • H264解码学习-2015.04.16

      今天看了不少,却感觉收获寥寥。

      1、H264相关知识

      因为RTP协议发过来的数据已经经过了H264编码,所以这边需要解码。补充一下H264的相关知识。

      与以往的视频压缩标准相比,H.264 视频压缩标准(简称H.264)具有更出色的性能,因此H.264 被称为新一代视频压缩标准。H.264 与H.263 或MPEG-4 相比,            主要新增特性如下:
          1、采用更为精细和丰富的帧内编码及帧间预测方式,有效地减少残差数据。
          2、引入新的算术编码方式,使得数据压缩比更高。
          3、 视频数据分层更为合理,引入 NAL 更利于网络传输。
      4、取消传统的帧结构,引入 slice 结构和参数集,提高码流的抗误码能力。
      5、引入灵活的参考帧管理机制,参考帧数目最多可以达到 16 个。

      上述特性使得H.264 在视频信噪比、图像质量以及应用的灵活性上有了质的飞跃,但带来的问题是H.264 在实现上复杂度较高。

      2、一些可能的解决方案(并未实践)

      Intel media SDK,windows media sdk,http://www.ffmpeg-csharp.com/(这个网站上说是最简单的方式使用ffmpeg,我也没有学会怎么使用,等以后再回来学习吧),C#调用ffmpeg开发库。以上这些方式只是搜索到的可能的解决方法,因为太懒了,着急做出东西,所以没有去学习,后来在海康的播放库API中看到H264的相关知识(http://www.cnblogs.com/over140/archive/2009/03/22/1418946.html),以前做海康摄像头调用的时候就经常看他的博客。最后在晚上的时候找到一种解决方式。使用海思提供的H264解码库,有专门的解码库,但也是用C++写的。不过这没有问题,想起以前海康摄像头的时候也是C++的代码,通过C#来调用。方法是通过PInvoke.net转一下就可以了。

      转换之后的代码,将hi_h264dec_w.dll转换为C#中的类(也是参考网上的代码)

    class Hi264Dec
        {
             public const int HI_SUCCESS = 0;
    
             public const int HI_FAILURE = -1;
    
             public const int HI_LITTLE_ENDIAN = 1234;
    
             public const int HI_BIG_ENDIAN = 4321;
    
             public const int HI_DECODER_SLEEP_TIME = 60000;
    
             public const int HI_H264DEC_OK = 0;
    
             public const int HI_H264DEC_NEED_MORE_BITS = -1;
    
             public const int HI_H264DEC_NO_PICTURE = -2;
    
             public const int HI_H264DEC_ERR_HANDLE = -3;
    
     
    
             [DllImport("hi_h264dec_w.dll",EntryPoint = "Hi264DecImageEnhance", CallingConvention = CallingConvention.Cdecl)]
    
             public static extern int Hi264DecImageEnhance(IntPtr hDec, ref hiH264_DEC_FRAME_S pDecFrame, uint uEnhanceCoeff);
    
     
    
             [DllImport("hi_h264dec_w.dll",EntryPoint = "Hi264DecCreate", CallingConvention = CallingConvention.Cdecl)]
    
             public static extern IntPtr Hi264DecCreate(ref hiH264_DEC_ATTR_S pDecAttr);
    
     
    
             [DllImport("hi_h264dec_w.dll", EntryPoint = "Hi264DecDestroy", CallingConvention = CallingConvention.Cdecl)]
    
             public static extern void Hi264DecDestroy(IntPtr hDec);
    
     
    
             [DllImport("hi_h264dec_w.dll", EntryPoint = "Hi264DecGetInfo", CallingConvention = CallingConvention.Cdecl)]
    
             public static extern int Hi264DecGetInfo(ref hiH264_LIBINFO_S pLibInfo);
    
     
    
             [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", EntryPoint = "Hi264DecAU", CallingConvention = CallingConvention.Cdecl)]
    
             public static extern int Hi264DecAU(IntPtr hDec, IntPtr pStream, uint iStreamLen, ulong ullPTS, ref hiH264_DEC_FRAME_S pDecFrame, uint uFlags);
    
     
    
             [StructLayout(LayoutKind.Sequential)]
    
             public struct hiH264_DEC_ATTR_S
    
             {
    
                 public uint uPictureFormat;
    
                 public uint uStreamInType;
    
                 public uint uPicWidthInMB;
    
                 public uint uPicHeightInMB;
    
                 public uint uBufNum;
    
                 public uint uWorkMode;
    
                 public IntPtr pUserData;
    
                 public uint uReserved;
    
             }
    
     
    
             [StructLayout(LayoutKind.Sequential)]
    
             public struct hiH264_DEC_FRAME_S
    
             {
    
                 public IntPtr pY;
    
                 public IntPtr pU;
    
                 public IntPtr pV;
    
                 public uint uWidth;
    
                 public uint uHeight;
    
                 public uint uYStride;
    
                 public uint uUVStride;
    
                 public uint uCroppingLeftOffset;
    
                 public uint uCroppingRightOffset;
    
                 public uint uCroppingTopOffset;
    
                 public uint uCroppingBottomOffset;
    
                 public uint uDpbIdx;
    
                 public uint uPicFlag;
    
                 public uint bError;
    
                 public uint bIntra;
    
                 public ulong ullPTS;
    
                 public uint uPictureID;
    
                 public uint uReserved;
    
                 public IntPtr pUserData;
    
             }
    
     
    
             [StructLayout(LayoutKind.Sequential)]
    
             public struct hiH264_LIBINFO_S
    
             {
    
                 public uint uMajor;
    
                 public uint uMinor;
    
                 public uint uRelease;
    
                 public uint uBuild;
    
                 [MarshalAs(UnmanagedType.LPStr)] public string sVersion;
    
                 [MarshalAs(UnmanagedType.LPStr)] public string sCopyRight;
    
                 public uint uFunctionSet;
    
                 public uint uPictureFormat;
    
                 public uint uStreamInType;
    
                 public uint uPicWidth;
    
                 public uint uPicHeight;
    
                 public uint uBufNum;
    
                 public uint uReserved;
    
             }
    
     
    
             [StructLayout(LayoutKind.Sequential)]
    
             public struct hiH264_USERDATA_S
    
             {
    
                 public uint uUserDataType;
    
                 public uint uUserDataSize;
    
                 public IntPtr pData;
    
                 public IntPtr pNext;
    
             }
        }
    

         可以在窗体加载的时候加载如下代码

    //初始化,可以在 FormLoad 事务里完成
    
                 var decAttr = new Hi264Dec.hiH264_DEC_ATTR_S();
    
                 decAttr.uPictureFormat = 0;
    
                 decAttr.uStreamInType = 0;
    
                 decAttr.uPicWidthInMB = 480 >> 4;
    
                 decAttr.uPicHeightInMB = 640 >> 4;
    
                 decAttr.uBufNum = 8;
    
                 decAttr.uWorkMode = 16;
    
                 IntPtr _decHandle = Hi264Dec.Hi264DecCreate(ref decAttr);
    
     
    
                 Hi264Dec.hiH264_DEC_FRAME_S _decodeFrame = new Hi264Dec.hiH264_DEC_FRAME_S();
    
                 //解码
    
                 //pData 为须要解码的 H264 nalu 数据,length 为该数据的长度
    
                 if (Hi264Dec.Hi264DecAU(_decHandle, pData, (uint) length, 0, ref _decodeFrame, 0) == 0)
    
                 {
    
                     if (_decodeFrame.bError == 0)
    
                     {
    
                         //策画 y u v 的长度
    
                         var yLength = _decodeFrame.uHeight * _decodeFrame.uYStride;
    
                         var uLength = _decodeFrame.uHeight * _decodeFrame.uUVStride / 2;
    
                         var vLength = uLength;
    
                         var yBytes = new byte[yLength];
    
                         var uBytes = new byte[uLength];
    
                         var vBytes = new byte[vLength];
    
                         var decodedBytes = new byte[yLength + uLength + vLength];
    
                         //_decodeFrame 是解码后的数据对象,里面包含 YUV 数据、宽度、高度等信息
    
                         Marshal.Copy(_decodeFrame.pY, yBytes, 0, (int)yLength);
    
                         Marshal.Copy(_decodeFrame.pU, uBytes, 0, (int)uLength);
    
                         Marshal.Copy(_decodeFrame.pV, vBytes, 0, (int)vLength);
    
                         //将从 _decodeFrame 中取出的 YUV 数据放入 decodedBytes 中
    
                         Array.Copy(yBytes, decodedBytes, yLength);
    
                         Array.Copy(uBytes, 0, decodedBytes, yLength, uLength);
    
                         Array.Copy(vBytes, 0, decodedBytes, yLength + uLength, vLength);
                         //decodedBytes 为yuv数据,可以将其转换为 RGB 数据后再转换为 BitMap 然后经由过程 PictureBox 控件即可显示
                         //这类代码网上斗劲常见,我就不贴了
         }
    

         在关闭的时候销毁解码器句柄

      

    Hi264Dec.Hi264DecDestroy(_decHandle);
    

         在上面也说了,传进来的数据转为YUV数据后,还需要转为RGB,再转为图片在控件中进行显示。粗略从网上看了一下,这类算法还是比较多的,所以明天的目标是将视频显示出来。争取让已有的轮子跑起来。

        3、C++学习

        今天上午还看了一小部分C++,看的比较慢,学习了基本的输入输出语句,只看到第28页。

        4、总结

        今天收毕业论文题目了,我还没怎么开始写呢。等把RTP和H264视频解码这一块解决就开始准备毕业论文了。晚上的时候给周兆熊老师发的邮件已经收到回复。对于我自己目前的问题也总结一下:(1)语言的确没什么再纠结的意思了,对我现在来说没有孰优孰劣,我需要的做的是尽量用熟悉的语言去解决现在存在的问题。(2)未来想找工作的话不单单需要专业方面的知识,也需要软实力,想起前几天犯得小错误,对自己的成长还是有帮助。需要继续看书,读过的书也需要做笔记。(3)关于怎么让自己坚持去学习,前几天的烦躁心里真的因为好好做事情减轻了呢。这几天一直尝试着用番茄工作法让自己安定下来,坚持使用第四天,每天大约5个番茄钟(效率好低啊)。看了高效工作后,里面的对拖延症的分析三个原因真的让我印象深刻:(1)其他人强迫你做的事情违背你的意愿(好像的确如此哈哈);(2)你给自己压力要有完美的表现;(3)害怕犯错误受批评。三个原因真的是非常准确。不愉快也因为忙碌起来而渐渐消失了。

        5、现在所学的很多东西真的是流于表面,即使我把这个视频解码做出来已经能播放了,但我还是觉得自己的提升好少。但我还是要继续这样做,时间紧迫。不知道我写的东西对您有没有帮助,希望各位懂这方面的我们多多交流。对于我的建议给在评论中提出,谢谢您对我的提议。每天记录一点点,就能进步一点点。

  • 相关阅读:
    es6 语法 (数值扩展)
    手机日期插件 (转加上自己喜欢的)
    仿微信抢红包(js 转)
    默认时间为今天
    es6 语法 (解构赋值)
    es6 语法 (let 和const)
    es6环境搭建
    express 安装和运行
    git 常用操作,下拉,提交,更新,还原
    排序。
  • 原文地址:https://www.cnblogs.com/kui0621/p/4433484.html
Copyright © 2011-2022 走看看