Saturday, March 29, 2008

The Flashcam Project

My previous post about a kludge to support V4L2 webcams on Flash for Linux has finally been useful and packaged enough to be held in a more appropriate place. Awaiting for a sourceforge reply about project creation, the homepage and resources have been placed here:
The Flashcam Project.


Sunday, March 9, 2008

The Linux Flash Webcam Headache

Update: this has been turned into a dedicated web page: The Flashcam Project.

Let me start this blog with a subject that has been quite often addressed: "How to make my webcam work with Flash on Linux?"
Even if there is a driver for the hardware, it might be not recognized by Flash.
I will propose a solution, even if it is a work-around it will allow many users to consider Flash as a potential video conference solution with their favorite platform.

But first of all, it is necessary to describe the problem at large. I have no intent to argue or offense, just list facts.

Yes, there is a man behind Flash for Linux at Adobe, many should respect this first. Mike Melanson has been working hard to make it work especially when it comes to solve many interface issues (audio, video, fonts, window manager, network layers, ...). He did one very useful thing: through a dynamic library it is possible to hook a certain number of functionalities that allow to delegate some tasks like SSL and audio. This library is called libflashsupport and it is maintained here at SF.
Looking at the source gives hope when it comes to hook the video capture part, and hope vanishes when you notice that none of the functions are called by the plugin. Ok, it's disappointing, but the interface wasn't of a perfect design if you want to manage more than one video source. The GetFrame interface could have been kept though.

Anyway, Mike chose V4L to capture video frames. This has been controversial since V4L is now considered obsolete and V4L2 is the preferred approach for video on Linux.
Some drivers still respond to V4L and I could myself use a Creative webcam thanks to the almighty Gspca driver (what a great job Michel, Sylvie et al). But Michel is heading towards V4L2 and newer drivers are V4L2 only.
On a brand new PackardBell laptop, I installed a Fedora 8 and could very easily setup UVC driver to support the builtin webcam. On my Linux desktop (old Fedora 4) I have a PCTV Rave PCI card which is perfectly supported by the bttv driver.
But none of these two video frame grabbers are supported (just nothing for UVC and garbage for bttv). So the challenge is to make Flash believe that both video devices are V4L compatible. Re-writing drivers to be V4L compatible is everything but smart.

I found a very useful driver designed for debug purpose called Vloopback. It is V4L compatible, thus predicted to disappear. Actually, it is a solution, well almost. This nifty useful driver creates video devices pipes where you can write frames on an end and grab them on the other end. But many thought Flash could not understand vloopback interface, wrong! There is a small issue with vloopback and Flash: vloopback creates two devices where the first one is the input and the second one is the ouput. So when you install the default driver you get, say /dev/video1 and /dev/video2 and video1 is the input. Ah! Unfortunately Flash iterates over videoN devices and stops enumeration when open fails whatever error comes out. Too bad, /dev/video2 is never reached because it fails to open /dev/video1 (the input). What an easy patch! Swapping device registrations in the driver to get the input after the output. And tada Flash could 'see' the loopback. I just had to find an simple V4L2 capture program (why rewriting one where the V4L2 author just provides one, capture.c) and make it send frames to the loopback.
One additional issue! That would have been too easy otherwise. Flash only supports 'read' method and YUV420P pixel format. Not a big deal a few lines of code later and I got my simple flashcam program to forward V4L2 devices frames to the V4L loopback.
The driver has also been modified to block on write calls when no one is reading the output end, this makes the flashcam endless looping program just not stupidly eating up CPU cycles.

Enough blabla!!! Show us the solution dude! Ok, ok. For once let's make it simple:
  1. Grab the flashcam program and the modified vloopback driver.
  2. type make flashcam to build the frame forwarder.
  3. Build the vloopback driver: make (note you must have V4L and V4L2 support in your kernel config).
  4. Install the driver as root: make install
Now you have all binaries. As root start the vloopback driver:
# modprobe vloopback inminor=9

The inminor=9 option tells vloopback to create the input device on /dev/video9. The output device will be the next available one after /dev/video (i.e: /dev/video1).
Kernel message should display:

vloopback: Video4linux loopback driver v1.1.1 vloopback: Loopback 0 registered, input: video9,output: video1

You may have to change permissions on /dev/video1 and /dev/video9 so users can access them.
As normal user now run flashcam program:

[olivier] $ ./flashcam -d /dev/video0 -l /dev/video9

Note: type flashcam -h for help about the utility.

By default flashcam grabs frames from /dev/video (with -d option you can specify where is your V4L2 device), it is told to forward them to /dev/video9 with the arguments shown above. From now on, /dev/video1 is a V4L compatible interface that grabs frames from /dev/video which is a V4L2 interface.

Fire up Firefox and get a SWF to test, why not this one (click Allow in the pop up otherwise the test will be totally useless)? Note: in any active SWF movie you can change the default video source with the contextual menu, right-click and select "Settings".
The first video source entry is the V4L2 device, which of course doesn't show anything, but the second one, which is the loopback...


This successfully worked with Bttv driver and UVC driver.

The solution isn't packaged at all as you can see. And the target audience here is Linux developers. There are certainly many things to improve, flashcam could support many more pixel formats than the default used one, automatically searches the loop device, etc.
It might become an easier to use stuff if this found useful by the community. This is the beginning, feedback is appreciated.

Keep in mind that this is a kludge until there is a true support for V4L2 in Flash.