文章最初发表于it168 
http://tech.it168.com/n/d/2007-04-18/200704181517531.shtml

这个月准备写一些关于如何使用3D API搭建一个高质量的视频回放后端,其实想想也是时候了,在这个公司快一年了,Backend从开始的支持RGB24,到YUV的支持,到后来质量的不断提高, 尤其是播放质量被SONY这样苛刻的公司接受以后,总觉得该写一点东西了.
其实要在3D 环境播放视频并不是件困难的事情,如果你仅仅是想做一个视频纹理,那么你可以放心的做很多假设,并且让美术提供的视频都必须满足你的假设,你可以使用RGB24的格式,你可以选择让DirectShow来为你完成YUV-RGB的color space的转化,你也可以不考虑播放是不是完全流畅的,因为那仅仅是整个游戏中的一个小小的部分,没人会来关系整个部分的视频是不是流畅.
如果你做的是个播放器,专门用来播放视频的,那么质量问题喝兼容问题显得非常重要:
1: 你要支持YUV格式,至少要支持一种: YV12.
2: 你不能不能考虑播放的流畅性.,不能产生Frame drop现象.
3: 必须适应Decoder出来的frame的步调,除了保证不丢帧以外,还需要保证不会有的帧在屏幕上停留时间太长,有的太短.
4: 你不得不考虑性能问题,因为有些视频文件是巨大的,HD的视频1920 x 1080 这样的分辨率是非常常见的,Decoder会在解码的动作上耗费掉大量的CPU,留给backend的时间并不多..
就以上问题,总结起来是两个: 一,YUV格式的支持.二,提供性能,保证播放流畅性. 下面我来说说一些解决方案.
一:YUV格式的支持.
YUV格式其实有很多种, 大类分成两类,Packed的跟plannar的.前者是YUV是挤到一个int32里的(注意这个挤字),另外一种是YUV三个分量的数据分开保存,等于三个数组.
我们知道用3D API中,用来保存图象的资源就是纹理,对于以上两类YUV格式,显然是第一种比较自然一些,但是必须注意的是packed的YUV格式,通常是交错的 ,比如排列方式是YUYV这样排列, 因为对视频来说,Y亮度信息明显比UV色差信号要来的重要,所以说,在4个字节中挤进去两个像素的信息,这两个像素公用一个UV值. 这种格式就称为YUYV格式. 除此之外还有其他很多对一般应用者来说可能是千奇百怪的格式. 因此,事实上packed的YUV.只是看上去比较自然,实现起来却并不是那么简单轻松.即使是比较容易实现的YUYV格式,也很难实现它的平滑滤波.
相反来说,对于plannar的YUV格式, 我们虽然没办法用一个纹理来模拟它,但是完全可以采用三个纹理的方式来模拟它,这种方式几乎不需要在Pixel Shader做很多特殊处理,无非就是三个纹理采样动作而已.非常幸运的是,现在大部分的解码器都是直接输出YV12格式的,在一个分辨率是MxN大小的YV12格式中,的一块数据是MxN的Y信号.接下来是一块M/2 x N/2大小的U信号,最后是M/2 x N/2的V信号,也就是说,Y信号的分辨率比UV大一倍. 这样我们可以用一个MxN跟两个M/2 x N/2纹理就可以模拟出YV12格式了.并且可以自由的使用各种纹理滤波方式.
解决了如何把YUV信号输入到3D API中,接下来就可以使用Pixel Shader来对采样的YUV信号进行调整,并转化成RGB信号,这个转化是非常简单的.代码如下:
sampler2D texYPlane;
sampler2D texUPlane;
sampler2D texVPlane;
float4 main( float2 texCoord : TEXCOORD0 , float4 fColor : COLOR) : COLOR
{
float4    matYUV2RGB0 = float4 (1.0 , 0.0    , 1.14   , 0.0);
float4    matYUV2RGB1 = float4 (1.0 , -0.390 , -0.58 , 0.0);
float4    matYUV2RGB2 = float4 (1.0 , 2.03   , 0      , 0.0);
//输入的YUV必须加个偏移量.详细细节参见www.fourcc.org
float4    deltaYUV = float4 (-0.00   , -0.500 , -0.500 , 0.0);
float4 yuvColor;
//对三个纹理进行采样
float2 newTexCoord = float2(texCoord.x , texCoord.y);
yuvColor.x   = tex2D( texYPlane, newTexCoord ).x;
yuvColor.y   = tex2D( texUPlane, newTexCoord ).x;
yuvColor.z   = tex2D( texVPlane, newTexCoord ).x;
yuvColor.w = 1.0f;
yuvColor = yuvColor + deltaYUV;
//adjust color
yuvColor = adjustColor(yuvColor);
float4 imageColor;
//YUV 到RGB的转换
imageColor.x =dot(matYUV2RGB0.xyz , yuvColor.xyz);
imageColor.y =dot(matYUV2RGB1.xyz , yuvColor.xyz);
imageColor.z =dot(matYUV2RGB2.xyz , yuvColor.xyz);
imageColor.w = 1.0;
return imageColor;
}
关于adjustColor函数,主要是用来对对比度,饱和度等进行调节的,具体算法,在数字图象处理中都可以找到.关于详细的YUV资料,可以到www.fourcc.org上去找.
二: 如果提高播放的流畅性
播放的流畅性,首先要保证性能. 如果说,解码器解码一帧的时间是40ms.那么无论如何你怎么优化,视频都不会流畅.同样的,如果视频解码器解码一帧费时是25ms.那么如果是24fps为正常播放速率,那么表示留给你去绘制的时间有16ms.在这16ms内,你必须把这一帧图象下载到GPU中,并把它绘制出去,绘制其实可以和解码是异步进行的,那么下载的动作呢?在OpenGL里我们可以采用PBO来进行纹理数据异步下载,这能大大的提高纹理更新的速度.
另外一方面,并不是说你的更新速度足够高就能让视频看起来是流畅的,你还必须保证更新的步调和解码器输出是一致的.也就是说不能更新快,也不能更新慢了.我们可以采用两种方法来进行解码帧和绘制帧两个动作的同步.
第一种方法,线程锁 + 标记变量. 通常绘制和解码不是在同一个线程中的,我们可以为视频输出纹理加一个锁和标记变量,当纹理正在被解码器写入的时候,我们就lock,并在unlock的时候,设置标记变量的状态为dirty.这就等于通知了绘制线程,告诉它视频帧的数据被更新,需要绘制. 而绘制线程会在进行绘制前检测标记变量,只有标记变量是dirty的时候,才进行绘制,或者可以选择不更新画面或者等待标记变量变成dirty状态.
第二种方法,采用信号量. 我们可以声明一个HANDLE drawEvent, 当解码器更新完一帧数据才升起这个信号量.具体代码如下:
int drawFrameThreadFunc(int)
{
initDrawDevice();//分配一个Direct3D/OpenGL的设备
while(1)
{
//其他一些逻辑.........
WaitForSingleObject(drawEvent,200);
drawYV12VideoTexture();
//其他一些逻辑.........
}        
closeDrawDevice();//关闭设备.
}
这两种方法,后一种比较精确,前一种相对比较自由.并且可以和有很多动态效果的GUI结合在一起.
到此为止,我简单了介绍了高质量播放视频时候需要注意的一些问题,相对来说都是比较大的概括,细节上的问题还会更加的多.比如缩放滤波的质量,视频的反交错等问题都需要费很大的精力去完成.因此,做一个播放器的后端也不是那么简单的:). 如果读者有更好的方法和建议,可以通过邮件跟我联系.

