当前位置: 代码迷 >> 综合 >> Gstreamer 工具使用 (一)
  详细解决方案

Gstreamer 工具使用 (一)

热度:70   发布时间:2024-01-11 23:27:26.0

http://blog.csdn.net/android_lee/article/details/6791753

http://blog.csdn.net/android_lee/article/details/7071989

拿 mp3档案做例子,用一个比较普遍而且广泛应用的格式做练习有很多好处,一来没有影像,就先省去同步的问题,也不会有cpu / bandwidth 不够的问题(因为 video的 bitrate 比 audio高出很多);二来测试档案满地爬,而且横跨多种不同参数的压缩格式,更好的是可以互相参照的播放器也是满地爬(一不小心就踩到的程度…搭捷运时年轻人几乎人手一台 player),抓虫或对照功能时很好用。

gstreamer 提供了一个command line 建立 pipeline的工具:gst-launch。给不同的参数可以自动或手动的方式去播放一个多媒体档,这个工具说方便很方便,说不方便也的确有点麻烦。方便是一个指令就可以叫它开始播档案,省去图型化介面的慢和滑老鼠的动作;不方便是因为它除了play 以外没有别的navigation command,不像mplayer还有给 hotkey快转 (快转对於看谜片来说是很重要的呀!!)

至於所谓的 pipeline,长得就像这样箭头和方块组成的结构就称为pipeline,而每个方块(element) 都负责某一部份的资料处理,称为element。这和 DirectShow的 graph 是相当神似的。有DirectShow 基础的人应该会比我还快了解gstreamer 吧。

总之,自动建立 pipeline的指令是如此:

gst-launchplaybin uri=file:///path/to/file.mp3

而手动建立的话可以这么简单:

gst-launchfilesrc location=/path/to/file.mp3 ! mad ! alsasink

其中的 mad 就是gstreamer 会 runtime去 load 的 element,也就是接下来会深入去讲的主题。如果你的系统缺少了解码mp3 必要的函式库或gstreamer 针对 mp3的插件,那就会播放失败。开源的 mp3函式库很多,我们就用mad(mpeg audio decoder)



以 ubuntu 为例,安装必要的函式库很容易:

sudoapt-get install libmad0 gstreamer0.10-plugins-ugly

 如此应该就可以顺利听到 mp3的音乐了。其他必要的 element像是 audio renderer通常预设就会安装了。知道了这些工具后我们就可以开始以mad 为师的 gstreamer插件学习过程。

首先,我们最好用 gst-inspect看看 mad这个插件的一些资料,这些都会是接下来写程式或多或少会用到的。

gst-inspectmad

我们会看到一些对这个插件的描述,padtemplate 的 capabilities等等,gstreamer的文件里有比较清楚的列出哪些properties 对 capabilities的描述和对应的意义,此处就不多说。

gst-launch 和 gst-inspect是开发插件时满重要的两个工具,玩熟练后我们就可以开始实作自己的mp3 gstreamer插件。gstreamer很体贴的在网站上摆了一个插件的 template,我们就从这个template 开始走下去。

<span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">git clone git://anongit.freedesktop.org/gstreamer/gst-template.git</kbd></span>

下载后在作业目录会找到一个 gst-template的资料夹,然后进到 gst-plugin/src执行

../tools/make_elementmp3dec

这个 tool 会用 mp3dec为名产生一个 gstreamerplugin 的 template。这两件事情就是在做gstreamer plugin writer’s guide section 3.1, 3.2

接著,我们要「立刻」看到自己写的 plugin被 gst-inspect 找到,这要怎么做呢?

首先,改写 gst-plugin/src/Makefile.am,让他编译我们的程式,用文字编辑器把gstplugin 这个字串换成gstmp3dec。接著就像一般我们在编译开源专案一样,藉autotool 来产生Makefile,执行gst-plugin/autogen.sh。接著到gst-plugin/src 下 make,就会在gst-plugin/src/.libs/ 下面看到libgstmp3dec.so,这个就是我们的gstreamer 插件。你可以用

GST_PLUGIN_PATH=/path/to/gst-template/gst-plugin/src/.libs/gst-inspect mp3dec

来检视这个插件的细节,就像之前我们检视 mad一样,会发现很多资讯在 mad里面有的,在 mp3dec这个新生的插件里看不到,那些就是我们要慢慢加上去的功能。

上一篇我们把一些编译 gstreamer插件的环境给准备好,也透过 gst-inspect看到新加入的插件 (在上一个例子中是「mp3dec)的属性,接著就要亲眼见证它的运作了。

先打开 gstmp3dec.c 找到

