« February 2008 | Main | April 2008 »

March 2008

March 21, 2008

The Squeezebox really is that good


Sadly, I purchased my Logitech Sqeezebox back in November but had procrastinated in doing the installation until today (March!). That was a big mistake, because this little box and the service that goes with it is amazing.


I purchased the Squeezebox for one very specific purpose - to enable me to access the Rhapsody.com music subscription service. I have had a Rhapsody.com account for a few years now, and have been extremely happy with the selection of music and overall performance. I am a huge fan of the 'rent my music' school of media consumption (vs. the 'own my music' school), which the Rhapsody service model directly supports. The only drawback is that you have to use your computer to access the service. I was partly handicapped due to the fact that I use Ubuntu Linux at home, limiting me to using Rhapsody.com's web-based interface. It works, but tends to cause Firefox to die periodically. What I really wanted was to play Rhapsody music using my existing (more and more infrequently used) home stereo.


Although I think the Squeezebox's original intent was to allow you to play music stored on your local/home PC over your stereo, the device also supports multiple on-line music services (Rhapsody, Pandora, Last.fm and others). The setup was dead simple: Turned it on, and used the remote control to quickly configure the Squeezebox to connect to my home WiFi network. At the end of the device setup sequence, the LCD displayed a device PIN that I could use to access and then control the device over the net.


I then pointed my browser at www.squeezenetwork.com and registered the device using the PIN. Once registered, I could then configure the Squeeze Network to access my Rhapsody.com account. Again, no problems encountered.


And now, nirvana. Sitting at my desk in the home office accessing my squeezenetwork.com account in Firefox I can browse, search and play any of the 3 million or so tracks available within Rhapsody.com over my home stereo. All of the device capabilities can be controlled by the browser, and the changes are near instant. I click 'Next track' in the browser and within 1 second the next track starts streaming via the Squeezebox. Totally amazing. It solved my problem completely.

March 15, 2008

07-1101 : Chicago Lawyers' v. Craigslist Inc


Notch a victory for sanity and reasoned judgment coming from the US 7th District Court of Appeals. In case 07-1101: Chicago Lawyers' vs. Craigslist the court ruled strongly in favor of the defendant, Craigslist. In the lawsuit, the Chicago Lawyers' are making the argument that Craigslist is at least partially liable for the content of the advertisements placed using their website. Specifically, the case revolves around a classified advertisement in which the statement "NO MINORITIES" appeared, which is in violation of federal Equal Housing Opportunity rules. Craigslist argued - correctly - that they are not the originator of the content so they cannot be held liable under any federal laws for the words used in the classified ad.


In the opinion written by Judge Easterbrook, Easterbrook makes several good points:

Web sites are not common carriers, but screening, though lawful, is hard. Simple filters along the lines of “postings may not contain the words ‘white’ ” can’t work. Statements such as “red brick house with white trim” do not violate any law, and prospective buyers and renters would be worse off if craigslist blocked descriptive statements.
Further, the judge points out that it would be completely impractical for a company like Craigslist to hire humans to manually review each ad for potentially illegal speech prior to posting:
An online service could hire a staff to vet the postings, but that would be expensive and may well be futile: if
postings had to be reviewed before being put online, long delay could make the service much less useful, and
if the vetting came only after the material was online the buyers and sellers might already have made their deals.
Every month more than 30 million notices are posted to the craigslist system. Fewer than 30 people, all based in
California, operate the system, which offers classifieds and forums for 450 cities. It would be necessary to increase
that staff (and the expense that users must bear) substantially to conduct the sort of editorial review that the
Lawyers’ Committee demands—and even then errors would be frequent.