高效率视频播放: 如何使用3D API 进行视频的高质量回放(1)相关推荐

  1. 哪里可以下载大量短视频?高质量短视频批量下载

    哪里可以下载大量短视频,高质量短视频批量下载,哪里可以下载大量短视频,现在很多人都觉得自媒体运营很难,其实它的确是很难,不过你学会运营技巧之后,就会容易很多,最近有些小伙伴问我哪里可以去批量下载视频素 ...

  2. NVIDIA研究人员利用AI将标准视频转换为高质量慢动作镜头

    内容来源:ATYUN AI平台 来自NVIDIA的研究人员开发了一个基于深度学习的系统,该系统可以用每秒30帧的视频制作高质量的慢动作视频,超过了旨在实现相同效果的各种方法.研究人员将在本周CVPR会 ...

  3. [FFMpeg开发]视频转高质量GIF优化方案(接近ps生成效果),从原理剖析

    摘要 虽然此前有人发过了,但是这个博主没有分析原理并且没有提炼出来.不适合开发者学习. 所以我只是进行二次优化,原文高质量视频转gif 此前,做产品的时候,产品用到了ffmpeg框架,手上几个ffmp ...

  4. 高效率的免费发布信息平台,助力企业高质量采购

    随着互联网采购平台的崛起,越来越多的企业从中受益,它们不再因为线下采购的单一性而产生供应链效率低化的现象,选择与这些免费发布信息平台合作,可以快速提高企业的核心竞争力,也正是各多企业都追求于线上采购, ...

  5. 在佛山如何找到一个高质量的股票交易API平台?

    股票交易API平台是量化交易和金融工具中最重要的组成部分.股票交易API平台就是一个帮助用户实现股票交易的过程,它可以实时监测市场交易情况,并且设定一些条件,一旦当市场交易情况满足这些条件时就自动执行 ...

  6. 视频播放器是如何播放音视频的?

    当我们用手机或者电脑打开一个电影视频或者一首音频歌曲的时候,不论是在线流量还是离线本地播放,通常设备上的音视频播放器都可以将音视频文件中的画面和声音给到我们的视觉和听觉器官,这是我们习以为常的东西.但 ...

  7. Map 3D API二次开发学习指南

    作者:杜长宇 – Autodesk开发技术顾问 2012年9月26日 AutoCAD Map 3D 是构建于AutoCAD之上,面向基础设施领域的产品,他采用FDO技术来实现对业界常见GIS数据格式的 ...

  8. IOS端微信小程序API播放视频无效,应该这样做

    微信小程序 IOS端通过API播放视频无效 需求 微信小程序项目中需求点击"播放"按钮,直接开始播放视频 问题 直接调用微信API操作视频播放,Adroid端运行一切正常,IOS端 ...

  9. 学习FFmpeg API –解码视频

    转自:http://my.oschina.net/u/555701/blog/56616 ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg ...

