看到 Delphi 盒子有人问视频处理的问题,这里针对此问题做一些原理上的解释。
先说能做什么:
1. 简单的,媒体播放器,播放本地视频文件;
2. 捕获本地摄像头的视频,编码压缩,网络传输出去;网络接收视频数据,解码后显示;
3. 把任意来源的视频数据,编码压缩后保存为录像文件;
4. 对视频数据进行一些处理,比如,叠加字幕。
5. 你能想象到的任何视频/音频处理,都能做。
用 Delphi 做媒体处理,比如做一个播放器,或者做一个抓取视频,录像成文件的程序,最方便的是使用 DsPack 那套控件。
Dspack 是基于 windows 的 DirectShow 框架的。这个 DirectShow 我之前也不懂,买了两本书看了半天,发现书也没讲得很明白。当然,按照书上讲的做,也能做出 Demo 来。
直到我自己做了一些东西以后,从做的过程中,逐渐猜到它究竟是个什么。这里面,要说清楚,得写一本书。这里我简单地说一下:
1. DirectShow 框架是基于 DCOM 的;
2. DirectShow 里面的 Filter 其实就是一个 DCOM,当然它必须满足 DirectShow 的规范。
3. DirectShow 的架构:
3.1. 假设我们是做一个播放器,从本地打开一个视频文件,播放到屏幕上,我们需要:1. 打开文件,加载数据;2. 解码文件,从文件里面解出视频帧;3. 逐帧读入数据,丢给分离器,将帧里面的视频数据和音频数据分离;4. 将压缩的视频数据解码;5. 将音频数据解码;6. 将解码后的视频数据显示到屏幕上;7. 将解码后的音频数据从声卡播放出来。
3.2. 上述过程,每一步,是一个独立的功能,为了代码重用,独立的功能,传统的 WINDOWS 程序,就编译为一个独立的 DLL,需要某个功能的地方调用 DLL 就好了。在 DirectShow 框架里面,就是做成一个一个独立的 Filter,然后把这些 Filter 串接起来,就可以完成上述功能。
3.3. 这些 Filter,在概念上,模拟为一个电路里面的芯片,把多个芯片连接起来,就是一个完整的视频播放器。要串接多个 Filter,所以,每个 Filter 必须要有输入和输出引脚(引脚的概念,也来自芯片),在 DirectShow 上面,就是说的一个 PIN,在电子元件上面,也是说 PIN 脚。前面一个 Filter 的输出 PIN,连接后面一个 Filter 的输出 PIN,如何连接,则是依靠 DirectShow 整个框架,具体的代码,就是这个框架提供的连接函数。另外,源头的 Filter 可能只有输出引脚,最末端的 Filter 可能只有输入引脚。
3.4. DirectShow 框架,比如你用 Dspack 构建一个视频播放器,最终在 DirectShow 框架里面,你是构建了一个由多个 Filter 组成的链条,如果你做过硬件,就知道,每个 Filter 其实就相当于是一个电子元件,是一个芯片。把整个视频信号处理的过程,分解为多个不同的功能需要,每个功能,用一个芯片来解决,数据流,流经每个芯片,最终得到视频画面。
3.5. 这些 Filter 在系统里面,是以二进制可执行文件的形态存在,文件名多半是 .ax,和编写它的具体语言无关。它必须符合 DirectShow 的框架,有标准的输入输出引脚(PIN)。这个引脚,其实也就是符合 DCOM 标准的函数,在 Delphi 语言看来,就是一些【接口 -- Interface】,以及接口底下的函数。
3.6. 上述过程中,你可能想加入一个功能,比如你想在图像画面上,加入字幕,那就找一个现成的,或者自己写一个在图像上加字幕的代码,把这个代码,按照 DirectShow 的标准,封装编译,它就是一个所谓的 Filter,文件名后缀是 .ax,其实就是一个 DCOM 控件。在 DirectShow 框架里面,在处理媒体数据流的过程中,你可以在整个处理链条中间,插入任意的 Filter,当然,能不能够插入,还得看具体的媒体数据类型。但原理就是这个原理。
3.7. 构建好整个链条后,它如何被驱动?所有这些代码,被谁驱动的?DirectShow 框架内部有线程在驱动这些代码,驱动数据流在 Filter 之间传递,我们自己写的程序,可以不用在意哪个线程在驱动它。具体到 Delphi,这个被封装到 Dspack 里面,使用 Dspack 就可以了。
4. 视频压缩,也就是要在整个链条里面,加入一个视频压缩的 Filter,取找现成的,这个自己写显然不太现实。另外,如果你的电脑安装了很多媒体相关的软件,可能它么也带来了一些 Filter,你也可以直接拿来用。DirectShow 的好处是,这些 Filter 都是二进制兼容的,在二进制底下可以互相挂接调用,无需源代码。
4.1. 如何知道自己电脑里面有哪些 Filter?其实用 Dspack 控件,拖一个 Filter 到界面上,就可以知道。
4.2. DirectShow 官方有提供一个工具:GraphEdit ,这个工具可以枚举电脑里面安装的 Filter,还可以可视化把各个 Filter 拿出来建立一个链条,让媒体数据在这个链条上跑起来。当然,你拿一个音频的 Filter 接到一个视频数据的 Filter 后面,多半是接不上去的,数据类型都不同嘛。
4.3. 关于 H.264 的解码 Filter,有一个开源的给 Delphi 用的,叫做 FFDShow,自己上网搜。这个东西里面可能也包含了一个压缩编码的 Filter,我不确定有没有。
5. 关于录像成 MP4:
MP4 是一个媒体文件封装标准,它内部的编码可能是 H.264,因此,这里需要 2 个 Filter:
5.1. 压缩编码 H.264 的 Filter
5.2. 把视频数据打包为 MP4 文件格式的 Filter -- 这个不太好找,但我曾经找到过。
5.3. 其实可以考虑其它的文件格式。文件格式和编码压缩格式,是两件不同的事。
5.4. 如果不想通用文件格式,仅仅是要保存录像文件,其实你在编码为 H.264 以后,可以用自己的文件格式来保存视频帧数据,解码的时候自己解析出帧数据,自己丢给 DirectShow 解码就好了。
至于,自己写一个 Filter,DsPack 里面有 Filter 的例子,拿例子来改就好了。这里唯一需要注意的是线程问题。