And yes, all of this has been covered extensively elsewhere, but something funny occurred to me as I was reading about the case and the ruling. Although I do not know for certain in which city this particular classified advertisement was placed, it seemed that the population trends throughout most of the USA would make such an advertisement fairly counterproductive. For example, assume that by "NO MINORITIES" the apartment owner meant "No people who are not of white European descent". Next, assume the ad was posted in a city like San Francisco, the home of Craigslist. Based on 2006 US Census data, that meant that they would only consider 57% of the city population as eligible to rent their apartment. Can you imagine any sensible business person declaring nearly half of all possible customers were unwelcome because of the color of their skin? I suppose you can, but they'd probably be out of business fairly quickly.

March 07, 2008

But wait, there's more to using a webcam on Linux!


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"
gst-launch-0.10 -v v4l2src num-buffers=1 ! fakesink
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'):
v4l2src0> getting src format enumerations
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)
Further 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:
[snip]
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]
which is then immediately followed by the combination that the driver has selected for use in recording - the process known as 'fixating':

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
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:
> set -x GST_DEBUG "*v4l2*:1"
> gst-launch-0.10 -v v4l2src num-buffers=1 !
image/jpeg,width=800,framerate=30/1,rate=30 ! fakesink
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'):
/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.

March 04, 2008

Using a USB Webcam on Ubuntu Linux to produce good quality video captures that can be uploaded to YouTube directly


Please excuse the lengthy title, but after spending the better part of the last two days getting this entire process nailed down I want to make sure that this write-up is indexed by the search engines as comprehensively as possible. The whole thing started when I was asked the seemingly simple question of "Is it possible to use a webcam on Linux?" My initial answer was "Yeah, sure, I think." The goal was clear - configure a low-cost webcam on Ubuntu Linux to capture video and audio in a form that could be used for both voice/video chat (Skype) as well as for upload to video sharing sites like YouTube.

A bit of digging later, I had put together enough information to convince myself that it could be done. To start, I needed the hardware - and I opted for the Logitech QuickCam for Noteooks Pro. It is a USB device with both camera and microphone. I selected this model because it supported relatively high resolutions and was fully supported by the Linux USB Video Class driver which are compatible with the Video For Linux, version 2 (v4l2) framework and kernel drivers. I wanted v4l2 support because the Skype Beta client for Linux uses that framework for voice and video calling. As it turns out, all of the drivers to make this work are included in a default installation of Ubuntu 7.10, so nothing additional needs to be installed as far as voice calling with Skype is concerned.

To first test things out, I downloaded and installed the Skype beta client for linux. I plugged in the USB webcam, launched Skype, and select Options -> Audio Devices. I selected the USB device from the list of possible sound input sources. I then selected Options -> Video Devices and did the same. Pressing the 'Test' button displayed a small video feed from the camera. To confirm, I placed a call to a friend, and everything just worked. The video quality was good and the audio quality was fine.

To get a closer look at how the kernel treats the device, I used the 'lsusb' command to get a list of the USB devices:

# lsusb
Bus 002 Device 002: ID 045e:00db Microsoft Corp.
us 002 Device 003: ID 047d:1020 Kensington
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 009: ID 046d:0991 Logitech, Inc.
Bus 001 Device 006: ID 0424:223a Standard Microsystems Corp. 8-in-1 Card Reader
Bus 001 Device 005: ID 0424:2504 Standard Microsystems Corp.
Bus 001 Device 002: ID 0424:2502 Standard Microsystems Corp.
Bus 001 Device 001: ID 0000:0000

There in the middle of the list is 'Logitech, Inc.' the maker of the webcam. For information on the list of sound devices that had been detected by ALSA, the audio framework:

# arecord -l
card 0: CK804 [NVidia CK804], device 0: Intel ICH [NVidia CK804]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: CK804 [NVidia CK804], device 1: Intel ICH - MIC ADC [NVidia CK804 - MIC ADC]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: U0x46d0x991 [USB Device 0x46d:0x991], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

This told me that the microphone on the webcam was registered as 'card 1, subdevice 0'. This information will be used later when we attempt to record audio/video. This can also be determined from the output of /proc/asound/pcm:

