要播放H264裸码流,可以分拆为以下三个工作:

1.解码H264裸码流获取YUV数据

2.将YUV数据转换为RGB数据填充图片

3.将获取的图片进行显示

要完成工作1,我们可以直接使用海思的解码库,由于海思的解码库是C++的动态库,要完成在C#中进行调用可以参考海思h264解码库这篇文章,介绍的很详细。但是对于该博文只介绍了一种帧解码的方法,并没有介绍真正实用的流式解码方法。自己根据解码库的参考文档写了一份C#版的流式解码算法。

  1. //初始化
  2. // 这是解码器输出图像信息
  3. hiH264_DEC_FRAME_S _decodeFrame = new hiH264_DEC_FRAME_S();
  4. // 这是解码器属性信息
  5. hiH264_DEC_ATTR_S decAttr = new hiH264_DEC_ATTR_S();
  6. decAttr.uPictureFormat = ;
  7. decAttr.uStreamInType = ;
  8. /* 解码器最大图像宽高, D1图像(1280x720) */
  9. decAttr.uPicWidthInMB = (uint)width / ;
  10. decAttr.uPicHeightInMB = (uint)height / ;
  11. /* 解码器最大参考帧数: 16 */
  12. decAttr.uBufNum = ;
  13. /* bit0 = 1: 标准输出模式; bit0 = 0: 快速输出模式 */
  14. /* bit4 = 1: 启动内部Deinterlace; bit4 = 0: 不启动内部Deinterlace */
  15. decAttr.uWorkMode = 0x10;
  16. //创建、初始化解码器句柄
  17. IntPtr _decHandle = H264Dec.Hi264DecCreate(ref decAttr);
  18. //解码结束
  19. bool isEnd = false;
  20. int bufferLen = 0x8000;
  21. //码流段
  22. byte[] buf = new byte[bufferLen];
  23. while (!isEnd)
  24. {
  25. //获取一段码流,积累一定缓存量再解
  26. if (streamBuf.Count >= bufferLen || isStop == )
  27. {
  28. byte tempByte;
  29. int j = ;
  30. for (int i = ; i < bufferLen; i++)
  31. {
  32. if (streamBuf.TryDequeue(out tempByte))
  33. buf[j++] = tempByte;
  34. else
  35. {
  36. break;
  37. }
  38. }
  39. IntPtr pData = Marshal.AllocHGlobal(j);
  40. Marshal.Copy(buf, , pData, j);
  41. int result = ;
  42. result = H264Dec.Hi264DecFrame(_decHandle, pData, (UInt32)j, , ref _decodeFrame, (uint)isStop);
  43. while (HI_H264DEC_NEED_MORE_BITS != result)
  44. {
  45. if (HI_H264DEC_NO_PICTURE == result)
  46. {
  47. isEnd = true;
  48. break;
  49. }
  50. if (HI_H264DEC_OK == result)/* 输出一帧图像 */
  51. {
  52. //获取yuv
  53. UInt32 tempWid = _decodeFrame.uWidth;
  54. UInt32 tempHeig = _decodeFrame.uHeight;
  55. UInt32 yStride = _decodeFrame.uYStride;
  56. UInt32 uvStride = _decodeFrame.uUVStride;
  57. byte[] y = new byte[tempHeig * yStride];
  58. byte[] u = new byte[tempHeig * uvStride / ];
  59. byte[] v = new byte[tempHeig * uvStride / ];
  60. Marshal.Copy(_decodeFrame.pY, y, , y.Length);
  61. Marshal.Copy(_decodeFrame.pU, u, , u.Length);
  62. Marshal.Copy(_decodeFrame.pV, v, , v.Length);
  63.  
  64. //转为yv12格式
  65. //byte[] yuvBytes = new byte[y.Length + u.Length + v.Length];
  66. //Array.Copy(y, 0, yuvBytes, 0, y.Length);
  67. //Array.Copy(v, 0, yuvBytes, y.Length , v.Length);
  68. //Array.Copy(u, 0, yuvBytes, y.Length + v.Length, u.Length);
  69. //更新显示
  70. this.d3dSource.Render(_decodeFrame.pY, _decodeFrame.pU, _decodeFrame.pV);
  71. }
  72. /* 继续解码剩余H.264码流 */
  73. result = H264Dec.Hi264DecFrame(_decHandle, IntPtr.Zero, , , ref _decodeFrame, (uint)isStop);
  74. }
  75. }
  76. System.Threading.Thread.Sleep();
  77. }
  78. /* 销毁解码器 */
  79. H264Dec.Hi264DecDestroy(_decHandle);

要完成工作2,有多种方式,一是自己实现转换,二是使用ffmpeg的库进行yuv和rgb的转换,三是使用D3D进行转换,效率最高的是第三种方式,因为它是利用显卡来进行转换的,更详细的内容可以参考WPF下YUV播放的D3D解决方案 。