g_printf(“I'mplugged, therefore I’m in.\n”);

这一行,改一下文字,然后跳出重编,执行

gst-launchfilesrc location=/path/to/file.mp3 ! mad ! mp3dec ! alsasink

有没有看到一行你刚刚改的字拚命洗画面,那就是插件运作的明证。接著我们要开始改写这个插件,来让它取代mad。所以测试方法也很明确,就是要让

gst-launchfilesrc location=/path/to/file.mp3 ! mp3dec ! alsasink

这指令可以正确地播出 file.mp3的内容。这个指令会在接下来的测试过程中不断的被执行。

接著编辑 gstmp3dec.c(这个档案也会不断的修改),寻找GstStaticPadTemplate ,会找到已经被自动产生的两个padsink_factory和 src_factory 。还不知道pad是什么没关系,先想像它是插件的「开口」就好;上一篇文章我们有提到所谓的pipeline 的箭头是有方向性的,资料从源头(档案、网路…等)读取出来后,从读取的插件开始(即:file-source),到播送的插件出去(即:audio-sink和 video-sink)

[转]看見 <wbr>gstreamer <wbr>plugin <wbr>的第二步

透过插件的「开口」,资料才能在插件之间流动,就像滤水器的进水阀和出水阀,控制流进流出的水量、速度等等。不过gstreamer的水阀比较复杂一点,它必须再去判断多媒体资料流的属性,动态地决定输入的多媒体档案要用哪一个滤水器来承接。在这里水阀就是GstPad,而标示水阀的「属性」就是 GstCaps。进水阀我们称为「sinkpad」,出水阀我们称为「sourcepad」,所以按上图来看,file-source没有「安装」「sinkpad」是因为他在进水的那一条路是透过系统的file I/O 来处理,不属於gstreamer pad 的范畴;同样的audio-sink 和 video-sink没有「安装」「sourcepad」是因为在播放声音和影像的部份是透过系统的A/V renderer。而在中间的插件们,最基本的型态是一个进水(后称sinkpad )一个出水(后称srcpad ),像 decoder;而 demuxer 要把audio/video (或更多,视封装格式而定)资料拆开给各自的解码器,就会有一个 sinkpad,多个 srcpad,因为责任重大,demuxer写起来也比较复杂。

解释完插件和 padcaps之间的关系后,我们先透过程式去设定 mp3dec的属性。为求简单,我们照抄 mad的属性就好,所以 sink_factory和 src_factory 会改成如下

<span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">    </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">GST_PAD_SINK,</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">    </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">GST_PAD_ALWAYS,</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">    </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">GST_STATIC_CAPS ("audio/mpeg,   \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">mpegversion=1,      \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">layer=[1,3],        \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">rate={8000,11025,12000,16000,22050,24000,32000,44100,48000},\</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">channels=[1,2]")</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">);</kbd></span>
<span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">    </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">GST_PAD_SRC,</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">    </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">GST_PAD_ALWAYS,</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">    </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">GST_STATIC_CAPS ("audio/x-raw-int,  \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">endianness=1234,    \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">signed=true,        \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">width=32,           \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">depth=32,           \</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">rate={8000,11025,12000,16000,22050,24000,32000,44100,48000},\</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">channels=[1,2]")</kbd></span>
<kbd class="cjk" style="font-family: 'DejaVu Sans', monospace;">        </kbd><span style="font-family: 'DejaVu Sans Mono', monospace;"><kbd class="western">);</kbd></span>

重编后再用 gst-inspect检查一下就会发现在 PadTemplates 里所描述 sinkpad和 srcpad 的属性都更新了,看的出来mp3dec 接受的输入格式是mpeg1 audio layer3 的资料流,输出pcm 。设定这些属性的目的就跟前述一样,让gstreamer 在自动产生pipeline的时候可以按照我们设定的格式找到正确的插件来处理资料。(想像一下滤水器的进入出入阀标示著这个是滤工业用水、那个是滤农业用水、另一个是滤家庭用水,口径多少、每单位吃水量多少…等等等,如此就算滤水器的功能一样,而相对应的口径、水量不符合,gstreamer也不会接错。)

然而,这边设定的 caps只是一个样板,告诉上下插件输入和输出资料的格式及相关属性的「范围」,做为建立pipeline时参考的依据,当档案开始播放时,真正的资料流的格式、属性要等解码完才知道。换言之,caps的设定不一定是在 template里写死就好,有时要另外动态产生运行时对应的caps 并指派给 pad( 包括 sinkpad srcpad )

在处理 sinkpad srcpad 的程式都还没写之前就先设定caps 其实并没有具体的功能,但我觉得这样解释比较不会搞不清楚或混淆caps 的目的和重要性。

当 caps 被设定好后,我们再来执行看看前面执行过的指令

gst-launchfilesrc location=/path/to/file.mp3 ! mad ! mp3dec ! alsasink

有没有发现结果不一样了?此时音乐不会播,程式直接中断并吐出一行字:

WARNING:erroneous pipeline: could not link mad0 to mp3dec0

原因很简单,就是 gstreamer发现 mad 的输出阀(srcpad) 和 mp3dec的输入阀 (sinkpad) caps 不符合。所以跑都不跑就直接跳掉了。


  相关解决方案