最新文章

  1. redis系列:通过队列案例学习list命令
  2. go get报错:unrecognized import path “golang.org/x/net/context”…
  3. ImportError: cannot import name 'AliPay'
  4. USACO-Section1.3 Palindromic Squares (进制转换和回文数)
  5. PSCAD中的频变参数线路模型(Frequency-Dependent (Phase) Line Model)
  6. Linux关于文档编辑的命令
  7. 计算机硬盘根目录是什么,解决方案:硬盘根目录是什么意思?它存储在哪里?...
  8. 计算机系统与维护专科毕业论文,计算机系统维护毕业设计论文
  9. [Luogu P3975] [TJOI2015]弦论
  10. 关于《那些年啊,那些事——一个程序员的奋斗史》的更新
  11. Mapbox GL JS 表达式概述
  12. 2019第十届蓝桥杯JAVA B组题目分析
  13. 标准C语言各种时间函数用法
  14. 【计算机网络】数据链路层 : 后退 N 帧协议 GBN ( 滑动窗口 | 发送窗口长度 | “发送方“ 累计确认、超时机制 | “接收方“ 按序接收、确认帧发送机制 | 计算示例 )★
  15. NLP中的特殊标记(Special Tokens)[PAD]、[CLS]、[SEP]、[UNK]
  16. 树的数据结构代码_如何以无代码方式学习树数据结构
  17. echarts 3d地图加动画效果
  18. express应用中ajax结合模板引擎ejs.js渲染页面
  19. 魔兽世界9.5人口最多服务器,魔兽世界最新全球服务器人口普查,国服早已不是世界第一人口大服...
  20. 书签转json格式代码(chrome,edge...)

热门文章

  1. 7-140 阶梯电价
  2. 笔记本外接显示器,窗口最大化后超出液晶显示器的屏幕
  3. 网页文字的应用于布局
  4. HEIC图片转换格式工具
  5. 恒成立、能成立和恰成立三类命题赏析【初级和中级辅导】
  6. outlook计算机应用操作题,《计算机应用基础》Internet应用题型专项练习
  7. 字节字双字地址的区别
  8. J2EE----JMS
  9. 数学建模养成篇1:了解数学建模
  10. 杂学——密码学、中国余数定理、韩信点兵法、取模运算