程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> H264解碼學習-2015.04.16,h264-2015.04.16

H264解碼學習-2015.04.16,h264-2015.04.16

編輯:C#入門知識

H264解碼學習-2015.04.16,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、現在所學的很多東西真的是流於表面,即使我把這個視頻解碼做出來已經能播放了,但我還是覺得自己的提升好少。但我還是要繼續這樣做,時間緊迫。不知道我寫的東西對您有沒有幫助,希望各位懂這方面的我們多多交流。對於我的建議給在評論中提出,謝謝您對我的提議。每天記錄一點點,就能進步一點點。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved