【转】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进行显示就好了。
【转】C#播放H264裸码流的更多相关文章
- C# 播放H264裸码流
要播放H264裸码流,可以分拆为以下三个工作: 1.解码H264裸码流获取YUV数据 2.将YUV数据转换为RGB数据填充图片 3.将获取的图片进行显示 要完成工作1,我们可以直接使用海思的解码库,由 ...
- H264裸码流I/P/B帧类型判别
花了两天时间做了个h264裸流nal类型和frame类型检测的工具,已上传至github,有需要的自行下载. 1.NAL类型检测 nal类型检测非常容易,对照下表即可容易判断类型. 较常用nal类型包 ...
- Wireshark Lua: 一个从RTP抓包里导出H.264 Payload,变成264裸码流文件(xxx.264)的Wireshark插件
Wireshark Lua: 一个从RTP抓包里导出H.264 Payload,变成264裸码流文件(xxx.264)的Wireshark插件 在win7-64, wireshark Version ...
- 利用ffmpeg0.6.1把.h264纯码流打包成.mp4 .avi等格式 (转载)
转自:http://cache2.weidaohang.org/h/index.php?q=aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1cWluZ183MzkvYXJ0aWNsZS ...
- 用ffmpeg命令将264裸码流封装成mp4(转载)
转自:http://bbs.csdn.net/topics/370256130 ffmpeg -f h264 -i source.264 -vcodec copy out.mp4
- C# 实现播放RTSP 标准协议码流播放
http://www.codeproject.com/Articles/507218/Managed-Media-Aggregation-using-Rtsp-and-Rtphttp://www.st ...
- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中
既然已经可以通过 RTSP 获取h264 裸流了.那么通过 FFmpeg 将其保存到文件中怎么做呢? 一.首先RTSP获取 h264 裸流 我们上面两篇文章主要讲的是通过 rtsp://Your ip ...
- H264码流打包分析
转自:http://www.360doc.com/content/13/0124/08/9008018_262076786.shtml SODB 数据比特串-->最原始的编码数据 RBSP ...
- H264码流打包分析(精华)
H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若 ...
随机推荐
- BZOJ 1711:[Usaco2007 Open]Dining吃饭(最大流)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1711 [题目大意] 每头牛都有一些喜欢的饮料和食物, 现在有一些食物和饮料,但是每样只 ...
- 【置换群/模拟】NOIP2005-篝火晚会
[问题描述] 佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”.在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会.一共有n个同学,编号从1到n.一开始,同学们 ...
- kong添加upstream
整理的文档比较早,kong版本可能是0.10.3版本.详情请看官网最新文档 准备 使用kong代理后端请求 1.开放几个接口如下: 本地请求1:http://aaa.wyc.com:8888/aaa ...
- JDK源码学习笔记——HashMap
Java集合的学习先理清数据结构: 一.属性 //哈希桶,存放链表. 长度是2的N次方,或者初始化时为0. transient Node<K,V>[] table; //最大容量 2的30 ...
- django, form.errors处理
from.errors其实就是一个字典, 可以利用for error in form.errors.values, 或者for key, value in form.errors遍历得到其中的数据
- Android:导入工程
File->new->Project->android->Android Project from Existing code 在Root Directory:中填写Andro ...
- 8VC Venture Cup 2016 - Final Round C. Package Delivery 优先队列
C. Package Delivery 题目连接: http://www.codeforces.com/contest/627/problem/C Description Johnny drives ...
- CentOS 6.9/Ubuntu 16.04搭建OpenVPN服务器以及客户端的使用
说明: 1.发现一个很奇怪的现象,CentOS和Ubuntu有着对用户不同的管理理念,比如CentOS中安装一切软件都是以root优先(su -),而Ubuntu则以当前用户优先,安装软件以sudo开 ...
- Elasticsearch 5.5.1的安装和入门教程(转)
说明:转自老阮的文章,业界最简单的入门教程.一切的安装的运行建议不要用root权限,最好是当前用户下的权限. 作者: 阮一峰 日期: 2017年8月17日 全文搜索属于最常见的需求,开源的 Elast ...
- 也来讲REST、SOAP
在GIS网络开发过程中不可避免的的会涉及到REST(Representational State Transfer)的服务.自从Roy Fielding博士在2000年他的博士论文中提出REST风格的 ...