Webcam Streaming in Perl/Tk (Linux)

Noah Petherbridge
Posted by Noah Petherbridge on Wednesday, September 02 2009 @ 09:38:42 AM

Late last week I started thinking about how to access a webcam device from within Perl. I have no direct need of such capability at the time being but I wanted to know how to do it in case I wanted to do something in the future involving webcams.

A few years ago when I used mostly Windows I found EZTwain, a DLL library for accessing a webcam in Windows using the TWAIN protocol (which as I understand is obsolete by now). The DLL was a pain in the butt to use and I couldn't get it to work how I wanted it to (it insisted on displaying its own GUI windows instead of allowing my Perl script to directly pull a frame from it without a GUI).

Besides that there's pretty much no libraries Perl has been built to use yet that can access a webcam. So, I started looking into using third-party programs such as ffmpeg and mplayer/mencoder to provide the hardware layer for me so that Perl can get just the jpeg images out and do with them what it needs.

Of these programs I wanted to use ffmpeg the most, because I know for sure there's an ffmpeg.exe for Windows, which might mean that whatever code I come up with might be reasonably portable to Windows as well.

After some searching I found some command-line sorcery for using ffmpeg over SSH to activate the camera on a remote computer and stream the video from it over SSH to the local system, and display it in mplayer:

ssh user@remoteip ffmpeg -b 100K -an -f video4linux2 -s 320x240 -r 10 -i /dev/video0 -b 100K -f ogg - | mplayer - -idle -demuxer ogg

Using the basic ffmpeg command in there, along with some hours of research and poking around, I eventually came up with a command that would activate the webcam and output a ton of jpeg images with consecutive file names, of each frame of video that the camera recorded:

ffmpeg -b 100K -an -f video4linux2 -s 640x480 -r 10 -i /dev/video0 -b 100K -f image2 -vcodec mjpeg test%d.jpg

The mjpeg codec (or "motion jpeg"), in ffmpeg, really means it's a bunch of jpeg images all combined together one after the other (the start of each jpeg image can be seen in hex by looking for the magic number, 0xFFD8). The "image2" format here means that each frame from the mjpeg stream gets written to an individual image file, in the format test%d.jpg where %d is a number that goes up for each image written.

By changing the image2 to image2pipe instead, the output (all the jpeg images in the mjpeg stream) is sent through the program's standard output, so it can be piped into another program, or read from in Perl.

So in Perl I opened a pipe that executes this command and have the script read from it, reading all the jpeg images and then displaying them in a Perl/Tk window as they come in. In effect: a live webcam stream, where Perl is entirely in control of the jpegs as they come in from ffmpeg and can do with them whatever it wants!

Tk Stream

I added a button to my GUI for taking a snapshot and saving it to disk (in actuality, as each complete image is read and displayed, it's kept around in memory until the next image is read and displayed... so this button just saves the last full image to disk).

Here's my proof of concept Perl code:

#!/usr/bin/perl -w

# Perl/Tk Webcam Streamer and Snapshot Taker
# Proof of Concept
# Author: Casey Kirsle,

use Tk;
use Tk::JPEG;
use MIME::Base64 "encode_base64";

# Some things that might need to be configured.
my $device = shift(@ARGV) || "/dev/video0";
if ($device =~ /^\// && !-e $device) {
    die "Can't see video device: $device";

# Tk MainWindow
my $mw = MainWindow->new (
    -title => 'Tk Stream',
$mw->protocol (WM_DELETE_WINDOW => \&onExit);

# A label to display the photos.
my $photo = $mw->Label ()->pack();

# A button to capture a photo
my $capture = $mw->Button (
    -text => "Take Picture",
    -command => \&snapshot,


You can download it here. It should run on any Linux distribution and it depends on having Perl/Tk and ffmpeg installed, and the video4linux2 system (any modern distro will have that).

In the ffmpeg command here you'll see I also piped the output into a quick Perl script that substitutes all the jpeg headers so that they begin with "KIRSLESEP" -- this was to make it easier to split the jpegs up while reading from the stream.

Since this uses ffmpeg and there's an ffmpeg.exe for Windows, this might work on Windows (you'll definitely need to modify the arguments sent to the ffmpeg command, though). I don't currently have access to a Windows machine with a webcam, though, so I can't work on that just yet.

Anyway, here it is: webcam access in Perl!


[ Blog ]


There are 10 comments on this page.

Posted on Monday, September 28 2009 @ 02:21:27 PM by Noah Petherbridge.

To fix the terminal afterward, just use the "reset" command.

It seems to be that ffmpeg changes the readmode on the terminal; I could fix it in my script with Term::ReadKey so it fixes the mode just before exiting... but this script is just a proof of concept anyway and I don't feel like fixing it. ;)

Posted on Friday, April 02 2010 @ 09:41:39 AM by Anonymous.

error in accessing webcam stream using ffmpeg... when i run your code or write
ffmpeg -f video4linux2 -s 720x480 -r 30000/1001 -i /dev/video1 -f avi -vcodec mjpeg -s cif -r 30000/1001 -y silver.avi

on terminal ... it gves error ,

[video4linux2 @ 0x99e0420][3]Capabilities: 5000001
[video4linux2 @ 0x99e0420]The V4L2 driver changed the video from 720x480 to 352x288
[video4linux2 @ 0x99e0420]Cannot find a proper format for codec_id 0, pix_fmt -1.
/dev/video1: Input/output error

i knw the /dev/vid1 path is correct.... what is this error codec _id=0 cannot find proper format?? plz explain how to fix this?ion

my email is
plzzz help i want a quick solution

Posted on Sunday, July 11 2010 @ 09:59:55 PM by caitlyn.


Posted on Saturday, July 31 2010 @ 09:55:34 AM by Andrew Dougherty.

Thanks! Should help with an ID Card Creation software.

Posted on Monday, November 15 2010 @ 11:09:46 PM by go0t0oyo0.


Posted on Wednesday, November 17 2010 @ 04:15:43 AM by gootooyoo.


Posted on Tuesday, April 22 2014 @ 02:05:53 AM by yutren.

vi voglio scopare

Posted on Tuesday, April 29 2014 @ 11:27:03 AM by billel.

i love sex je taime beucoup l amour

Posted on Wednesday, May 14 2014 @ 08:40:38 PM by sebastian duerte .

y es una figura que no me quiero perder

Posted on Wednesday, June 22 2016 @ 12:20:25 PM by Anonymous.

Thanks :)

Add a Comment

Your name:
Your Email:
Comments can be formatted with Markdown, and you can use
emoticons in your comment.

If you can see this, don't touch the following fields.