imx53qsb linux-2.6.35.3 gstreamer 播放ts流媒体

来源:互联网 发布:石黑一雄 知乎 编辑:程序博客网 时间:2024/05/13 10:55

硬件环境:imx53qsb

软件环境:

linux-2.6.35.3

gstreamer-0.10.36

gstreamer gui开发需要使用xoverlay把gstreamer嫁接到gui窗口,这些过程这里不做详述。

飞思卡尔虽然提供了封装有自身硬解单元操作固件库的gstreamer插件,然而如果直接使用有所限制。其一 ,播放uri为空频道时stop则cpu占用飙升100%,程序卡死,飞思卡尔给出的文档要求服务器必须在客户端之前1s开始播放,这个要求实践起来并不友好。其二,在播放正常频道的程序中对管道调用stop然后play时程序将放不出视频。

下面对飞思卡尔插件进行追踪修改。

gstreamer是一套基于插件的音视频处理库,本文的开发工作围绕这些插件展开。

开发参考指令(注意,这里只是参考指令,本文开发中切换频道等动作只有在c源码中根据该指令构建管道添加控制逻辑才有意义):

gst-launch-0.10 udpsrc do-timestamp=false timeout=2000000 uri=udp://225.0.0.1:2001  caps="application/x-rtp" ! queue max-size-time=0 ! rtpmp2tdepay ! queue max-size-time=0 !  aiurdemux streaming_latency=2000 name=d d. ! queue max-size-time=0 ! mfw_vpudecoder  parser=false dbkenable=false profiling=false framedrop=true  min-latency=true fmt=0 ! imxv4l2sink sync=true  d. ! queue  max-size-time=0 ! beepdec ! audioconvert !  'audio/x-raw-int, channels=2' ! volume ! alsasink sync=true

(这里本可以直接使用playbin2 ,虽然playbin2能够利用gstreamer的自动插入插件特性寻到合适的飞思卡尔硬件操作插件,但是这些插件有些bug需要做特殊处理,所以这里还是老老实实自己构造管道)

首先,在应用层播放流时如果播放中stop后又play管道就放不出视频,经测试猜测问题出自mfw_decoder和aiurdemux两个插件,可以采用在play之前将这两个插件从管道中移除然后重新添加的方案解决。

现在管道可以在不同的频道间切换,但是一旦涉及到没有流的uri管道就会使cpu飙升100%,程序卡死,这里在代码中采用逐步从后往前注释掉局部插件代码的方法定位问题,发现只要管道中有aiurdemux插件,则stop就会卡死。

追踪aiurdemux代码发现问题出自于aiurdemux.c 第4590行:

