122 lines
3.5 KiB
Python
122 lines
3.5 KiB
Python
#!/usr/bin/env python
|
|
# -*- Mode: Python; -*-
|
|
# -*- coding: utf-8 -*-
|
|
# vi:si:et:sw=2:sts=2:ts=2
|
|
|
|
import gobject
|
|
gobject.threads_init()
|
|
|
|
import pygst
|
|
pygst.require('0.10')
|
|
import gst
|
|
import Image
|
|
import sys, os, shutil, time
|
|
from glob import glob
|
|
import math
|
|
|
|
|
|
bar_part_time = 60 * 10
|
|
bar_height = 16
|
|
|
|
class GstTimeline:
|
|
def __init__(self, timeline_png):
|
|
self.timeline_png = timeline_png
|
|
self.bar = None
|
|
self.frames = 0
|
|
self.length = 0
|
|
self.number_of_frames = 0
|
|
|
|
def addVideo(self, video_file):
|
|
s = ''' filesrc name=input
|
|
! decodebin name=dbin
|
|
! queue name =q
|
|
! ffmpegcolorspace ! video/x-raw-rgb
|
|
! fakesink name=output signal-handoffs=true
|
|
'''
|
|
self.pipeline = gst.parse_launch(s)
|
|
self.input = self.pipeline.get_by_name('input')
|
|
self.fakesink = self.pipeline.get_by_name('output')
|
|
self.dbin = self.pipeline.get_by_name('dbin')
|
|
self.bus = self.pipeline.get_bus()
|
|
self.input.set_property("location", video_file)
|
|
|
|
self.pipeline.set_state(gst.STATE_PAUSED)
|
|
self.pipeline.get_state()
|
|
|
|
#length
|
|
queue = self.pipeline.get_by_name('q')
|
|
pads = queue.sink_pads()
|
|
q = gst.query_new_duration(gst.FORMAT_TIME)
|
|
for pad in pads:
|
|
if pad.get_peer() and pad.get_peer().query(q):
|
|
format, self.length = q.parse_duration()
|
|
|
|
seconds = int(math.ceil(float(self.length) / gst.SECOND))
|
|
print "seconds", seconds
|
|
self.timelineImage = Image.new("RGB", (seconds, bar_height))
|
|
self.timelineImagePos = 0
|
|
|
|
#extract frames
|
|
ho = self.fakesink.connect ("handoff", self.snapshot_png_handoff_cb)
|
|
self.pipeline.set_state(gst.STATE_PLAYING)
|
|
self.pipeline.get_state()
|
|
while 1:
|
|
msg = self.bus.poll(gst.MESSAGE_EOS | gst.MESSAGE_ERROR, gst.SECOND)
|
|
if msg:
|
|
break
|
|
self.fakesink.disconnect(ho)
|
|
self.pipeline.set_state(gst.STATE_NULL)
|
|
|
|
def cropAndSave(self):
|
|
if self.frames:
|
|
mini_width = int(self.frames / self.fps)
|
|
mini_width = min(mini_width, bar_part_time)
|
|
#crop if segment is shorter
|
|
c = self.bar.crop((0, 0, self.frames,bar_height))
|
|
#resize to 1 pixel per second
|
|
mini = c.resize((mini_width,bar_height), Image.ANTIALIAS)
|
|
#add to timeline png
|
|
self.timelineImage.paste(mini, (self.timelineImagePos, 0))
|
|
self.timelineImagePos += mini_width
|
|
self.frames = 0
|
|
|
|
def close(self):
|
|
self.cropAndSave()
|
|
self.timelineImage.save(self.timeline_png)
|
|
|
|
def snapshot_png_handoff_cb(self, sink, gst_buffer, pad):
|
|
caps = sink.sink_pads().next().get_negotiated_caps()
|
|
for s in caps:
|
|
input_d = (s['width'], s['height'])
|
|
framerate = s['framerate']
|
|
if not self.bar:
|
|
self.fps = float(framerate.num) / framerate.denom
|
|
self.width_part = int(self.fps * bar_part_time)
|
|
self.bar = Image.new("RGB", (self.width_part + 1 ,bar_height))
|
|
|
|
img = Image.fromstring('RGB',input_d, gst_buffer)
|
|
height = 16
|
|
img = img.resize((1, height), Image.ANTIALIAS)
|
|
self.frames += 1
|
|
for i in range(height):
|
|
self.bar.putpixel((self.frames, i), img.getpixel((0,i)))
|
|
if self.frames >= self.width_part and self.frames > 30:
|
|
self.cropAndSave()
|
|
|
|
def usage():
|
|
print ""
|
|
print "usage: %s output_base_path video_file" % sys.argv[0]
|
|
print ""
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 2:
|
|
usage()
|
|
if not os.path.exists(sys.argv[1]):
|
|
print "target does not exist"
|
|
sys.exit(1)
|
|
|
|
g = GstTimeline(sys.argv[1])
|
|
g.addVideo(sys.argv[2])
|
|
g.close()
|