• 【转】C#播放H264裸码流


    原文地址:https://www.cnblogs.com/cangyue080180/p/5873351.html

    要播放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进行显示就好了。

  • 相关阅读:
    vue项目,百度地图api高亮选取区域,高亮某个地区,行政区域等
    vue 项目, 通知子组件更新,父组件中每次点击按钮重新加载子组件,(重新生成dom 元素)
    洛谷 P1003 铺地毯
    Codeforces Round #582 (Div. 3)
    安科 OJ 1190 连接电脑 (并查集)
    2018年牛客多校寒假 第四场 F (call to your teacher) (图的连通性)
    牛客小白月赛16 A 小石的签到题 ( 博弈)
    牛客小白月赛16 E 小雨的矩阵 ( 暴搜)
    安科 OJ 1054 排队买票 (递归,排列组合)
    牛客小白月赛15 C 表单 ( map 使用)
  • 原文地址:https://www.cnblogs.com/boonya/p/8249773.html
Copyright © 2020-2023  润新知