【问题标题】:How do video players write frame data to the screen?视频播放器如何将帧数据写入屏幕?
【发布时间】:2013-01-18 02:28:07
【问题描述】:

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

谢谢!

【问题讨论】:

  • VLC 是开源的不是吗?你可以检查一下:)
  • 我只记得我们是如何在袖珍电脑上使用 mpeg 库做到的。就像你描述的那样。我们使用 2D 库,打开一个表面,将帧位复制到表面并将其翻转到屏幕上。现在你当然可以提前缓冲几帧,或者做一些简洁的事情,比如在帧之间进行插值。但我不认为在这一点上有更多的魔力,而不仅仅是将像素带到屏幕上。
  • 画图放音频数据,音视频时间同步。

标签: c# video video-streaming


【解决方案1】:

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

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

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

为了获得流畅的操作,您需要在绘图之前进行缓冲,以便磁盘(或网络)和解码延迟不会影响实时绘图。即使是视频中最轻微的抖动也能被人类感知到。当您的计时器触发时,您需要在图像缓冲区中解码像素并准备好绘制。

【讨论】:

  • +1 但 Windows 中的 bitblt-ing 会受到称为 tearing 的不幸副作用的影响,只要图像更新在刷新中被捕获,就会发生这种情况。不幸的是,您必须使用 Direct... 或更新的 API 来避免撕裂。
  • 是的,我记得当我在 386 上编写 blit 例程时咬牙切齿时泪流满面 =) 我认为等待 VSync 的老式方法不适用...谢谢您评论。
  • 我不久前在编写播放器时遇到了这个确切的问题。我想出了一个奇怪的解决方法,它涉及使用 DirectX 来计时 v-sync 事件(DirectX 公开)。您只需要注册一些事件即可降低垂直同步的时间,因为它们以近乎完美的规律发生。在动画引擎中,如果您在任一侧同步的几毫秒内,您只需确保不渲染任何帧;相反,您延迟到之后。它有效,但它非常愚蠢,因为如果你要使用 DirectX,你不妨只使用 DirectX
【解决方案2】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 2014-02-06
    • 1970-01-01
    相关资源
    最近更新 更多