Just when you thought it was safe to go back in the webcam waters, I've got an update to my earlier entry on how to record high quality video footage from a USB webcam (the Logitech QuickCam Pro for Notebooks) on Ubuntu Linux. While I was reasonably happy with the outcome of my earlier results, I was bothered by the fact that I had not been able to record video at the highest claimed frame rate (30 frames per second, 30fps) and resolution (800 px wide by 600 px high). The best I'd been able to achieve earlier was 640x480@15fps. After a few email messages exchanged with members of the (very helpful) gstreamer community, I was able to dig to the bottom of the problem. This understanding then allowed me to construct a gstreamer pipeline to capture 800x600@30fps video.
Edgard Lima, the maintainer of the v4l2 gstreamer source driver taught me a nice troubleshooting trick: set the environment variable 'GST_DEBUG' to the value "*v4l2*:5" before executing your gstreamer command. In the Fish shell, this looks something like this:
set -x GST_DEBUG "*v4l2*:5"This command will produce a LARGE amount of debug output, but it will tell you everything that the v4l2src driver was able to learn about your video camera. The first important part is that the v4l2src driver acknowledges that the QuickCam can provide video in one of two pixel formats - MJPEG (or 'motion jpeg') and YUYV (also called 'YUV2'):
gst-launch-0.10 -v v4l2src num-buffers=1 ! fakesink
v4l2src0> getting src format enumerationsFurther down in the output you will see the driver enumerate every possible combination of pixel format, height, width and framereate that the device is capable of (abbreviated). The important thing to notice is that when in the YUV2 pixel format and 800x600 pixels the camera will only deliver a maximum of 25fps. In order to enable 30pfs capture, you must use the MJPEG pixel format:
v4l2src0> index: 0
v4l2src0> type: 1
v4l2src0> flags: 00000001
v4l2src0> description: 'MJPEG'
v4l2src0> pixelformat: MJPG
v4l2src0> index: 1
v4l2src0> type: 1
v4l2src0> flags: 00000000
v4l2src0> description: 'YUV 4:2:2 (YUYV)'
v4l2src0> pixelformat: YUYV
v4l2src0> got 2 format(s)
[snip]which is then immediately followed by the combination that the driver has selected for use in recording - the process known as 'fixating':
v4l2src0> get frame interval for 800x600, MJPG
v4l2src0> adding discrete framerate: 30/1
v4l2src0> adding discrete framerate: 25/1
v4l2src0> adding discrete framerate: 20/1
v4l2src0> adding discrete framerate: 15/1
v4l2src0> adding discrete framerate: 10/1
v4l2src0> adding discrete framerate: 5/1
[snip]
v4l2src0> get frame interval for 800x600, YUYV
v4l2src0> adding discrete framerate: 25/1
v4l2src0> adding discrete framerate: 20/1
v4l2src0> adding discrete framerate: 15/1
v4l2src0> adding discrete framerate: 10/1
v4l2src0> adding discrete framerate: 5/1
[snip]
Now that I knew what the device was capable of, it was only a matter of time before I was able to figure out how to tell gstreamer to use the specific settings (800x600@30fps) that I wanted. I then turned down the debug level and added the '-v' switch to gstreamer to get more verbose information on the stream:
v4l2src0> fixating caps image/jpeg, width=(int)160, height=(int)120,
framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }
v4l2src0> trying to set_capture 160x120 at 30/1 fps, format MJPEG
> set -x GST_DEBUG "*v4l2*:1"The output confirmed that the stream was exactly as I wanted it. This output tells you that the video originates as 800x600@30fps MJPEG and stays that way as it is sent to its destination (in this case, the 'fake' destination named 'fakesink'):
> gst-launch-0.10 -v v4l2src num-buffers=1 !
image/jpeg,width=800,framerate=30/1,rate=30 ! fakesink
/pipeline0/capsfilter0.src: caps = image/jpeg,
width=(int)800, height=(int)600, framerate=(fraction)30/1, rate=(int)30
/pipeline0/capsfilter0.sink: caps = image/jpeg,
width=(int)800, height=(int)600, framerate=(fraction)30/1, rate=(int)30
/pipeline0/fakesink0.sink: caps = image/jpeg,
width=(int)800, height=(int)600, framerate=(fraction)30/1, rate=(int)30
With this confirmed, it was then just a matter of using this video pipeline in an overall processing pipeline to combine audio and generate a file that can still be easily played back and uploaded to YouTube. That command is:
gst-launch-0.10 v4l2src queue-size=16 ! stamp sync-margin=1 sync-interval=1
! image/jpeg,width=800,framerate=30/1,rate=30 ! ffdec_mjpeg
! queue2 max-size-buffers=10000 max-size-bytes=0 max-size-time=0
! ffmpegcolorspace ! theoraenc quality=60 name=venc alsasrc device="hw:1,0"
! audio/x-raw-int,rate=16000,channels=1,depth=16 ! audioconvert
! queue2 max-size-buffers=10000 max-size-bytes=0 max-size-time=0
! vorbisenc quality=0.9 name=aenc oggmux name=mux
! filesink location=out.ogg aenc. ! mux. venc. ! mux.
An example of a file encoded using this command can be from here.





