how to monitor or release filesystem-backed buffers in gstreamer 0.10

Dave Milici davemilici at sbcglobal.net
Tue Jun 11 18:08:32 PDT 2013


I've been modifying qtwebkit gstreamer media player for running on an embedded device, and keep running out of memory (OOM killer) when streaming for more than a minute, or running more than one media player instance.

The device is ARM A9, 256MB phys RAM, ~154MB system mem available.
FW is Linux 3.4.24, with Qt/Embedded 4.8.4, GStreamer 0.10.36 stack.

In tracing the existing media player code, I noticed that there was not thorough cleanup in media player destructor, so tracked some of the bus and message handler objects for removal in destructor. This symmetrical cleanup had little effect on subsequent player instances, though they did work when sufficient memory available. (Patch snippets below.)

It seems like the problem is related to buffering and filesystem support. Tried simplifying the pipeline to avoid queue and tee elements, and also disabled auto-fill buffering timer. Masking off GST_PLAY_FLAG_DOWNLOAD option results in poor playback, and still does not avoid OOM situations.

Is there an API call to release or monitor filesystem-backed buffers?

>>>>>

@@ -803,6 +904,7 @@
         return;
     }
 
+#if 0 // FIXME
     // This is on-disk buffering, that allows us to download much more
     // than needed for right now.
     if (!m_startedBuffering) {
@@ -815,6 +917,7 @@
 
         m_fillTimer.startRepeating(0.2);
     }
+#endif
 }
 
 void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*)
@@ -1013,12 +1116,26 @@


@@ -1649,25 +1796,32 @@
 void MediaPlayerPrivateGStreamer::createGSTPlayBin()
 {
     ASSERT(!m_playBin);
+
     m_playBin = gst_element_factory_make("playbin2", "play");
 
     m_gstGWorld = GStreamerGWorld::createGWorld(m_playBin);
 
-    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
-    gst_bus_add_signal_watch(bus);
-    g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
-    gst_object_unref(bus);
+    m_bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
+    gst_bus_add_signal_watch(m_bus);
+    m_handlers[m_index++] =
+    g_signal_connect(m_bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
 
     g_object_set(m_playBin, "mute", m_player->muted(), NULL);
 
+    m_handlers[m_index++] =
     g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
+    m_handlers[m_index++] =
     g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
+    m_handlers[m_index++] =
     g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
+    m_handlers[m_index++] =
     g_signal_connect(m_playBin, "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
+    m_handlers[m_index++] =
     g_signal_connect(m_playBin, "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
 
     m_webkitVideoSink = webkit_video_sink_new();
 
+    m_handlers[m_index++] =
     g_signal_connect(m_webkitVideoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
 
     m_videoSinkBin = gst_bin_new("sink");
@@ -1685,6 +1839,7 @@
 
     gst_bin_add_many(GST_BIN(m_videoSinkBin), videoTee, queue, identity, NULL);
 
+#if 0 // no tee, no queue
     // Link a new src pad from tee to queue1.
     GstPad* srcPad = gst_element_get_request_pad(videoTee, "src%d");
     GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
@@ -1723,6 +1878,7 @@
     }
 
     ASSERT(actualVideoSink);
+    if (!m_videoRate) {
 #if GST_CHECK_VERSION(0, 10, 30)
         // Faster elements linking, if possible.
         gst_element_link_pads_full(queue, "src", identity, "sink", GST_PAD_LINK_CHECK_NOTHING);
@@ -1730,9 +1886,23 @@
 #else
         gst_element_link_many(queue, identity, actualVideoSink, NULL);
 #endif
+    }
+#endif
+
+    m_videoRate = gst_element_factory_make("videorate", "videoRate");
+    GST_LOG("%s: videoRate=%p\n", __FUNCTION__, m_videoRate);
+    if (m_videoRate) {
+        g_object_set(m_videoRate, "silent", TRUE , NULL);
+        g_object_set(m_videoRate, "drop-only", TRUE , NULL);
+        g_object_set(m_videoRate, "max-rate", 15 , NULL);
+        g_object_set(m_videoRate, "average-period", GST_TIME_AS_MSECONDS(66) , NULL);
+        gst_bin_add(GST_BIN(m_videoSinkBin), m_videoRate);
+        gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink);
+        gst_element_link_many(identity, m_videoRate, m_webkitVideoSink, NULL);
+    }
 
     // Add a ghostpad to the bin so it can proxy to tee.
-    GstPad* pad = gst_element_get_static_pad(videoTee, "sink");
+    GstPad* pad = gst_element_get_static_pad(identity, "sink");
     gst_element_add_pad(m_videoSinkBin, gst_ghost_pad_new("sink", pad));
     gst_object_unref(GST_OBJECT(pad));
 
@@ -1742,10 +1912,10 @@
 
     pad = gst_element_get_static_pad(m_webkitVideoSink, "sink");
     if (pad) {
+        m_handlers[m_index++] =
         g_signal_connect(pad, "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
         gst_object_unref(GST_OBJECT(pad));
     }
-
 }
 
 }



More information about the gstreamer-devel mailing list