问题描述:

当使用GStreamer的rtmpsrc plugin时,在停止pipeline时会偶现一个crash bug。

具体描述:

当从外部调用gst_set_state(GST_STATE_NULL)之后, rtmpsrc会进一步调用gst_rtmp_src_unlock()和gst_rtmp_src_stop()两个接口,然后当此时pipeline的数据线程阻塞在gst_rtmp_src_create()的librtmp的RTMP_Read()接口时,调用RTMP_Free()会导致crash;究其原因,librtmp不是一个多线程的库。

解决方案:

1. 在gstrtmpsrc中加锁保护rtmp对象。
2. 在librtmp中添加回调方法,使得RTMP_Read()在无音视频数据的情况下不会长时间阻塞。

备注:

GStreamer 1.4.5
librtmp 2.4_p20131018


gstrtmpsrc.c

gst_rtmp_src_init()
{
...
g_mutex_init(&rtmpsrc->lock);
}

static void
gst_rtmp_src_finalize (GObject * object)
{
    /* Add by sparktend. */
    rtmpsrc->stop_flag = FALSE;
    g_mutex_clear (&rtmpsrc->lock);
}

static int stop_interrupt_cb(void *ctx)
{
    GstRTMPSrc *rtmpsrc = (GstRTMPSrc *)ctx;
    if (rtmpsrc) {
          GST_DEBUG_OBJECT (rtmpsrc, "interrupt_cb flag=%d", rtmpsrc->stop_flag);
         return rtmpsrc->stop_flag;
    } else {
        return 0;
    }
}

gst_rtmp_src_start() 
{
....
  RTMP_Init (src->rtmp);
  /* Add by sparktend, init rtmp object callback. */
  src->rtmp->interrupt_callback.callback = stop_interrupt_cb;
  src->rtmp->interrupt_callback.opaque = src;
} 

在_unlock()、_create()和_stop()中使用rtmp对象时,用锁保护。

g_mutex_lock(&rtmpsrc->lock);
..
g_mutex_unlock(&rtmpsrc->lock);

librtmp
rtmp.h

  /* Add by sparktend, for no-block callback. */
  typedef struct AVIOInterruptCB {
       int (*callback)(void*);
       void *opaque;
  } AVIOInterruptCB;

  typedef struct RTMP
  {
    ....
     /* Add by sparktend, for no-block callback. */
     AVIOInterruptCB interrupt_callback;
   }RTMP;


rtmp.c
RTMP_GetNextMediaPacket()
{
      if (!bHasMediaPacket)
     {
       RTMPPacket_Free(packet);
       /* Add  by sparktend, do callback. */
       RTMP_Log(RTMP_LOGDEBUG,"bHasMediaPacket = 0");
       if (r->interrupt_callback.callback) {
            RTMP_Log(RTMP_LOGDEBUG,"will do callback");
            if (r->interrupt_callback.callback(r->interrupt_callback.opaque)) {
               break;
            }
       }
     }
}