Public feed
#604099
#!/usr/bin/python
# 2007-07
# test-dr // based on my c-coding tests for picture injections into video
# first try as pyhton-src - based on the gst-examples like gst-python-0.10.7/examples/filesrc.py
import inspect
import sys
import random
import string
import gc
import pygst
pygst.require("0.10")
import gobject
import gst
import pygtk
import gtk
import copy
def get_attributes(obj, public_only=True):
attrs = inspect.getmembers(obj, lambda o: not inspect.isroutine(o))
if public_only:
return [x for x in attrs if x[0][0] != "_"]
else:
return attrs
class PictureSource(gst.BaseSrc):
__gsttemplates__ = (
gst.PadTemplate("src",
gst.PAD_SRC,
gst.PAD_ALWAYS,
gst.caps_new_any()),
)
filename = ""
width = 0
height = 0
framerate = 10
pixbuf = None
last_pixbuf = None
out_pixbuf = None
pic_duration = 100
pic_number = 0
frame = 0
step_scale = 0
transition_duration = 2
transition_type = 0
random_value = range(600)
datarate = 0
def __init__(self, name):
self.__gobject_init__()
self.curoffset = 0
self.set_name(name)
def set_property(self, name, value):
if name == 'location':
self.filename = value
pixbuf = gtk.gdk.pixbuf_new_from_file(self.filename)
if self.width == 0:
self.width = pixbuf.get_width()
if self.height == 0:
self.height = pixbuf.get_height()
# scale picture, if not the right size
if self.height != pixbuf.get_height() or self.width != pixbuf.get_width:
self.pixbuf = pixbuf.scale_simple(self.width, self.height, gtk.gdk.INTERP_BILINEAR)
print "new picture ", value
if name == "width":
self.width = value
if name == "height":
self.height = value
if name == "pic_duration":
self.pic_duration = value
if name == "framerate":
self.framerate = value
if name == "transition_type":
self.transition_type = value
if name == "transition_duration":
self.transition_duration = value
def get_property(self, name):
if name == "width":
return self.width
if name == "height":
return self.height
if name == "framerate":
return self.framerate
def do_create(self, offset, size):
if self.datarate == 0:
self.datarate = self.width * self.height * 3 * self.framerate
if self.frame % self.pic_duration == 0:
if self.pic_number >= len(pic_names):
return gst.FLOW_UNEXPECTED, None
if self.transition_type > 0 and self.pic_number > 0:
self.step_scale = self.transition_duration * self.framerate
if self.last_pixbuf:
del self.last_pixbuf
self.last_pixbuf = self.pixbuf.copy()
del self.pixbuf
self.set_property("location", pic_names[self.pic_number])
self.pic_number += 1
# need this gc-stuff or memory usage grows on and on ...
gc.collect()
if not self.pixbuf:
return gst.FLOW_UNEXPECTED, None
# !! at the moment this should always be the same, because the pic is scaled when loaded
# or should i do some more checks with self.width/height
width = self.pixbuf.get_width()
height = self.pixbuf.get_height()
#print "settings pic pixbuf: %s (%d x %d)" % (self.filename, width, height)
if self.step_scale > 0:
step_scale = self.step_scale
transition_type = self.transition_type
steps = self.transition_duration * self.framerate
print "step_scale:", step_scale
self.out_pixbuf = self.last_pixbuf.copy()
if transition_type == 1:
self.pixbuf.scale(self.out_pixbuf, 0, 0, width/step_scale, height/step_scale, 0, 0, 1.0/step_scale, 1.0/step_scale, gtk.gdk.INTERP_BILINEAR)
if transition_type == 2:
self.pixbuf.composite(self.out_pixbuf, 0, 0, width/step_scale, height/step_scale, 0, 0, 1.0/step_scale, 1.0/step_scale, gtk.gdk.INTERP_BILINEAR, 100+(150/step_scale))
if transition_type == 3:
self.pixbuf.scale(self.out_pixbuf, width*(step_scale-1)/(2*step_scale), height*(step_scale-1)/(2*step_scale),
width/step_scale, height/step_scale,
width*(step_scale-1)/(2*step_scale), height*(step_scale-1)/(2*step_scale),
1.0/step_scale, 1.0/step_scale, gtk.gdk.INTERP_BILINEAR)
if transition_type == 4:
self.pixbuf.composite(self.out_pixbuf, width*(step_scale-1)/(2*step_scale), height*(step_scale-1)/(2*step_scale),
width/step_scale, height/step_scale,
width*(step_scale-1)/(2*step_scale), height*(step_scale-1)/(2*step_scale),
1.0/step_scale, 1.0/step_scale, gtk.gdk.INTERP_BILINEAR, 100+(150/step_scale))
if transition_type == 5:
self.pixbuf.composite(self.out_pixbuf, 0, 0, width, height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_BILINEAR, 50+(200/step_scale))
if transition_type == 6:
del self.out_pixbuf
self.out_pixbuf = self.pixbuf.copy()
self.last_pixbuf.composite(self.out_pixbuf, 0, height - ((height/steps)*step_scale),
width, ((height/steps)*step_scale),
0, height - ((height/steps)*step_scale), 1.0, 1.0 - (1.0/step_scale), gtk.gdk.INTERP_BILINEAR,
150+step_scale*100/steps)
# scale the old picture down in the height, like melte down to the bottom
if transition_type == 7:
del self.out_pixbuf
self.out_pixbuf = self.pixbuf.copy()
self.last_pixbuf.composite(self.out_pixbuf, 0, height - ((height/steps)*step_scale),
width, ((height/steps)*step_scale),
0, height - ((height/steps)*step_scale), 1.0, step_scale*(1.0/steps), gtk.gdk.INTERP_BILINEAR,
150+step_scale*100/steps)
# move old picture out to the right with a bit down-scaling in the width
if transition_type == 8:
del self.out_pixbuf
self.out_pixbuf = self.pixbuf.copy()
self.last_pixbuf.composite(self.out_pixbuf, width - ((width/steps)*step_scale), 0,
((width/steps)*step_scale), height,
width - ((width/steps)*step_scale), 0, 1.0, 1.0 - (1.0/step_scale), gtk.gdk.INTERP_BILINEAR,
150+step_scale*100/steps)
# move old picture out to the left without scaling
if transition_type == 9:
del self.out_pixbuf
self.out_pixbuf = self.pixbuf.copy()
self.last_pixbuf.composite(self.out_pixbuf, 0, 0,
((width/steps)*step_scale), height,
((width/steps)*step_scale)-width, 0, 1.0, 1.0, gtk.gdk.INTERP_BILINEAR,
150+step_scale*100/steps)
# try of some good old doom-kind melting
if transition_type == 10:
stripsize = width/500
if stripsize < 2:
stripsize = 1
del self.out_pixbuf
self.out_pixbuf = self.pixbuf.copy()
for i in range(0, width/stripsize):
if steps == step_scale:
self.random_value[i] = int(random.random() * 40 + 100)
#print stripsize, " val: ", i, ":", self.random_value[i], " ", i*stripsize, " ", (i+1)*stripsize
if self.random_value[i] < 100:
self.last_pixbuf.composite(self.out_pixbuf, i*stripsize, height-1-((height/100)*self.random_value[i]),
stripsize, ((height/100)*self.random_value[i]),
0, height -1- ((height/100)*self.random_value[i]), 1.0, self.random_value[i]/100.0, gtk.gdk.INTERP_BILINEAR,
200+step_scale*50/steps)
else:
self.last_pixbuf.composite(self.out_pixbuf, i*stripsize, 0,
stripsize, height,
0, 0, 1.0, 1.0, gtk.gdk.INTERP_BILINEAR,
200+step_scale*50/steps)
self.random_value[i] -= int(80/(steps))+(steps-step_scale)
if self.random_value[i] < 0:
self.random_value[i] = 0
self.step_scale -= 1
data3 = self.out_pixbuf.get_pixels_array().flat.tostring()
#data1 = self.out_pixbuf.get_pixels_array()
else:
data3 = self.pixbuf.get_pixels_array().flat.tostring()
#data1 = self.pixbuf.get_pixels_array()
# get the array, make it flat and to a string=byte-sequence
#data2 = data1.flat
#data3 = data2.tostring()
#print data1[0]
#print len(data1[0])
#print len(data3)
#print len(data1[:,0])
#print data1[:, 0]
if data3:
self.frame += 1
print "frame ", self.frame
#buffer = gst.Buffer(data3)
return gst.FLOW_OK, gst.Buffer(data3)
#return gst.FLOW_OK, buffer
else:
return gst.FLOW_UNEXPECTED, None
gobject.type_register(PictureSource)
pic_names=[]
def main(args):
width = height = framerate = pic_duration = transition_type = pic_first = pic_last = transition_duration = 0
outputfile = ""
pic_pattern = ""
if len(args) < 2:
print 'Usage: %s -width scale2## -height scale2## -framerate ## -pic-duration #frames -pic-names {picture1}{picture2}......' % (args[0])
print ' example: %s -framerate 20 -pic-duration 40 -pic-names ~/mypics/*.png\n\tchanges picture after 40 frames(=2 seconds for 20fps) to next picture' %(args[0])
print ' write to theora-ogg: %s -outputfile sheets.ogg -pic-names ~/mypics/hello.png ~/mypics/way*.png\n\t uses size of first picture and default framerate of 10fps with 10 seconds displaytime for each picture' %(args[0])
print ' -transition 1-10 = a optional transition-effect with a duration of 2 seconds'
print ' optional instead of single picture-names, use a pattern with startnumber and endnumber like\n\t %s -pic-pattern "out%%05d.png" -pic-first 100 -pic-last 10\n\t will create from out00100.png down to out00010.png' %(args[0])
return -1
for i in range(len(args)):
#print i, ":", args[i]
if args[i] == "-outputfile":
outputfile = args[i+1]
if args[i] == "-framerate":
framerate = string.atoi(args[i+1])
if args[i] == "-width":
width = string.atoi(args[i+1])
if args[i] == "-height":
height = string.atoi(args[i+1])
if args[i] == "-pic-duration":
pic_duration = string.atoi(args[i+1])
if args[i] == "-transition":
transition_type = string.atoi(args[i+1])
if args[i] == "-transition-duration":
transition_duration = string.atoi(args[i+1])
if args[i] == "-pic-pattern":
pic_pattern = args[i+1]
if args[i] == "-pic-first":
pic_first = string.atoi(args[i+1])
if args[i] == "-pic-last":
pic_last = string.atoi(args[i+1])
if args[i] == "-pic-names":
for j in range(i+1, len(args)):
print args[j]
pic_names.append(args[j])
i += 1
break
if not pic_pattern == "":
if pic_first <= pic_last:
for i in range(pic_first, pic_last+1):
str = pic_pattern % (i)
pic_names.append( str )
else:
for i in range(pic_first, pic_last-1, -1):
str = pic_pattern % (i)
pic_names.append( str )
for i in (pic_names):
print i
pipeline = gst.Pipeline('pipeline')
if outputfile == "":
bin1 = gst.gst_parse_bin_from_description("capsfilter name=caps ! identity single-segment=True ! ffmpegcolorspace ! xvimagesink", 1)
else:
str = "capsfilter name=caps ! identity single-segment=True ! ffmpegcolorspace ! theoraenc quality=60 ! oggmux ! filesink location=%s" % (outputfile)
bin1 = gst.gst_parse_bin_from_description(str, 1)
assert bin1
picture = PictureSource('picture')
assert picture
if width > 0:
picture.set_property('width', width)
if height > 0:
picture.set_property('height', height)
if pic_duration > 0:
picture.set_property('pic_duration', pic_duration)
if framerate > 0:
picture.set_property('framerate', framerate)
if transition_type > 0:
picture.set_property('transition_type', transition_type)
if transition_duration > 0:
picture.set_property('transition_duration', transition_duration)
# need this to setup sizes from first picture if not specified for scaling
picture.set_property('location', pic_names[0])
capsfilter = bin1.get_by_name('caps')
pipeline.add(picture, bin1)
str = "video/x-raw-rgb, width=(int)%d, height=(int)%d, framerate=(fraction)%d/1, bpp=(int)24, depth=(int)24, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, endianness=(int)4321" % ( picture.get_property('width'), picture.get_property('height'), picture.get_property('framerate'))
print str
caps = gst.caps_from_string(str)
capsfilter.set_property("caps", caps)
gst.element_link_many(picture, bin1)
pipeline.set_state(gst.STATE_PLAYING)
mainloop = gobject.MainLoop()
def bus_event(bus, message):
t = message.type
if t == gst.MESSAGE_EOS:
mainloop.quit()
elif t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
print "Error: %s" % err, debug
mainloop.quit()
return True
pipeline.get_bus().add_watch(bus_event)
mainloop.run()
pipeline.set_state(gst.STATE_NULL)
if __name__ == '__main__':
sys.exit(main(sys.argv))