Gstqueue2 ring-buffer-max-size buggy behavior after loop

jacek_skiba jacekskiba.88 at gmail.com
Fri Feb 7 18:20:26 UTC 2020


Hello, 

When I'm using gstqueue2 with enabled ring-buffer-max-size property, then
video looping (seek to PTS 0) is not working. Logically the seek operation
works OK (flash start, flash stop, new segment), but I'm getting Malformed
GstBuffers: fatal decoding error is seen on video filter and video decoder.

Problem is visible when video size (e.g 390MB) is grather then ring-buffer
size (e.g 128 MB). 
Problem is not visible when:
- video size is similar to ring buffer size
- without ring-buffer option
- when media chunks are stored on flash.

When chunks are stored in RAM (NOK) or on flash (OK), then gstqueue2 is
working in PULL mode. In both cases QTDemux is requesting the same chunks
(with the same length) after seek to 0 PTS operation.

Problem was reproduced on x86 (GST v1.14) and ARM (GST v1.10) embedded
platform.

Gstreamer pipeline graph attached: 
<http://gstreamer-devel.966125.n4.nabble.com/file/t379272/pipeline.png> 

I'm attaching x86 OK/NOK logs: seek operation starts from pattern: "EOS
received; seeking to 0"
video_loop_ok.log
<http://gstreamer-devel.966125.n4.nabble.com/file/t379272/video_loop_ok.log>  
with_ring_buffer_nok.log
<http://gstreamer-devel.966125.n4.nabble.com/file/t379272/with_ring_buffer_nok.log>  

It's a bug or I'm using gstqueue2 ring-buffer in a inappropriate way?


Simple reproduction code:
// g++ queue2.cc `pkg-config --cflags --libs gstreamer-1.0`
// GST_DEBUG=4,queue2:5 GST_DEBUG_FILE=output.txt GST_DEBUG_NO_COLOR=1
./a.out

// GST_DEBUG_DUMP_DOT_DIR=. ./a.out
// dot -Tpng pipeline.dot > pipeline.png
// feh pipeline.png

#include <stdio.h>
#include <gst/gst.h>

typedef struct _CustomData
{
    GstElement *playbin;          /* Our one and only element */
    GMainLoop *main_loop;         /* GLib's Main Loop */
} CustomData;

/* playbin flags */
typedef enum
{
    GST_PLAY_FLAG_VIDEO = (1 << 0),       /* We want video output */
    GST_PLAY_FLAG_AUDIO = (1 << 1),       /* We want audio output */
} GstPlayFlags;

static gboolean handle_message (GstBus* bus, GstMessage* msg, CustomData*
data);
void uri_decode_bin_added(GstBin* bin, GstElement* element, GstElement*
playbin);
void queue2_added(GstBin* bin, GstElement* element, GstElement* playbin);
static gboolean generate_graph (GstElement *pipeline);
static gboolean print_position (GstElement* pipeline);

int main (int argc, char *argv[])
{
    CustomData data;
    GstBus* bus;
    GstStateChangeReturn ret;
    gint flags;

    gst_init (&argc, &argv);

    // by default we use playbin2
    data.playbin = gst_element_factory_make ("playbin", "playbin");

    if (!data.playbin) {
    GST_INFO ("Not all elements could be created.\n");
    return -1;
    }

    g_object_set (data.playbin, "uri",
"http://horizonapps.dmdsdp.com/MoodLounge/dance.mp4", NULL);

    /* set flags to show audio and video */
    g_object_get (data.playbin, "flags", &flags, NULL);
    flags |= GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO;
    g_object_set (data.playbin, "flags", flags, NULL);

    GstElement* sink = gst_element_factory_make("xvimagesink", "videosink");
    g_object_set(data.playbin, "video-sink", sink, nullptr);

    bus = gst_element_get_bus (data.playbin);
    gst_bus_add_watch (bus, (GstBusFunc) handle_message, &data);

    g_signal_connect(data.playbin, "element-added",
G_CALLBACK(uri_decode_bin_added), data.playbin);

    ret = gst_element_set_state (data.playbin, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
    GST_INFO ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (data.playbin);
    return -1;
    }

    g_timeout_add(1000, (GSourceFunc) print_position, data.playbin);
    g_timeout_add(1000, (GSourceFunc) generate_graph, data.playbin);

    data.main_loop = g_main_loop_new (NULL, FALSE);
    g_main_loop_run (data.main_loop);

    g_main_loop_unref (data.main_loop);
    gst_object_unref (bus);
    gst_element_set_state (data.playbin, GST_STATE_NULL);
    gst_object_unref (data.playbin);
    return 0;
}

static gboolean
handle_message (GstBus * bus, GstMessage * msg, CustomData * data)
{
  GError *err;
  gchar *debug_info;

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_ERROR:
      gst_message_parse_error (msg, &err, &debug_info);
      GST_INFO ("Error received from element %s: %s\n",
          GST_OBJECT_NAME (msg->src), err->message);
      GST_INFO ("Debugging information: %s\n",
          debug_info ? debug_info : "none");
      g_clear_error (&err);
      g_free (debug_info);
      g_main_loop_quit (data->main_loop);
      break;
    case GST_MESSAGE_EOS:
      GST_INFO("EOS received; seeking to 0\n");
      if (!gst_element_seek(data->playbin,
                  1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
                  GST_SEEK_TYPE_SET,  2000000000, //2 seconds (in
nanoseconds)
                  GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
          GST_INFO("Seek failed!\n");
      }
      break;
    default:
      break;
  }

  return TRUE;
}

void uri_decode_bin_added(GstBin* bin, GstElement* element, GstElement*
playbin)
{
    if
(!g_strcmp0(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(G_OBJECT(element))),
"GstURIDecodeBin")) {
        GST_INFO("%s found\n",
G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(G_OBJECT(element))));
        g_signal_connect(element, "element-added", G_CALLBACK(queue2_added),
nullptr);
    }
}

void queue2_added(GstBin* bin, GstElement* element, GstElement* playbin)
{
    if
(!g_strcmp0(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(G_OBJECT(element))),
"GstQueue2")) {
        GST_INFO("plugin found: %s\n",
G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(G_OBJECT(element))));
        g_object_set(element, "ring-buffer-max-size", 128 * 1024 * 1024,
nullptr);
        // g_object_set(element, "max-size-bytes", (128 * 1024 * 1024) / 2,
nullptr);
    }
}

static gboolean print_position (GstElement *pipeline)
{
    static bool generate_once = false;
    if (!generate_once) {
        generate_once = true;
        GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline),
GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
    }

    gint64 pos, len;
    if (gst_element_query_position(pipeline, GST_FORMAT_TIME, &pos)
        && gst_element_query_duration(pipeline, GST_FORMAT_TIME, &len))
    {
        GST_INFO("Time: %ld, %ld\n", pos, len);
        GST_INFO("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
GST_TIME_ARGS(pos), GST_TIME_ARGS(len));
    }

    return TRUE;
}

static gboolean generate_graph (GstElement *pipeline)
{
    GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL,
"pipeline");
    return FALSE;
}




--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/


More information about the gstreamer-devel mailing list