简体   繁体   中英

Dynamic GStreamer pipeline not seekable

I have a simple gstreamer pipeline that plays an mp4 file and it supports seeking. I've made another version of this pipeline, this one with the demux dynamically created using a typefind element. With this version of the pipeline, seeking doesn't seem to work. Here are the most minimal versions of these two in Python:

Here are the pipeline diagrams:

The working/seekable version: 工作/可搜索管道

The dynamic/non-seekable version: 动态/不可搜索管道

Notice that actual playback works in both pipelines just fine. Only seeking does not work in the dynamic version. The only major difference between the two as far as I can see is that in the dynamic pipeline, the pads connecting typefind to the demux element are in pull mode while in the other they are in push mode, but I have no idea if this is relevant and if it is how to fix it.

Another difference is that the newly created demux in the dynamic version is in the playing state while the other elements are in paused, at the seeking time. I've tried setting the new demux to paused state, but this does not seem to change anything.

The most minimal version of the code I could come up with follows:

Working version:

import gi
gi.require_version('Gst', '1.0')
gi.require_version('GLib', '2.0')
from gi.repository import Gst, GLib


def demux_pad_added(element, pad, pipeline):
    dec = pipeline.get_by_name('dec0')
    result = pad.link(dec.get_static_pad('sink'))
    if result != Gst.PadLinkReturn.OK:
        print('Could not link demux to dec.')
        exit(1)

    print('Linked demux to dec.')

    Gst.debug_bin_to_dot_file(pipeline, Gst.DebugGraphDetails.ALL, 'working')

    ret = pipeline.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 1800 * Gst.SECOND)
    print('seek result:', ret)


def main():
    Gst.init(None)
    loop = GLib.MainLoop()

    pipeline = Gst.Pipeline()
    src = Gst.ElementFactory.make('filesrc', 'src0')
    typefind = Gst.ElementFactory.make('typefind', 'typefind0')
    demux = Gst.ElementFactory.make('qtdemux', 'demux0')
    dec = Gst.ElementFactory.make('libde265dec', 'dec0')
    sink = Gst.ElementFactory.make('appsink', 'sink0')

    src.set_property('location', 'foo.mp4')
    demux.connect('pad-added', demux_pad_added, pipeline)

    elements = [src, typefind, demux, dec, sink]

    for e in elements:
        pipeline.add(e)

    for i in range(0, len(elements) - 1):
        e1, e2 = elements[i], elements[i+1]
        if e1 == demux:
            continue
        if not e1.link(e2):
            print('Could not link {} to {}.'.format(e1.name, e2.name))
            exit(1)

    pipeline.set_state(Gst.State.PLAYING)
    loop.run()


if __name__ == '__main__':
    main()

The version where seek does not work:

import gi
gi.require_version('Gst', '1.0')
gi.require_version('GLib', '2.0')
from gi.repository import Gst, GLib


def demux_pad_added(element, pad, pipeline):
    dec = pipeline.get_by_name('dec0')
    result = pad.link(dec.get_static_pad('sink'))
    if result != Gst.PadLinkReturn.OK:
        print(pad.name, dec.get_static_pad('sink').name)
        print('Could not link demux to dec.')
        exit(1)

    print('Linked demux to dec.')

    Gst.debug_bin_to_dot_file(pipeline, Gst.DebugGraphDetails.ALL, 'not-working')

    ret = pipeline.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 1800 * Gst.SECOND)
    print('seek result:', ret)


def typefind_have_type(typefind, probability, caps, pipeline):
    videofmt = caps.to_string()
    if ',' in videofmt:
        videofmt = videofmt.split(',')[0]

    demux_name = {
        'video/quicktime': 'qtdemux',
        'video/x-matroska': 'matroskademux',
        'video/x-msvideo': 'avidemux',
    }.get(videofmt, None)

    if not demux_name:
        print('Unknown input file format: {}'.format(videofmt))
        exit(1)

    demux = Gst.ElementFactory.make(demux_name, 'demux0')
    pipeline.add(demux)
    demux.connect('pad-added', demux_pad_added, pipeline)
    demux.set_state(Gst.State.PLAYING)

    if not typefind.link(demux):
        print('Could not link typefind to demux.')
        exit(1)


def main():
    Gst.init(None)
    loop = GLib.MainLoop()

    pipeline = Gst.Pipeline()
    src = Gst.ElementFactory.make('filesrc', 'src0')
    typefind = Gst.ElementFactory.make('typefind', 'typefind0')
    demux = object() # dummy
    dec = Gst.ElementFactory.make('libde265dec', 'dec0')
    sink = Gst.ElementFactory.make('appsink', 'sink0')

    src.set_property('location', 'foo.mp4')
    typefind.connect('have-type', typefind_have_type, pipeline)

    elements = [src, typefind, demux, dec, sink]

    for e in elements:
        if e != demux:
            pipeline.add(e)

    for i in range(0, len(elements) - 1):
        e1, e2 = elements[i], elements[i+1]
        if e1 == demux or e2 == demux:
            continue
        if not e1.link(e2):
            print('Could not link {} to {}.'.format(e1.name, e2.name))
            exit(1)

    pipeline.set_state(Gst.State.PLAYING)
    loop.run()


if __name__ == '__main__':
    main()

Any help would be greatly appreciated.

I managed to find the fix to this myself. I simply needed to move the demux.set_state(...) call to the end of the typefind callback, after linking typefind to demux. The new typefind callback looks like this now:

def typefind_have_type(typefind, probability, caps, pipeline):
    videofmt = caps.to_string()
    if ',' in videofmt:
        videofmt = videofmt.split(',')[0]

    demux_name = {
        'video/quicktime': 'qtdemux',
        'video/x-matroska': 'matroskademux',
        'video/x-msvideo': 'avidemux',
    }.get(videofmt, None)

    if not demux_name:
        print('Unknown input file format: {}'.format(videofmt))
        exit(1)

    demux = Gst.ElementFactory.make(demux_name, 'demux0')
    pipeline.add(demux)
    demux.connect('pad-added', demux_pad_added, pipeline)
    #demux.set_state(Gst.State.PLAYING) # moved from here to further down

    if not typefind.link(demux):
        print('Could not link typefind to demux.')
        exit(1)

    demux.set_state(Gst.State.PLAYING) # <--- new location

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM