C# 播放H264裸码流
Posted 跟班的小鸟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 播放H264裸码流相关的知识,希望对你有一定的参考价值。
要播放H264裸码流,可以分拆为以下三个工作:
1.解码H264裸码流获取YUV数据
2.将YUV数据转换为RGB数据填充图片
3.将获取的图片进行显示
要完成工作1,我们可以直接使用海思的解码库,由于海思的解码库是C++的动态库,要完成在C#中进行调用可以参考海思h264解码库这篇文章,介绍的很详细。但是对于该博文只介绍了一种帧解码的方法,并没有介绍真正实用的流式解码方法。自己根据解码库的参考文档写了一份C#版的流式解码算法。
//初始化 // 这是解码器输出图像信息 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 = 0x8000; //码流段 byte[] buf = new byte[bufferLen]; while (!isEnd) { //获取一段码流,积累一定缓存量再解 if (streamBuf.Count >= bufferLen || isStop == 1) { byte tempByte; int j = 0; for (int i = 0; i < bufferLen; i++) { if (streamBuf.TryDequeue(out tempByte)) buf[j++] = tempByte; else { break; } } IntPtr pData = Marshal.AllocHGlobal(j); Marshal.Copy(buf, 0, pData, j); int result = 0; result = H264Dec.Hi264DecFrame(_decHandle, pData, (UInt32)j, 0, ref _decodeFrame, (uint)isStop); while (HI_H264DEC_NEED_MORE_BITS != result) { 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); //转为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(5); } /* 销毁解码器 */ H264Dec.Hi264DecDestroy(_decHandle);
要完成工作2,有多种方式,一是自己实现转换,二是使用ffmpeg的库进行yuv和rgb的转换,三是使用D3D进行转换,效率最高的是第三种方式,因为它是利用显卡来进行转换的,更详细的内容可以参考WPF下YUV播放的D3D解决方案 。
要完成工作3就非常简单了,弄个ImageView进行显示就好了。
以上是关于C# 播放H264裸码流的主要内容,如果未能解决你的问题,请参考以下文章