# cat /proc/asound/pcm
00-02: Intel ICH - IEC958 : NVidia CK804 - IEC958 : playback 1
00-01: Intel ICH - MIC ADC : NVidia CK804 - MIC ADC : capture 1
00-00: Intel ICH : NVidia CK804 : playback 1 : capture 1
01-00: USB Audio : USB Audio : capture 1
Again, the USB Audio is registered as card 1, subdevice 0.

With the basics working, the next thing I wanted to do was make a high-quality video recording that would be suitable for upload to YouTube. After another round of digging it looked like two video capture frameworks had direct support for v4l2 - mplayer/mencoder and gstreamer. I first attempted to use mencoder, but after several hours was not able to get things working. I was able to capture video only, and as soon as I tried to mix in the audio input, mencoder would die with a 'Floating point exception' error. A message to the mplayer-devel mailing list about the problem went unanswered. So next I turned my attention to gstreamer.

Although I will spare you details, after about two days of hacking at this I was able to achieve my goal: High resolution video, good audio quality, and perfect synchronization between the two.

First, make sure you have the full set of gstreamer-plugins (good, bad, and ugly) installed. This should include:

# dpkg --list '*gst*' | grep ii
ii  gstreamer-tools                       0.10.14-1ubuntu3 Tools for use with GStreamer
ii  gstreamer0.10-alsa                    0.10.14-1ubuntu3 GStreamer plugin for ALSA
ii  gstreamer0.10-esd                     0.10.6-0ubuntu4  GStreamer plugin for ESD
ii  gstreamer0.10-ffmpeg                  0.10.2-2ubuntu1  FFmpeg plugin for GStreamer
ii  gstreamer0.10-gnomevfs                0.10.14-1ubuntu3 GStreamer plugin for GnomeVFS
ii  gstreamer0.10-gnonlin                 0.10.9-1         non-linear editing module for GStreamer
ii  gstreamer0.10-plugins-bad             0.10.5-4ubuntu1  GStreamer plugins from the "bad" set
ii  gstreamer0.10-plugins-bad-multiverse  0.10.5-1         GStreamer plugins from the "bad" set (Multiv
ii  gstreamer0.10-plugins-base            0.10.14-1ubuntu3 GStreamer plugins from the "base" set
ii  gstreamer0.10-plugins-base-apps       0.10.14-1ubuntu3 GStreamer helper programs from the "base" se
ii  gstreamer0.10-plugins-good            0.10.6-0ubuntu4  GStreamer plugins from the "good" set
ii  gstreamer0.10-plugins-ugly            0.10.6-0ubuntu2  GStreamer plugins from the "ugly" set
ii  gstreamer0.10-plugins-ugly-multiverse 0.10.6-0ubuntu1  GStreamer plugins from the "ugly" set (Multi
ii  gstreamer0.10-tools                   0.10.14-1ubuntu3 Tools for use with GStreamer
ii  gstreamer0.10-x                       0.10.14-1ubuntu3 GStreamer plugins for X11 and Pango
ii  libgstreamer-plugins-base0.10-0       0.10.14-1ubuntu3 GStreamer libraries from the "base" set
ii  libgstreamer-plugins-base0.10-dev     0.10.14-1ubuntu3 GStreamer development files for libraries fr
ii  libgstreamer0.10-0                    0.10.14-1ubuntu3 Core GStreamer libraries and elements
ii  libgstreamer0.10-dev                  0.10.14-1ubuntu3 GStreamer core development files
ii  python-gst0.10                        0.10.8-1ubuntu1  generic media-playing framework (Python bind

Next, we'll need to install one non-standard package called GEntrans which is maintained by Mark Nauwalaerts. I discovered this package via an email sent to the GStreamer-devel mailing list asking for help with my initial video recording problems: I was completely unable to get good synchonized audio and video recordinds. The audio always lagged or was shifted or garbled in some way. The GEntrans package is a gstreamer plugin that provides a gstreamer element named 'stamp' that can apply timestamps to incoming video streams in a way that they can later by perfectly matched to the incoming audio streams to produce perfectly sync'd output.

You can download the source from the sf.net site, and install it with:

./configure --prefix=/usr 
sudo make install

I suggest you use the --prefix=/usr so that the compiled plugins will go into the standard gstreamer plugins directory (/usr/lib/gstreamer-0.10). That makes them easier to use in the next step. After many, many rounds of experimentation and help from Mark, I put together the following gstreamer recording command:

# gst-launch-0.10  v4l2src queue-size=16 !  stamp sync-margin=1 sync-interval=1 
    ! video/x-raw-yuv,width=800,height=600,framerate=15/1 
    ! queue2 max-size-buffers=1000 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=1000 max-size-bytes=0 max-size-time=0  
    !  vorbisenc quality=0.9 name=aenc oggmux name=mux ! filesink location=test.ogg aenc. ! mux. venc. ! mux

Yes, that is actually one single command-line command. The basic interpetation is this: Create a gstreamer processing pipeline with the following characteristics:

  • Use v4l2 as the source of video, and tell it to use its max buffer setting
  • Apply a timestamp signal to that video stream using 'stamp'
  • Treat that incoming vidoe data as x-raw-yuv of size 800x600 @ 15 frames/second.
  • Perform the remaining video transformation in a separate thread using 'queue2'
  • Use the ffmpeg color space to properly map the colors on the inbound video signal
  • Send that input into the 'theoraenc' video encoder to produce a Theora compressed video stream
  • Combine that stream (or 'mux it') with sound input coming from ALSA sound input card 1, subdevice 0
  • Treat the incoming audio data as x-raw-int at 16kHz mono with 16 bits, which is what the QuickCam produces
  • Convert that audio stream into a generic form that gstreamer audio encoders can handle using 'audioconvert'
  • Create a separate threat for audio processing using 'queue2' and plenty of buffering
  • Encode the audio using the vorbis encoder ('vorbisenc') the combine (or 'mux it') into an Ogg container ('oggmux')
  • Dump the Ogg formatted file data to disk into a file named 'test.ogg'

What I did not know, but was thrilled to discover, is that YouTube accepts files formatted like this - Theora encoded video, Vorbis encoded audio, wrapped into an Ogg formatted file - directly for upload! You can see the results of me wishing my nephew a happy birthday here on YouTube. Keep in mind that the YouTube processed version is not as high quality as the original Ogg file that was produced during the recording locally. The fact is that it can be done and that it works!

Side note: If you just want to record audio to an mp3 file using the microphone on your webcam, use the following command:

gst-launch-0.10 alsasrc device="hw:1,0" 
    ! audio/x-raw-int,rate=16000,channels=1,depth=16 
    ! audioconvert ! lame ! filesink location=test.mp3
To do the same but using Vorbis encoded Ogg-formatted output:
gst-launch-0.10 alsasrc device="hw:1,0" 
    ! audio/x-raw-int,rate=16000,channels=1,depth=16 
    ! audioconvert ! vorbisenc ! oggmux 
    ! filesink location=test.ogg
And if you just want to play the audio back to yourself:
gst-launch-0.10 alsasrc device="hw:1,0" 
    ! audio/x-raw-int,rate=16000,channels=1,depth=16 
    ! audioconvert 
    ! alsasink
If all you want is to show the video being captured by the camera in a window on your desktop:
gst-launch-0.10 v4l2src 
    ! video/x-raw-yuv,width=800,height=600 
    ! ffmpegcolorspace 
    ! xvimagesink
For those of you who need to adjust the color/contrast/brightness settings of their webcam, I suggest luvcview.

Listening To

Real Estate Stats

  • Price Trend for Sunnyvale 94086
  • Median Price for All Sunnyvale
  • Median Price for Sunnyvale 94086

GA