Skip to content

Instantly share code, notes, and snippets.

@dplanella
Last active September 13, 2017 08:19
Show Gist options
  • Save dplanella/5563018 to your computer and use it in GitHub Desktop.
Save dplanella/5563018 to your computer and use it in GitHub Desktop.
A snippet to create thumbnails from video files, using GStreamer and Python. Original author: [daf](http://stackoverflow.com/users/32082/daf) via http://stackoverflow.com/a/16478342/1049318
# Video thumbnailer, non-PyGI version, working as expected
import os
import sys
import gst
def get_frame(path, offset=5, caps=gst.Caps('image/png')):
pipeline = gst.parse_launch('playbin2')
pipeline.props.uri = 'file://' + os.path.abspath(path)
pipeline.props.audio_sink = gst.element_factory_make('fakesink')
pipeline.props.video_sink = gst.element_factory_make('fakesink')
pipeline.set_state(gst.STATE_PAUSED)
# Wait for state change to finish.
pipeline.get_state()
assert pipeline.seek_simple(
gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, offset * gst.SECOND)
# Wait for seek to finish.
pipeline.get_state()
buffer = pipeline.emit('convert-frame', caps)
pipeline.set_state(gst.STATE_NULL)
return buffer
def main():
buf = get_frame(sys.argv[1])
with file('frame.png', 'w') as fh:
fh.write(bytes(buf))
if __name__ == '__main__':
main()
# Video thumbnailer, PyGI version, not working (creates unreadable thumbnails)
import os
import sys
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
Gst.init(None)
def get_frame(path, offset=5, caps=Gst.Caps.from_string('image/png')):
pipeline = Gst.parse_launch('playbin')
pipeline.props.uri = 'file://' + os.path.abspath(path)
pipeline.props.audio_sink = Gst.ElementFactory.make('fakesink', 'fakeaudio')
pipeline.props.video_sink = Gst.ElementFactory.make('fakesink', 'fakevideo')
pipeline.set_state(Gst.State.PAUSED)
# Wait for state change to finish.
pipeline.get_state(Gst.CLOCK_TIME_NONE)
assert pipeline.seek_simple(
Gst.Format.TIME, Gst.SeekFlags.FLUSH, offset * Gst.SECOND)
# Wait for seek to finish.
pipeline.get_state(Gst.CLOCK_TIME_NONE)
buffer = pipeline.emit('convert-sample', caps).get_buffer()
pipeline.set_state(Gst.State.NULL)
return buffer
def main():
buf = get_frame(sys.argv[1])
with file('frame.png', 'w') as fh:
# This (i.e. getting the data from the buffer) does not work. See https://bugzilla.gnome.org/show_bug.cgi?id=678663
fh.write(bytes(buf))
if __name__ == '__main__':
main()
@malbork
Copy link

malbork commented May 12, 2013

Do you actually want a 1 second timeout on the state change and seek? If you do, you probably want to check the return value of get_state(). Otherwise, you probably want Gst.CLOCK_TIME_NONE.

@dplanella
Copy link
Author

You're right, I don't need a 1 second timeout, I was just adding an arbitrary value to get the rest of the snippet working. Thanks a lot for the Gst.CLOCK_TIME_NONE tip, I've now added that.

@mateosalta
Copy link

Do you know if any progress was made on this, a friend and I are working on a project, https://github.com/mateosalta/CamCastic-Desktop , and are planning to grab an image to measure the proper proportions/resolution of the camera, then use that to provide a "black bar" free window. This snippet seems like a step in the right direction. (using pygi)

@aking1012
Copy link

Nevermind on the getting resolution that way... I found a better way to do it. Alternately, I'm still playing with the thumbnailer snippet if you want something that works.

@SadaleNet
Copy link

The code above isn't working in my environment. I solved it by doing the following:
Replace:

buffer = pipeline.emit('convert-sample', caps).get_buffer()

with

sample = pipeline.emit('convert-sample', caps)
buffer = sample.get_buffer()

Also replace: with file('frame.png', 'w') as fh: with with file('frame.png', 'wb') as fh:

@green-anger
Copy link

As stated bytes(buf) doesn't work, so you will have to do it another way:

with file('frame.png', 'w') as fh:
    fh.write(buf.extract_dup(0, buf.get_size()))

Also as wongcc966422 said, you will need 'wb' file mode on Windows. It works with 'w' on Linux for me.

@macnibblet
Copy link

This seems to have broken in a recent version of gstreamer?

@zaplo00
Copy link

zaplo00 commented Sep 13, 2017

I can't get it work with mp4 file which is h264 (High profile) / AAC. But this works with webm file.
convert-sample returns None in mp4's case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment