Frame Stepping

Brian Panneton brian.panneton at gmail.com
Thu Aug 11 21:10:15 UTC 2016


All,

I've been trying to step through frame by frame with one pipeline and pass
through to another. Basically I want to look at every h264 frame and then
pipe it off into a filesink. I have made an example of what I thought would
work below.

It should take an MKV file, step thought the h264 frames and pipe them to a
MP4 file without missing any frames (It is important that I get the actual
frames here). So the first pipeline is in PAUSE mode and the second
pipeline is in PLAYING (I don't think writing to a file can be done in
paused mode?). I understand I could do this by removing the appsink->appsrc
but that is not what I am looking for and wont work in my application.

My big problem at the moment is that I can't seem to determine when the
end-of-stream occurs since I am in paused mode. My best attempt was to use
pos > dur, but I have found this isn't always true. In the current case I
either end early or never end (when I remove the pos == last section). If
there is a better way to do this I would appreciate any ideas. Sample code
is below! Sample MKV file: http://jell.yfish.us/media/
jellyfish-25-mbps-hd-h264.mkv

<code>
from gi.repository import Gst, GObject
import sys
import os
import glob

def test_file(inc):
    filename = "jellyfish-25-mbps-hd-h264.mkv"
    elements = {}

    def demuxer_callback(demuxer, pad):
        if pad.get_property("template").name_template == "video_%u":
            pad.link(elements['h264parse'].get_static_pad("sink"))

    #GObject.threads_init()
    Gst.init()
    Gst.debug_set_active(True)
    Gst.debug_set_default_threshold(1)
    pipeline_front = Gst.Pipeline()
    pipeline_end = Gst.Pipeline()

    elements['filesrc'] = Gst.ElementFactory.make('filesrc',
str(inc)+'_filesrc')
    elements['filesrc'].set_property('location', filename)
    elements['matroskademux'] = Gst.ElementFactory.make('matroskademux',
str(inc)+'_matroskademux')
    elements['matroskademux'].connect('pad-added', demuxer_callback)
    elements['h264parse'] = Gst.ElementFactory.make('h264parse',
str(inc)+'_h264parse')
    elements['raw1queue'] = Gst.ElementFactory.make('queue',
str(inc)+'_raw1queue')
    elements['innersink'] = Gst.ElementFactory.make('appsink',
str(inc)+'_appsink')

    elements['mp4appsrc'] = Gst.ElementFactory.make('appsrc')
    elements['mp4h264parse'] = Gst.ElementFactory.make('h264parse')
    elements['mp4queue'] = Gst.ElementFactory.make('queue')
    elements['mp4mux'] = Gst.ElementFactory.make('mp4mux')
    elements['mp4mqueue'] = Gst.ElementFactory.make('queue')
    elements['mp4filesink'] = Gst.ElementFactory.make('filesink')
    elements['mp4filesink'].set_property('location', "{}.mp4".format(inc))

    pipeline_front.add(elements['filesrc'])
    pipeline_front.add(elements['matroskademux'])
    pipeline_front.add(elements['h264parse'])
    pipeline_front.add(elements['raw1queue'])
    pipeline_front.add(elements['innersink'])

    pipeline_end.add(elements['mp4appsrc'])
    pipeline_end.add(elements['mp4h264parse'])
    pipeline_end.add(elements['mp4queue'])
    pipeline_end.add(elements['mp4mux'])
    pipeline_end.add(elements['mp4mqueue'])
    pipeline_end.add(elements['mp4filesink'])

    elements['filesrc'].link(elements['matroskademux'])
    elements['matroskademux'].link(elements['h264parse'])
    elements['h264parse'].link(elements['raw1queue'])
    elements['raw1queue'].link(elements['innersink'])

    elements['mp4appsrc'].link(elements['mp4queue'])
    elements['mp4queue'].link(elements['mp4h264parse'])
    elements['mp4h264parse'].link(elements['mp4mux'])
    elements['mp4mux'].link(elements['mp4mqueue'])
    elements['mp4mqueue'].link(elements['mp4filesink'])

    pipeline_front.set_state(Gst.State.READY)
    pipeline_front.set_state(Gst.State.PAUSED)

    pipeline_end.set_state(Gst.State.READY)
    pipeline_end.set_state(Gst.State.PAUSED)
    pipeline_end.set_state(Gst.State.PLAYING)
    print 'Front Setup Status:', pipeline_front.get_state(Gst.
CLOCK_TIME_NONE)[0]
    print 'Start', inc
    completed = False
    last = None
    while True:
        if not completed:
            pipeline_front.get_state(Gst.CLOCK_TIME_NONE)[0]
            elements['innersink'].send_event(Gst.Event.new_step(Gst.Format.BUFFERS,
1, 1, True, False))
            inner_sample = elements['innersink'].emit('pull-preroll')
            inner_buffer = inner_sample.get_buffer()
            elements['mp4appsrc'].set_property('caps',
inner_sample.get_caps())
            elements['mp4appsrc'].emit('push-buffer', inner_buffer)

        # Check position for completion
        # Can't figure out how to tell there are no more frames
        pos = elements['innersink'].query_position(Gst.Format.TIME)[1]
        dur = elements['innersink'].query_duration(Gst.Format.TIME)[1]
        print 'Loc:', pos, dur

        if pos > dur:
            completed = True
        if pos == last:
            completed = True

        bus = pipeline_front.get_bus()
        while True:
            message = bus.pop_filtered(Gst.MessageType.ANY)
            if not message:
                break
            elif message.type in [Gst.MessageType.EOS]:
                completed = True
                break

        # Close stream if completed
        if completed:
            elements['mp4appsrc'].emit('end-of-stream')
            break
        last = pos

    pipeline_front.set_state(Gst.State.NULL)
    pipeline_end.set_state(Gst.State.NULL)
    print 'End', inc, pos, dur

test_file(0)
</code>

Thanks,
Brian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20160811/07fc4dc6/attachment-0001.html>


More information about the gstreamer-devel mailing list