要完成工作3就非常简单了,弄个ImageView进行显示就好了。

C# 播放H264裸码流的更多相关文章

  1. 【转】C#播放H264裸码流

    原文地址:https://www.cnblogs.com/cangyue080180/p/5873351.html 要播放H264裸码流,可以分拆为以下三个工作: 1.解码H264裸码流获取YUV数据 ...

  2. H264裸码流I/P/B帧类型判别

    花了两天时间做了个h264裸流nal类型和frame类型检测的工具,已上传至github,有需要的自行下载. 1.NAL类型检测 nal类型检测非常容易,对照下表即可容易判断类型. 较常用nal类型包 ...

  3. Wireshark Lua: 一个从RTP抓包里导出H.264 Payload,变成264裸码流文件(xxx.264)的Wireshark插件

    Wireshark Lua: 一个从RTP抓包里导出H.264 Payload,变成264裸码流文件(xxx.264)的Wireshark插件 在win7-64, wireshark Version ...

  4. 利用ffmpeg0.6.1把.h264纯码流打包成.mp4 .avi等格式 (转载)

    转自:http://cache2.weidaohang.org/h/index.php?q=aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1cWluZ183MzkvYXJ0aWNsZS ...

  5. 用ffmpeg命令将264裸码流封装成mp4(转载)

    转自:http://bbs.csdn.net/topics/370256130 ffmpeg -f h264 -i source.264 -vcodec copy out.mp4

  6. C# 实现播放RTSP 标准协议码流播放

    http://www.codeproject.com/Articles/507218/Managed-Media-Aggregation-using-Rtsp-and-Rtphttp://www.st ...

  7. 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

    既然已经可以通过 RTSP 获取h264 裸流了.那么通过 FFmpeg 将其保存到文件中怎么做呢? 一.首先RTSP获取 h264 裸流 我们上面两篇文章主要讲的是通过 rtsp://Your ip ...

  8. H264码流打包分析

    转自:http://www.360doc.com/content/13/0124/08/9008018_262076786.shtml   SODB 数据比特串-->最原始的编码数据 RBSP ...

  9. H264码流打包分析(精华)

    H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若 ...

随机推荐

  1. Visualbox安装Ubuntu网络设置

    注意:Windows 10在安装Visualbox后,创建的Ubuntu系统只有32位的,没有64位供选择,原因是Windows 10系统自带的Hyper-V系统占用了CPU虚拟化技术,解决的方法是取 ...

  2. 树上两点的最近公共祖先问题(Least Common Ancestors)

    概念: 对于有根树T的两个节点u,v,最近公共祖先LCA(T, u, v)表示一个节点 x, 满足 x 是 u , v 的祖先且 x 的深度尽可能的大.即从 u 到 v 的路径一定经过点 x. 算法: ...

  3. NOIP2011选择客栈

    n家客栈,1~n编号,每家按照某一种色调装饰,共k种,每家客栈都设有咖啡店,每家咖啡店均有各自的最低消费两位游客,要求住在颜色相同,且不是同一个客栈,在两人的客栈间选择咖啡店(包括他们住的客栈),要求 ...

  4. 推荐下载CentOS下各种组件的网址

    http://vault.centos.org/ ftp://mirrors.sohu.com/ http://mirror.webtatic.com/

  5. 4、Django实战第4天:xadmin快速搭建后台管理系统

    Django默认为我们提供了后台管理系统admin, urls.py中配置的第一条就是访问后台管理系统admin的 urlpatterns = [ url(r'^admin/', admin.site ...

  6. ( 转 ) UML 类图

    在UML类图中,常见的有以下几种关系:泛化(Generalization),  实现(Realization),关联(Association),聚合(Aggregation),组合(Compositi ...

  7. [Atcoder Regular Contest 060] Tutorial

    Link: ARC060 传送门 C: 由于难以维护和更新平均数的值: $Average->Sum/Num$ 这样我们只要用$dp[i][j][sum]$维护前$i$个数中取$j$个,且和为$s ...

  8. 【Java】Java划水练习

    bzoj1000 A+B Problem Scanner sc=new Scanner(new BufferedInputStream(System.in)); 声明读入器 nextInt 读入整数 ...

  9. 【计算几何】 Codeforces Beta Round #67 (Div. 2) E. Ship's Shortest Path

    读懂题意其实是模板题.就是细节略多. #include<cstdio> #include<cmath> #include<algorithm> using name ...

  10. python3开发进阶-Django视图(View)的常见用法

    阅读目录 简述Django的View(视图) CBV和FBV Request对象和Response对象 Django组件(render,redirect)详解 一.简述Django的View(视图) ...