Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • gstreamer gstreamer
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 936
    • Issues 936
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 440
    • Merge requests 440
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Container Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • GStreamerGStreamer
  • gstreamergstreamer
  • Issues
  • #432
Closed
Open
Issue created Aug 23, 2019 by Florian Zwoch@fzwochContributor

gstbaseparse never resets drain flag

Running GStreamer 1.16.0. I have an issue with some streams in combination with seeking after EOS. Most basic example use case is rewind to start of stream after EOS.

Example app with pipeline below:

#include <gst/gst.h>

int main()
{
    gst_init(NULL, NULL);

    GstElement *pipe = gst_parse_launch("filesrc location=file.265 ! h265parse ! identity dump=false ! decodebin ! autovideoconvert ! xvimagesink max-lateness=-1 qos=false", NULL);
    GstBus *bus = gst_element_get_bus(pipe);

    gst_element_set_state(pipe, GST_STATE_PLAYING);
    gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);

    g_print("\n");
    g_print("loop\n");
    g_print("\n");

    gst_element_seek_simple(pipe, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0);

    gst_element_set_state(pipe, GST_STATE_PLAYING);
    gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);

    gst_element_set_state(pipe, GST_STATE_NULL);

    gst_object_unref(bus);
    gst_object_unref(pipe);

    return 0;
}

The first buffer after the seek is truncated to a max buffer size of 0x10000. If the NAL does not fit in this buffer it gets handed to decoder incomplete causing visible distortion.

A little bit of debugging got me to gstbaseparse.c:3456 where parse->priv->drain is set:

    /* if we got a short read, inform subclass we are draining leftover
     * and no more is to be expected */
    if (gst_buffer_get_size (buffer) < min_size) {
      GST_LOG_OBJECT (parse, "... but did not get that; marked draining");
      parse->priv->drain = TRUE;
    }

A little further down I think it exits the function at the block at gstbaseparse.c:3497:

    /* something flushed means something happened,
     * and we should bail out of this loop so as not to occupy
     * the task thread indefinitely */
    if (flushed) {
      GST_LOG_OBJECT (parse, "frame finished, breaking loop");
      break;
    }

basically leaving parse->priv->drain as it is set.

I seems that all data is consumed in this data path, never running through gstbaseparse.c:3517:

 parse->priv->drain = FALSE;

Where parse->priv->drain would be reset. So after seek/flush this flag is still present causing the subclass (h265parse at least) to trip over its logic since it thinks it is draining.

I haven't checked if, when or how it recovers - but the rest of the streams basically decodes fine once the distortions have recovered.

I simply tried adding parse->priv->drain = FALSE; after the subclass is called in gstbaseparse.c:3478:

    ret = gst_base_parse_handle_buffer (parse, buffer, &skip, &flushed);
    if (ret != GST_FLOW_OK)
      break;

and it fixed the obvious issue I was having. That clearly isn't the correct fix as parse->priv->drain's value is checked later in that function..

Should this flag be reset in some specific code paths where it is missing - or should it get reset on a flush? It certainly feels like it should not be set on a new segment after it was previously draining.

Assignee
Assign to
Time tracking