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

C# 视频播放器如何将帧数据写入屏幕?,c#,video,video-streaming,C#,Video,Video Streaming,我一直在做一些关于机器之间的编码/解码和流式视频的研究,我觉得我已经相当好地掌握了从文件到流的管道。我可以打开容器,解码并抓取单个帧和音频块,我想象通过网络移动这些帧就像简单地发送字节数据一样简单(尽管原始且效率低下)。我不明白的是它到底是怎么演奏的。简单地将帧写入某个图像框,然后将音频数据放到声卡缓冲区中,效果并不理想。有谁能确切地向我解释一下,像vlc player或windows media player这样的程序中发生了什么,它们可以在不破坏cpu和内存的情况下将所有帧数据发送到屏幕上?

我一直在做一些关于机器之间的编码/解码和流式视频的研究,我觉得我已经相当好地掌握了从文件到流的管道。我可以打开容器,解码并抓取单个帧和音频块,我想象通过网络移动这些帧就像简单地发送字节数据一样简单(尽管原始且效率低下)。我不明白的是它到底是怎么演奏的。简单地将帧写入某个图像框,然后将音频数据放到声卡缓冲区中,效果并不理想。有谁能确切地向我解释一下,像vlc player或windows media player这样的程序中发生了什么,它们可以在不破坏cpu和内存的情况下将所有帧数据发送到屏幕上?仅仅是一般的想法或一些高级文档就好了。我甚至不知道从哪里开始


谢谢大家!

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

在Windows中,如果使用DirectX或Direct3D,同样的情况也适用。您甚至可以通过BLITING DIB部分(GDI)获得良好的性能:

不管你怎么画像素,你都要为更新设置一个定时器,就这么简单


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

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

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

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

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


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

VLC是开源的,不是吗?你可以检查一下:)我刚刚记得我们是如何在pocket pc上使用mpeg库实现的。就像你描述的那样。我们使用一个2D库,打开一个曲面,将帧位复制到曲面中,然后将其翻转到屏幕上。当然,现在你可以提前缓冲几帧,或者在帧之间做一些简单的事情,比如插值。但我不认为在这一点上有什么比仅仅把像素带到屏幕上更神奇的了。通过音频-视频时间同步,绘制图像并放置音频数据。+1但Windows中的bitblt会受到一种不幸的副作用,即每当图像更新被刷新时,就会发生这种副作用。你必须使用直接。。。或者更新的API来避免撕裂,不幸的是。是的,我记得当我在386=)上写汇编中的blit例程时撕裂了。我认为等待VSync的老派方法不适用。。。谢谢你的评论。不久前我在写一个播放器的时候遇到了这个问题。我想出了一个奇怪的解决办法,使用DirectX来计时v-sync事件(DirectX公开了这些事件)。您只需要注册几个事件就可以降低v同步的时间,因为它们几乎以完美的规律发生。在动画引擎中,只要确保不渲染任何帧(如果在两侧同步的几毫秒内);相反,你会推迟到之后。它可以工作,但非常愚蠢,因为如果你要使用DirectX,你也可以使用DirectX