视频播放器如何将帧数据写入屏幕?

时间:2013-01-18 02:28:07

标签: c# video video-streaming

我一直在研究机器之间的编码/解码和流视频,我觉得我已经掌握了从文件到流的管道。我可以打开容器,解码并抓取单个帧和音频块,我想通过网络移动这些帧就像发送字节数据一样简单(虽然原始和低效)。我不明白的是它实际上是如何发挥作用的。简单地将帧写入某个图像框并将声音数据放在声卡缓冲区中并不能很好地工作。任何人都可以向我解释在vlc播放器或Windows媒体播放器等程序中发生的事情,它们允许它们将所有这些帧数据发送到屏幕而不会破坏CPU和内存吗?只是一般的想法或一些高级文档将是伟大的。我甚至不知道从哪里开始...

谢谢!

2 个答案:

答案 0 :(得分:1)

如果使用OpenGL,则可以创建纹理并不断用新的帧数据替换它。这不是一个非常昂贵的操作。然后,您可以在窗口中绘制纹理矩形。 glOrtho是有用的预测。

在Windows中,如果您使用DirectX或Direct3D,则同样适用。您甚至可以获得良好的性能blitting DIB Sections(GDI):Fastest method for blitting from a pixel buffer into a device context

无论您如何绘制像素,都可以为更新设置计时器,就这么简单。

要获得平稳的操作,您需要在绘图之前缓冲,以便磁盘(或网络)和解码延迟不会影响实时绘图。即使视频中最轻微的抽搐也可以被人类感知。当您的计时器触发时,您需要在图像缓冲区中解码像素并准备绘制。

答案 1 :(得分:1)

我已经编写了许多播放器应用程序(适用于Windows),它们结合了视频和音频,并且需要两者之间的精确同步。在Windows音频中,您基本上准备缓冲区(只是音频样本值的数组)并将它们排队到音频子系统进行播放;当每个缓冲区完成播放时,子系统会对您的应用程序进行回调,并且您的应用程序会使用每个回调来1)将下一帧渲染到屏幕,以及2)准备下一个音频块以排队到音频子系统。 / p>

例如,假设您在内存中有一些视频帧要以每秒50帧的速度播放,与单声道音频同步,每个样本2个字节,每秒449个样本。这意味着您的音频缓冲区大小需要882个样本(44,100 / 50 = 882),因此每个缓冲区只是一个包含882个元素的短(2字节)整数数组。你需要至少两个缓冲区,但实际上更多更好(与缓冲区的权衡是更多的缓冲区意味着更平滑的播放,代价是更长的启动延迟和更大的内存占用)。

视频的帧需要以相同的方式“缓冲”,以便至少一帧始终可以渲染;将单个图像传输到PC屏幕是如此之快,以至于它实际上是即时的,而不是您需要担心的事情。唯一的问题是用任何方法提取或组合帧。这些方法需要至少足够快以跟上播放速率,或者需要在播放之前很好地缓冲,这也会导致更长的启动延迟和更大的内存占用(这些问题对于视频来说要比它们用于音频,具有任何合理的分辨率。)

当应用程序开始播放时,它会预先加载所有带有音频的缓冲区并将它们排队等待播放;然后,它同时开始播放并将第一帧渲染到屏幕。用户看到第一帧并听到前20毫秒的音频(20毫秒= 1/50秒)。此时,音频子系统将播放从第一缓冲区切换到第二缓冲区,并对应用程序进行回调。然后应用程序将第二帧渲染到屏幕并使用下一个可用的音频块填充第一个缓冲区,然后将第一个缓冲区再次排队到音频子系统。

只要应用程序有可用的音频和视频数据来继续填充缓冲区和帧,此过程就会继续,您可以看到/听到视频。