Last active
September 13, 2017 08:19
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() |
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:
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.
This seems to have broken in a recent version of gstreamer?
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
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.