Basic webcam viewer written in python + gtk + gstreamer.
I spent time making the gst pipe to work properly because I was finding a way to both display the stream on the screen and analyze it.
The latter would be interesting because of the use one can do with it in terms of patter recognition or motion tracking (maybe one day ..).
Anyway here is the resulting gst-pipe even tought only the first branch is implemented in the script below:
v4l2sr
|
ccaps(image/jpeg)
|
videoflip
|
videobalance
|
tee-------------+
| |
queue1 ffmpegcolorspace
| |
xvimagesink caps(video/xraw-rgb)
|
fakesink
Implemented pipe:
v4l2sr ---> ccaps(image/jpeg) ---> videoflip ---> videobalance ---> xvimagesink
The script contains few hardcoded settings such as device number, width .. You can manipulate these during application startup:
let’s suppose i want to display /dev/video2 with a resolution of 640×480 pixels and a framerate of 15fps:
$ python webcam.py 2 640 480 15
Attention: the script doesn’t check whether the device exists or it supports the specified settings.
Here is the code:
#!/usr/bin/env python
import sys
import gtk
import gst
# Webcam settings
DEVICE = 0
WIDTH = 320
HEIGHT = 240
FRAMERATE = 15
# Widget params
VIDEO_PROPERTIES = [("contrast", 0, 2, 1),
("brightness", -1, 1, 0),
("hue", -1, 1, 0),
("saturation", 0, 2, 1)]
class Webcam:
def __init__(self):
# Gui init
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.connect("destroy", self.destroy_cb)
darea = gtk.DrawingArea()
darea.set_size_request(WIDTH, HEIGHT)
controls = gtk.VBox()
labels = gtk.VBox()
for prop, lower, upper, default in VIDEO_PROPERTIES:
adj = gtk.Adjustment(default, lower, upper)
widget = gtk.HScale(adj)
label = gtk.Label(prop)
widget.connect("value-changed", self.value_changed_cb, prop)
controls.pack_start(widget, True, True)
labels.pack_start(label, True, False)
configs = gtk.HBox()
configs.pack_start(labels, False, False)
configs.pack_end(controls, True, True)
layout = gtk.VBox()
layout.pack_start(darea)
layout.pack_end(configs, False, False)
window.add(layout)
# Pipeline configuration
self.pipeline = gst.Pipeline()
source = gst.element_factory_make("v4l2src")
source.set_property('device', "/dev/video%d" % DEVICE)
decoder = gst.element_factory_make("jpegdec")
flip = gst.element_factory_make("videoflip")
flip.set_property('method', 'horizontal-flip')
self.balance = gst.element_factory_make("videobalance")
videosink = gst.element_factory_make("xvimagesink")
videosink.set_property('force-aspect-ratio', True)
self.pipeline.add(source, decoder, flip, self.balance, videosink)
window.show_all()
# Pipeline blocks linking
caps = "image/jpeg,width=%d,height=%d,framerate=%d/1" %
(WIDTH, HEIGHT, FRAMERATE)
source.link(decoder, gst.caps_from_string(caps))
decoder.link(flip)
flip.link(self.balance)
self.balance.link(videosink)
# Callback for display the webcam over the darea
bus = self.pipeline.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
bus.connect('sync-message', self.sync_message_cb, darea)
# Start the flow
self.pipeline.set_state(gst.STATE_PLAYING)
def destroy_cb(self, widget):
self.pipeline.set_state(gst.STATE_NULL)
gtk.main_quit()
def value_changed_cb(self, widget, prop):
self.balance.set_property(prop, widget.get_value())
def sync_message_cb(self, bus, message, darea):
if message.structure is None:
return
message_name = message.structure.get_name()
if message_name == 'prepare-xwindow-id':
# Assign the viewport
imagesink = message.src
imagesink.set_xwindow_id(darea.window.xid)
if __name__ == '__main__':
i = 1
for arg in sys.argv[1:]:
if i == 1: DEVICE = int(arg)
elif i == 2: WIDTH = int(arg)
elif i == 3: HEIGHT = int(arg)
elif i == 4: FRAMERATE = int(arg)
else: break
i += 1
Webcam()
gtk.main()