oxtimeline/oxgst/video.py

144 lines
4.2 KiB
Python
Raw Normal View History

2009-01-18 08:39:14 +00:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
# GPL 2008
import gobject
gobject.threads_init()
import pygst
pygst.require("0.10")
import gst
import Image
import time
from singledecodebin import SingleDecodeBin
from imagesink import ImageSink
class Video(gst.Pipeline):
def __init__(self, uri):
gst.Pipeline.__init__(self)
self.duration = -1
# queue of timestamps
self.queue = []
# queue callbacks
self.callback = {}
# extracted frames
2009-01-18 23:43:30 +00:00
self._frames = {}
2009-01-18 08:39:14 +00:00
# true only if we are prerolled
self._ready = False
uri = 'file://' + uri
self.log("uri : %s" % uri)
self.uri = uri
self.sbin = SingleDecodeBin(caps=gst.Caps("video/x-raw-rgb;video/x-raw-yuv"),
uri=self.uri)
self.csp = gst.element_factory_make("ffmpegcolorspace")
self.sink = ImageSink()
self.sink.connect('frame', self._frameCb)
self.add(self.sbin, self.csp, self.sink)
self.csp.link(self.sink)
self.sbin.connect('pad-added', self._sbinPadAddedCb)
self.set_state(gst.STATE_PAUSED)
2009-06-21 19:42:10 +00:00
2009-01-18 08:39:14 +00:00
def _sbinPadAddedCb(self, unused_sbin, pad):
self.log("pad : %s" % pad)
2009-06-21 19:42:10 +00:00
pad.set_blocked_async (True, self._pad_blocked_cb)
def _pad_blocked_cb(self, pad, blocked):
if blocked:
#duration
if self.duration < 0:
q = gst.query_new_duration(gst.FORMAT_TIME)
if pad.query(q):
format, self.duration = q.parse_duration()
pad.link(self.csp.get_pad("sink"))
pad.set_blocked_async (False, self._pad_blocked_cb)
2009-01-18 08:39:14 +00:00
def _frameCb(self, unused_thsink, frame, timestamp):
self.log("image:%s, timestamp:%s" % (frame, gst.TIME_ARGS(timestamp)))
if not self._ready:
# we know we're prerolled when we get the initial thumbnail
self._ready = True
elif timestamp in self.callback and self.callback[timestamp]:
self.callback[timestamp](frame, timestamp)
del self.callback[timestamp]
if timestamp in self.queue:
self.queue.remove(timestamp)
if self.queue:
# still some more thumbnails to process
gobject.idle_add(self._getFrame, self.queue.pop(0))
def getFrame(self, timestamp, callback):
"""
Queue a frame request for the given timestamp,
callback is called once frame is extracted.
returns False if timestamp > duration
"""
self.log("timestamp %s" % gst.TIME_ARGS(timestamp))
2009-06-21 19:42:10 +00:00
#if self.duration < 0:
# self.getDuration()
2009-01-18 08:39:14 +00:00
2009-06-21 19:42:10 +00:00
#if timestamp > self.duration:
# self.log("timestamp %s > duration %s" % (timestamp, self.duration))
# return False
2009-01-18 08:39:14 +00:00
self.callback[timestamp] = callback
if self.queue or not self._ready:
self.log('ready')
self.queue.append(timestamp)
else:
self.queue.append(timestamp)
self._getFrame(timestamp)
return True
def _getFrame(self, timestamp):
if not self._ready:
return
2009-06-21 19:42:10 +00:00
if timestamp > self.duration:
if self.mainloop:
self.mainloop.quit()
return
2009-01-18 08:39:14 +00:00
self.log("timestamp : %s" % gst.TIME_ARGS(timestamp))
self.seek(1.0, gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
gst.SEEK_TYPE_SET, timestamp,
gst.SEEK_TYPE_NONE, -1)
return False
def frame(self, timestamp):
2009-06-21 19:42:10 +00:00
self.mainloop = gobject.MainLoop()
2009-01-18 23:43:30 +00:00
self._frames[timestamp] = None
2009-01-18 08:39:14 +00:00
def callback(frame, timestamp):
2009-01-18 23:43:30 +00:00
self._frames[timestamp] = frame
2009-06-21 19:42:10 +00:00
self.mainloop.quit()
2009-06-21 20:25:38 +00:00
self._quit = False
def quit():
if self._quit:
self.mainloop.quit()
return False
else:
self._quit = True
return True
gobject.timeout_add(1000, quit)
2009-01-18 08:39:14 +00:00
if self.getFrame(timestamp, callback):
2009-06-21 19:42:10 +00:00
self.mainloop.run()
2009-06-21 20:25:38 +00:00
2009-01-18 23:43:30 +00:00
frame = self._frames[timestamp]
del self._frames[timestamp]
2009-01-18 08:39:14 +00:00
return frame