Question for stream buffering.

HoonHee Lee hoonh83.lee at gmail.com
Tue Apr 8 03:29:40 PDT 2014


I have a question for stream buffering with Q2 element via playbin.
And I want to measure buffered-size(undecoded-size) using current-level-byte
or current-level-time from Q2.


What I was intending is that showing up progressive bar such as youtube.

duration        : ========== (1:00)
playtime        : = (0:10)
buffered size  : ==(0:13)


I have refered below docs for buffering.
=>
http://cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-buffering.txt
Also, I have refered below code for buffering.
=> gst-launch.c (tools) & playback-test.c
(gst-plugins-base\tests\examples\playback)


I have just tested it with below url based on my sample test code with
latest gstreamer version.
=> http://media.w3.org/2010/05/sintel/trailer.mp4

------------------------------------------------------------------------------------------------
my sample test code


/*** block a  from ../../../docs/manual/highlevel-playback.xml ***/
#include <gst/gst.h>

static GMainLoop *loop = NULL;
static GstElement *queue2 = NULL;
static gboolean buffering = FALSE;

static GstPadProbeReturn
_queue2_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata)
{
  GstElement *playbin = udata;
  GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
  GstState state;

  state = GST_STATE (playbin);

  GST_WARNING ("_queue2_buffer_probe : playbin state = %d, queue2 state =
%d", state, GST_STATE (queue2));
  GST_WARNING ("_queue2_buffer_probe : ts: %" GST_TIME_FORMAT, GST_TIME_ARGS
(GST_BUFFER_TIMESTAMP (buffer)));

  return GST_PAD_PROBE_OK;
}

static gboolean
bus_call (GstBus * bus, GstMessage * message, gpointer data)
{
  GstElement *playbin = (GstElement *) data;
  GstPad *src = NULL;
  GstPad *peer = NULL;

  GST_WARNING ("bus_call : message = %s", GST_MESSAGE_TYPE_NAME (message));

  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ASYNC_DONE:
    {
      src = gst_element_get_static_pad (queue2, "src");
      peer = gst_pad_get_peer (src);
      gst_pad_add_probe (peer, GST_PAD_PROBE_TYPE_BUFFER,
_queue2_buffer_probe, playbin, NULL);
      break;
    }
    case GST_MESSAGE_BUFFERING:
    {
      gint percent;
      GstBufferingMode mode;
      gint avg_in, avg_out;
      gint64 buffering_left;

      gst_message_parse_buffering (message, &percent);
      gst_message_parse_buffering_stats (message, &mode, &avg_in, &avg_out,
          &buffering_left);

      GST_WARNING ("@@@@@@@@@@@@@ percent: %d", percent);
      GST_WARNING ("@@@@@@@@@@@@@ mode:%d, rates: in: %d, out: %d", mode,
avg_in, avg_out);
      GST_WARNING ("@@@@@@@@@@@@@ buffering_left %" G_GUINT64_FORMAT,
buffering_left);

      if (percent == 100) {
        buffering = FALSE;
        gst_element_set_state (playbin, GST_STATE_PLAYING);
      } else {
        if (buffering == FALSE) {
          gst_element_set_state (playbin, GST_STATE_PAUSED);
        }
        buffering = TRUE;
      }
      break;
    }
    case GST_MESSAGE_ERROR:
    {
      g_main_loop_quit (loop);
      break;
    }
    case GST_MESSAGE_EOS:
      g_message ("received EOS");
      g_main_loop_quit (loop);
      break;
    default:
      break;
  }

  return TRUE;
}

static void
playbin_element_added_cb (GstElement * playbin, GstElement * element,
gpointer u_data)
{
  GstState state;
  GstElementFactory *factory = NULL;
  const gchar *klass = NULL;
  gchar *elem_name = NULL;

  factory = gst_element_get_factory (element);
  klass = gst_element_factory_get_metadata (factory,
GST_ELEMENT_METADATA_KLASS);
  elem_name = gst_element_get_name (element);
  state = GST_STATE (element);

  GST_WARNING ("added element = %s, state = %d", elem_name, state);

  if (g_strrstr (klass, "Bin"))
    g_signal_connect (element, "element-added", G_CALLBACK
(playbin_element_added_cb), playbin);

  if (g_strrstr (elem_name, "queue2") && queue2 == NULL)
    queue2 = element;

  g_free (elem_name);
}

gint
main (gint argc, gchar * argv[])
{
  GstElement *playbin;
  GstBus *bus;
  gchar *uri;
  GstStateChangeReturn sret;

  gst_init (&argc, &argv);

  if (argc < 2) {
    GST_ERROR ("usage: %s <media file or uri>\n", argv[0]);
    return 1;
  }

  playbin = gst_element_factory_make ("playbin", NULL);
  if (!playbin) {
    GST_ERROR ("playbin plugin missing\n");
    return 1;
  }

  if (gst_uri_is_valid (argv[1]))
    uri = g_strdup (argv[1]);
  else
    uri = gst_filename_to_uri (argv[1], NULL);

  g_object_set (playbin, "uri", uri, NULL);
  g_free (uri);
  loop = g_main_loop_new (NULL, FALSE);

  bus = gst_element_get_bus (playbin);
  if (bus) {
    gst_bus_add_signal_watch (bus);
    g_signal_connect (bus, "message", G_CALLBACK (bus_call), playbin);
  }
  g_object_unref (bus);

  g_signal_connect (playbin, "element-added", G_CALLBACK
(playbin_element_added_cb), loop);

  if (gst_element_set_state (playbin,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
    GST_DEBUG_OBJECT (playbin, "Failed to paused state");
    goto done;
  }

  sret = gst_element_get_state (playbin, NULL, NULL, -1);

  if (sret == GST_STATE_CHANGE_FAILURE) {
    GST_DEBUG_OBJECT (playbin, "Failed to get lpbin state");
    goto done;
  }

  g_main_loop_run (loop);

done:
  gst_element_set_state (playbin, GST_STATE_NULL);
  g_object_unref (playbin);
  g_main_loop_unref (loop);

  return 0;
}

------------------------------------------------------------------------------------------------

When I have received the buffering message from Q2, I have changed state of
pipeline from playing to paused.
After finished state change, a peer pad of srcpad in Q2 have received the
buffer data for a moment through the chain function. It means that although
buffer is flowing to peer pad when paused state in pipeline.
IMHO, we can not guarantee the accurate bufferd-size(undecoded-size) from Q2
in this situation.
Also, I think that speed of buffering can be slowed caused by repeatedly
buffering percentage is to go up and down.

When I reviewed the Q2's code, there is no explicit code for pausing task
about enquene and dequeue task when state is changed from playing to paused.
gst_queue2_loop() function of Q2 kept to run and gst_pad_push
(queue->srcpad, buffer) operated by gst_queue2_locked_dequeue()
continuously.
It means that gst_queue2_loop() depens on internal logic in GstPad with
GstTask??
But, I am lack of insight GstTask.....


Thus, What I am asking is that data of Q2 is flowing to peerpad is an normal
operating or not when paused state in pipeline?
Or my sample test code is wrong??
And Can I get some advise for this??

Please let me know, if you have any information or advise.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Question-for-stream-buffering-tp4666355.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.


More information about the gstreamer-devel mailing list