【转】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”)若 ...
随机推荐
- 用xib自定义UITableViewCell的注意事项——重用
问题的提出: 有时候我们经常需要自定义tableView的cell,当cell里面的布局较为复杂时往往舍弃纯代码的方式而改用xib的方式进行自定义.当我们用纯代码的方式布局cell时,往往会在cell ...
- 【MySQL笔记】字符串、时间日期转换
1.新增一列,将字符串日期(年.月.日)转换为Date类型 报错:Error Code: 1175. You are using safe update:http://jingyan.baidu. ...
- express路由和中间件
路由 简单来说,express路由就是用来处理一些请求,响应一些url地址. var express = require('express'); var app = express(); app.ge ...
- [转]SpringMVC拦截器详解[附带源码分析]
目录 前言 重要接口及类介绍 源码分析 拦截器的配置 编写自定义的拦截器 总结 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:ht ...
- MYSQL复习笔记8-数据完整性
Date: 20140207Auth: Jin 一.数据完整性的分类数据完整性是指数据库中数据在逻辑上的一致性和准确性.包括三种1.实体完整性又称行的完成性,要求表中有一个主键,其值不能为空且唯一地标 ...
- Web安全测试指南--权限管理
垂直权限提升: 编号 Web_Author_01 用例名称 垂直权限提升测试 用例描述 测试用户是否具有使用超越其角色范围之外的权限. 严重级别 高 前置条件 1. 目标系统拥有不同等级的角色和权限 ...
- oracle 性能优化建议
原则一:注意WHERE子句中的连接顺序: ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHER ...
- Android内存优化7 内存检测工具1 Memory Monitor检测内存泄露
上篇说了一些性能优化的理论部分,主要是回顾一下,有了理论,小平同志又讲了,实践是检验真理的唯一标准,对于内存泄露的问题,现在通过Android Studio自带工具Memory Monitor 检测出 ...
- [Linux] ubuntu 安装 Wireshark
Wireshark是一款非常流行的协议分析软件.自然可以网络抓包的需求. sudo apt-get install wireshark 出于安全方面的考虑,普通用户不能够打开网卡设备进行抓包,wire ...
- Eureka的自我保护机制
最近项目在Kubernetes上使用Eureka遇到一些问题,在网站上找到一篇针对Eureka自我保护机制原理的文章,觉得不错,总结如下: Eureka的自我保护特性主要用于减少在网络分区或者不稳定状 ...