4582 gpointer
4583 aiurdemux_loop_push (gpointer * data)
4584 {
4585   GstAiurDemux *demux = (GstAiurDemux *) data;
4586 
4587   g_mutex_lock (demux->runmutex);
4588 
4589   while (demux->running) {
4590     aiurdemux_push_task (demux);
4591   }
4592 
4593   g_mutex_unlock (demux->runmutex);
4594 }
4595 
4596 
4597 static gboolean
4598 aiurdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
4599 {
4600   GstAiurDemux *demux = GST_AIURDEMUX (GST_PAD_PARENT (sinkpad));
4601 
4602   demux->pullbased = FALSE;
4603 
4604   if (active) {
4605     demux->running = TRUE;
4606     g_thread_create ((GThreadFunc) aiurdemux_loop_push,
4607         (gpointer) demux, FALSE, NULL);
4608   } else {
4609     demux->running = FALSE;
4610     gst_aiur_stream_cache_close (demux->stream_cache);
4611     /* make sure task is closed */
4612     g_mutex_lock (demux->runmutex);
4613     g_mutex_unlock (demux->runmutex);
4614     return gst_pad_stop_task (sinkpad);
4615   }

当aiurdemux发生ready->paused状态转变,则gst_aiurdemux_change_state会调用aiurdemux父类的change_state函数,并在其中以active=true调用aiurdemux_sink_activate_push函数以激活aiurdemux的输入衬垫sinkpad,在4606~4607行调用g_thread_create创建另一个线程执行aiurdemux_loop_push

当aiurdemux发生paused->ready状态转变,则管道中将以active=false调用aiurdemux_sink_activate_push函数以停止aiurdemux的输入衬垫sinkpad,这会使aiurdemux_loop_push函数中的循环变量demux->running=false(46094589行),然后通过g_mutex_lock (demux->runmutex)和g_mutex_unlock (demux->runmutex)确保aiurdemux_loop_push退出后再继续下面操作。然而这里当aiurdemux_loop_push处于demux->state == AIURDEMUX_STATE_PROBE时循环并没有终止,猜测可能是由于循环过快,在

4590    aiurdemux_push_task (demux);之后加一句

if(demux->state == AIURDEMUX_STATE_PROBE)

usleep(1);

编译、更新libmfw_gst_aiur_demux.so库,问题解决。(注意,这里睡眠1us即可,只是为了使while执行下次循环前发生一次进程调度。)

经过上面的修改,程序可以在空频道的play状态stop而不会卡死,但是在空频道重新play时仍然可能会卡死,而这个问题在两个正常频道uri间切换就不会出现,根据提示信息,出现[WARN]VPU mutex couldn't be locked before timeout expired 警告,之后管道放不出视频,此问题是由于从管道移除mfw_decoder之后又创建新的mfw_decoder时初始化VPU无法或VPU 互斥锁导致,试验中发现在空频道->stop->移除mfw_decoder过程中,mfw_decoder的引用有可能会增到16次以上,导致一次释放mfw_decoder其析构函数不会的到调用,相应的锁也无法得到释放,需释放对应于引用计数次才能真正释放mfw_decoder对象。


实际使用当中由于公司自身目标板问题,音频口有可能流入静电,使音频芯片复位,此时管道阻死且得不到任何异常反馈,追踪代码

pipeline ready->paused

aiurdemux ready->paused

gst_aiurdemux_change_state(ready->paused)

GST_ELEMENT_CLASS (parent_class)->change_state();

aiurdemux_sink_activate_push(sinkpad,true);

g_thread_create ((GThreadFunc) aiurdemux_loop_push,(gpointer) demux, FALSE, NULL);

 aiurdemux_loop_push();

aiurdemux_push_task (demux);

aiurdemux_loop_state_init(aiurdemux);

CORE_API (inf, createParser2, goto fail, core_ret,flag, file_cbks, mem_cbks, buf_cbks, (void *) demux, &handle);

此处创建createParser2,该解析器内部使用 lib_mpg2_parser_arm11_elinux.so中的机制,当有合适数据时调用file_cbks中的回调函数gst_aiur_stream_cache_read()从cache中读出数据,而当静电影响到板子时,gst_aiur_stream_cache_read()将得不到调用,cache中数据只有产生没有消费。

aiurdemux上游插件udpsrc有新缓冲块时会调用 gst_aiurdemux_chain函数将buff  推到aiurdemux的sinkpad,gst_aiurdemux_chain中调用gst_aiur_stream_cache_add_buffer将buff加入aiur适配器缓冲中,而此时aiur适配器cache中数据有入无处,数据填满,

aiurstreamcache.c

263     while ((gst_adapter_available (cache->adapter) > cache->threshold_max)
264         && (cache->closed == FALSE)) {
265       if (((++trycnt) & 0x1f) == 0x0) {
266         GST_WARNING ("wait push try %d SIZE %d %lld", trycnt,
267             gst_adapter_available (cache->adapter), cache->threshold_max);
268       }

代码将不停运行至上面循环中,管道数据传至aiurdemux的此处不能下传,遇到这种情况,数据消费问题发生在封闭的lib_mpg2_parser_arm11_elinux.so库中,无计可施,此时可以简单的在267行gst_adapter_available (cache->adapter), cache->threshold_max);下面加一句exit(-1);使程序异常退出。

0 0