There are sometimes the video output from webcam are turned upside down by default on some notebook type. I’ve seen this on some hp notebook (I forgot the type) and also on Axioo Pico DJH model that one of the user at klixsonline were complaining about this issue. This upside down image issue was not a big deal if only using wxcam application because there were a function “upturned” on wxcam that can fix the issue, but this is a major problem on kopete instant messenger since kopete only had a mirror horizontal option on the setting page, thus the video image on the other side were still flip upside down. Since this upside down stream image were from webcam device buffer stream, this issue will affected all application that grab the stream output like skype, mplayer, kopete, lucview, cheese, etc.
The only solution is revert back to the stream itself and rewrite back the image, before uvcvideo module give them to user space. The patch can be found here. I have made a patch on uvcvideo module that can be downloaded as dkms module for KLIXs user, so the user doesn’t have to patch manually, recompile and inserting the module to kernel library module by themself. Here is the rpm I have made for KLIXs-2010 and they can be installed automatically using synaptic package manager or manually installed them using rpm :
{code type=css}
[root@jfklixs-domain noarch]# rpm -Uvh dkms-uvcvideo-0.1.0-6.svn263vflipklixs2010.noarch.rpm
Preparing… ########################################### [100%]
1:dkms-uvcvideo ########################################### [100%]
Creating symlink /var/lib/dkms/uvcvideo/0.1.0-6.svn263vflipklixs2010/source ->
/usr/src/uvcvideo-0.1.0-6.svn263vflipklixs2010
DKMS: add Completed.
Running KLIXs DKMS build routine. Please Wait….
Building module:
cleaning build area….
make KERNELRELEASE=2.6.27.31.jf5 -C /lib/modules/2.6.27.31.jf5/build SUBDIRS=/var/lib/dkms/uvcvideo/0.1.0-6.svn263vflipklixs2010/build modules……
cleaning build area….
DKMS: build Completed.
Running module version sanity check.
uvcvideo.ko.gz:
– Original module
– Found /lib/modules/2.6.27.31.jf5/kernel/drivers/media/video/uvc/uvcvideo.ko.gz
– Storing in /var/lib/dkms/uvcvideo/original_module/2.6.27.31.jf5/i586/
– Archiving for uninstallation purposes
– Installation
– Installing to /lib/modules/2.6.27.31.jf5/kernel/drivers/media/video/
depmod……
DKMS: install Completed.
[root@jfklixs-domain noarch]#
{/code}
Remember to reboot after install this dkms module so the patched uvcvideo module can reloading themself during boot.
For you who interested to do patch the uvcvideo module manually, here is the steps you should know :
1. Make sure the webcam was using the uvcvideo module before stepping further. By doing lsusb you can have the vendor and product code and invoke this command :
{code type=css}
lsusb -d xxxx:yyyy -v | grep “14 Video”
{/code}
If you’ve got the output like this :
{code type=css}[root@localhost user]# lsusb
Bus 001 Device 003: ID 0bda:0158 Realtek Semiconductor Corp. Mass Stroage Device
Bus 001 Device 002: ID 04f2:b071 Chicony Electronics Co., Ltd 2.0M UVC WebCam / CNF7129
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
[root@localhost user]# lsusb -d 04f2:b071 -v | grep “14 Video”
bFunctionClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
bInterfaceClass 14 Video
[root@localhost user]#{/code}
then you can go on reading, otherwise, your webcam must be not using uvcvideo and need a proprietary driver, there is nothing you can do here and try to find another reference.
2. Grab the latest uvcvideo trunk from svn
{code type=css}
svn checkout svn://svn.berlios.de/linux-uvc/linux-uvc/trunk
{/code}
3. Refer to uvc_video.c from the trunk folder, apply this patch :
{code type=css}— uvcvideo/uvc_video.c.org 2010-03-02 09:03:12.000000000 +0700
+++ uvcvideo/uvc_video.c 2010-03-01 11:38:51.000000000 +0700
@@ -424,23 +424,93 @@
return data[0];
}
+/* This patched function allows to overturn video images from an upside-down
+ * orientation to a normal one with mirrored effect. The conversion consists in
+ * reversing the order of the rows of imagines.
+ * “data” stores a sequence of pixels coming from the video source.
+ * This sequence is not a full frame or a full row of pixel, but just an
+ * ordered vector of pixels (from top-left to bottom-right), whose
+ * represents just an area of the current frame and which size (“nbytes”) is
+ * not constant. In fact this function has to be called hundreds of times
+ * before a frame is completed. Each time “data” contains the next part of the
+ * current frame (upside-down). At the end data stored in “mem” buffer will be
+ * used by the application who requested the video stream.
+ * No memory allocation is needed because pixel order is modified directly
+ * while copying from “data” into “mem” buffer (i.e. in each call of this
+ * function), and not just once when the frame is already completed.
+ * This patch should work with all YUV image formats.
+ * — JFDesign Patches —
+ */
static void uvc_video_decode_data(struct uvc_video_device *video,
struct uvc_buffer *buf, const __u8 *data, int len)
{
struct uvc_video_queue *queue = &video->queue;
unsigned int maxlen, nbytes;
void *mem;
+ /* Patch variables */
+ unsigned int row_size, to_be_copied, shift_right;
if (len <= 0)
return;
/* Copy the video data to the buffer. */
– maxlen = buf->buf.length – buf->buf.bytesused;
– mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
– nbytes = min((unsigned int)len, maxlen);
– memcpy(mem, data, nbytes);
– buf->buf.bytesused += nbytes;
–
+ /* How many bytes are needed to complete the buffer? */
+ maxlen = buf->buf.length – buf->buf.bytesused;
+ /* Where do pixels stored in “data” have to be copied? */
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ /* How many bytes really can be copied into “mem”? */
+ nbytes = min((unsigned int)len, maxlen);
+
+ /* “row_size” is the number of bytes required to store a full row of
+ * the frame.
+ */
+ row_size = video->streaming->cur_frame->wWidth *
+ video->streaming->format->bpp / 8;
+ /* Each loop “nbytes” is decremented of the number of bytes just copied.
+ * So are there any other bytes to be copied?
+ */
+ while (nbytes > 0) {
+ /* As the rows of modified frames have to be fulfilled from
+ * bottom-left to top-right, each cycle tries to complete a
+ * single row.
+ * In this cycle where is it needed to start to store bytes
+ * within the selected row? From the beginning or shifted
+ * right? Because other bytes could have been already stored in
+ * that row without completing it, so it could be needed a right
+ * shift.
+ */
+ shift_right = buf->buf.bytesused % row_size;
+ /* In this cycle how many byte can we copy in the selected row?
+ */
+ if (nbytes > row_size – shift_right)
+ to_be_copied = row_size – shift_right ;
+ else
+ to_be_copied = nbytes;
+ /* “queue->mem + buf->buf.m.offset” is the base-address where to
+ * start to store the current frame. This address refers to a
+ * preallocated area (just for a sigle frame) taking part in a
+ * circular buffer, where to store a fixed number of sequent
+ * frames.
+ */
+ memcpy(queue->mem + buf->buf.m.offset
+ /* Go to the end of this frame. */
+ + row_size * video->streaming->cur_frame->wHeight
+ /* Go back for the number of bytes corrisponding to the
+ * already fully completed rows.
+ */
+ – (buf->buf.bytesused – shift_right)
+ /* Go back at the starting point of the upper row. */
+ – row_size
+ /* Shift right on this row if it is needed. */
+ + shift_right,
+ data,
+ to_be_copied );
+ /* Update “data”, “byteused” and “nbytes” values. */
+ data += to_be_copied;
+ buf->buf.bytesused += to_be_copied ;
+ nbytes -= to_be_copied;
+ }
+
/* Complete the current frame if the buffer size was exceeded. */
if (len > maxlen) {
uvc_trace(UVC_TRACE_FRAME, “Frame complete (overflow).n”);{/code}
4. Then compile and insert the module :
{code type=css}[root@jfklixs-domain uvcvideo-trunk263]# make uvcvideo
Building USB Video Class driver…
make[1]: Entering directory `/usr/src/linux-2.6.27.31.jf5′
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_driver.o
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_queue.o
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_v4l2.o
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_video.o
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_ctrl.o
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_status.o
CC [M] /home/jfdesign/projects/uvcvideo-trunk263/uvc_isight.o
LD [M] /home/jfdesign/projects/uvcvideo-trunk263/uvcvideo.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/jfdesign/projects/uvcvideo-trunk263/uvcvideo.mod.o
LD [M] /home/jfdesign/projects/uvcvideo-trunk263/uvcvideo.ko
make[1]: Leaving directory `/usr/src/linux-2.6.27.31.jf5′
[root@jfklixs-domain uvcvideo-trunk263]# make install
[root@jfklixs-domain uvcvideo-trunk263]# depmod -ae
[root@jfklixs-domain uvcvideo-trunk263]# insmod uvcvideo.ko{/code}
The webcam now should show the right image.
Good luck and have fun.