Skip to main content

Color is back

I should have read the kernel driver sources carefully:

static int pxa_cam_WCAM_VIDIOCSNIGHTMODE(p_camera_context_t cam_ctx, void * param)
{
    struct {u32 mode, maxexpotime; } cam_mode;
    u32 maxexpotime;
...

Picture. Now with colors. Will write a detailed description on how to use A1200 driver interface later.

/galleries/dropbox/picture0004.jpg

:)

One-line Footer in OpenOffice.org Writer

Update: Ted has provided a great hint about the “normal” way to remove the last paragraph:

There’s an easier way to do this, as documented here. Go to the end, ie place the text cursor after the last character, of the last cell of the table and press CTRL-SHIFT-DELETE. Presumably this trick works under all operating systems and not just Ubuntu Linux.

Thanks, Ted!

Old content was removed.

Ogg Vorbis on MING

So it turned to be just a matter of time. Ogg Vorbis support is possible in Motorola’s a1200. I was able to play test files. Now I’ve got another problem. While playing ogg vorbis, CPU frequency increases 3 times the original and vorbis decoding takes all the CPU. The sound becomes distorted as if buffer underruns occur. MP3 decoding (programmed by RealOne) makes CPU frequency increase up to 2 times. So it looks like default Ogg Vorbis decoder is not well suited for embedded systems therefore some alternative approach is needed. I guess it is time to take a look on Tremor, integer only decoder designed especially for such kind of devices.

Update: I found a thread that perfectly matches our requirements: [Xiph-dev] CR-Client: add Tremor support to vorbisrend. Unfortunately it is not known what revision “SVN HEAD of Tremor” was used and the current HEAD API is not that compatible.

P.S. It is possible that such resource consumption forced Motorola’s engineers to omit Ogg Vorbis support from their package.

OpenMoko under QEMU

Yep, I know, I should be studying and doing some university assignments, no fun.

But now I have my new tamagotchi thing much much better than The Sims – my new pet is an emulated Neo 1973 phone. The screenshot shows my desktop while I am having some intimate conversation through ssh connection to the emulated device.

P.S. Man, I gotta get a new laptop – the current one (Aspire 3000LC/1800MHz Sempron/1280 DDR RAM) is too slow to be the phone ☺.

/galleries/dropbox/openmoko-qemu.thumbnail.png

Come in, you beep

My girlfriend has bought a jacket in Metro mall a while ago. Yesterday we went into music records store and the RFID detector beeped. During next 5 minutes we were standing near the detector to figure out what exactly causes this behavior. It turned out that one little sticker with barcode was forgotten to be removed by the shop assistants so that could probably cause some annoying looks and questions from the security of every other shop.

I recalled someone’s post that if you wrap the RFID tag with a foil it will fail to be powered by the scanners and thus will not be able to send the ID. So I took Orbit chewing gum pack, put the tag on it and passed all the scanners w/o any trouble.

It does not mean I want to steal anything but looks like every security feature has its flaws. You can read more about RFID at wikipedia: http://en.wikipedia.org/wiki/RFID.

DESTROY your exit()

Recently we’ve been facing an interesting problem. Even if we used ‘die()’, the exit code of the script remained 0, that is, “success”. Several hours of careful debugging of our script and nothing special was discovered.

The next day started with tries to reproduce that and in the end we had this:

package Bug::Destroy::System;
sub new {
    my $pkg = shift;
    bless {}, $pkg;
}

sub DESTROY {
    # we need to call some system routine
    system("echo hello");
}

package main;
my $t = Bug::Destroy::System->new();
die "Oh, no, bad thing happened!";

You can try it on your system, it will exit with 0 provided that your system has the “echo” command.

The whole thing happens because of global $? variable which gets modified by system(), so first you have die() that sets $? to 1, then the destructors start to be executed, one of them calls system() that modifies $? to 0 as echo has succeeded. Then the script exits with whatever is in $?, i.e. 0. Pretty straightforward, you know?

In order to minimize the consequences, always do local() on your $? in DESTROY block. You’ll save a lot of time.

MOTOMING: Performance Issues

So, I’ve got the camera working in video capture mode, in 320×240 and lower resolutions. The colorspace conversion is done by IJG libjpeg with some minor byte swapping in my code.

Here’s what I get when the frames are concatenated together:

The target media seems to be lost upon migration

Now comes an interesting part. The image captured using camera-only data is pretty dark and low color. I’ve checked the colorspace conversion routines and they are ok, the camera gives out this kind of image. On the contrary, the phone itself shows vivid colors and the image is not dark at all given the same conditions. So there must be some color-brightness post-processing code that makes all these fancy things. I’m not an expert in image processing but the way mentioned looks like the only one the phone can create such nice pictures.

But there is one disappointing fact — the image writing bottleneck. If you use A1200 and capture video, you may see that the resulting stream is not uniform, i.e. some frames are running smooth but eventually (every 6th or so) frame is dropped. Now I know why that happens – on this very moment of time the stream is written to the storage, be it SD/MMC card or internal phone memory. This forces some frames to be dropped.

I’m not ready to create Motion-JPEG files yet but it looks like multiple buffers and extremely optimized code to copy memory regions from mmaped driver area to userspace are needed.

It is a shame, but this is the first time in my life I faced the real, noticeable performance degradation while using double-precision calculations as opposed to integer only. Sometimes you need to see your code running on low speed CPU to understand that every fancy thing has its price.

Sony-Ericsson phone fails to save pictures and files

If your phone is Sony-Ericsson and you see the following symptoms:

  • Failure to download files via bluetooth (memory full)
  • Camera photos are not saved

Do not reformat your card right away – it may not be guilty. The reason for such behavior may be the “read-only” flag set for some of your folders. Connect your phone to transfer files via USB and clear this flag for all files and folders on your phone and card volumes.

Unfortunately this has to be done from Windows host system as I have no idea how linux vfat layer maps r/o rights to unix permissions, and I don’t care :)

When strace is not enough

I’ve got START_VIDEO working, I got the colorspace converted, I emulated all ioctls() ezx camera is sending and even got the picture. But it looks like the mmaped area is read before or after the synchronization happens.

The first time I read the image after camera app finishes it comes pretty good, all subsequent attempts result in a broken image. So I decided to dig more into the data camera app passes through ioctl.

I found just what I needed: Using LD_PRELOAD libraries and glibc backtrace function for debugging by Scary Reasoner. This will allow not only camera app to be investigated but… mmm… much, much more. BTW, read() on camera interface usually gives you a random piece of memory, so use mmap()ed region instead.

Update: Here is the promised trace:

# LD_PRELOAD=./libwrapioctl.so.1.0 /usr/SYSqtapp/camera/camera
ioctl : wrapping ioctl
next_ioctl = 0x4112b480
ioctl: wrapping done
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
ioctl WCAM_VIDIOCSINFOR: { val1=15, val2=16 }
ioctl WCAM_VIDIOCSBUFCOUNT: 4
ioctl WCAM_VIDIOCSFLICKER: 50
ioctl WCAM_VIDIOCSFPS: { minfps=30, maxfps=30 }
ioctl WCAM_VIDIOCSMIRROR: 0
ioctl WCAM_VIDIOCSNIGHTMODE: 0
ioctl WCAM_VIDIOCSBRIGHT: 0
ioctl WCAM_VIDIOCSLIGHT: 0
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
ioctl WCAM_VIDIOCSSTYLE: 0
QLinuxFbDoubleScreen::flip() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::flip() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
ioctl WCAM_VIDIOCSJPEGQUALITY: 6
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x42525f58, flags=0x44960000 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl WCAM_VIDIOCSBRIGHT: 1
ioctl WCAM_VIDIOCSBRIGHT: 2
ioctl WCAM_VIDIOCSBRIGHT: 3
ioctl WCAM_VIDIOCSBRIGHT: 4
ioctl WCAM_VIDIOCSBRIGHT: 3
ioctl WCAM_VIDIOCSBRIGHT: 2
ioctl WCAM_VIDIOCSBRIGHT: 1
ioctl WCAM_VIDIOCSBRIGHT: 0
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 358
ioctl WCAM_VIDIOCSSZOOM: 358
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 512
ioctl WCAM_VIDIOCSSZOOM: 512
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 717
ioctl WCAM_VIDIOCSSZOOM: 717
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=572, h=430 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 1024
ioctl WCAM_VIDIOCSSZOOM: 1024
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=400, h=300 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 1280
ioctl WCAM_VIDIOCSSZOOM: 1434
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=286, h=214 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 1280
ioctl WCAM_VIDIOCSSZOOM: 2048
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=200, h=150 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 1280
ioctl WCAM_VIDIOCSSZOOM: 1434
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=286, h=214 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 1024
ioctl WCAM_VIDIOCSSZOOM: 1024
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=400, h=300 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 717
ioctl WCAM_VIDIOCSSZOOM: 717
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=572, h=430 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 512
ioctl WCAM_VIDIOCSSZOOM: 512
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x64000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 358
ioctl WCAM_VIDIOCSSZOOM: 358
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x44960000, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
QLinuxFbDoubleScreen::flip() called, but flipping disabled
QLinuxFbDoubleScreen::redirectQtToBack() called, but flipping disabled
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=180, height=240,
chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=900, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=180, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=1600, h=1200 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=1024, h=768 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=1600, h=1200 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=1024, h=768 }
ioctl VIDIOCSWIN: {  x=0x107, y=0x40002118, width=320, height=240, chromakey=0xd9, clipcount=0x40002234, flags=0x400021c8 }
ioctl WCAM_VIDIOCSSSIZE: { w=1600, h=1200 }
ioctl WCAM_VIDIOCSZOOM: 256
ioctl WCAM_VIDIOCSSZOOM: 256
ioctl WCAM_VIDIOCSOSIZE: { w=320, h=240 }
ioctl WCAM_VIDIOCSCSIZE: { w=640, h=480 }
ioctl WCAM_VIDIOCSNIGHTMODE: 1
ioctl WCAM_VIDIOCSNIGHTMODE: 0
ioctl WCAM_VIDIOCSSTYLE: 1
ioctl WCAM_VIDIOCSSTYLE: 2
ioctl WCAM_VIDIOCSSTYLE: 3
ioctl WCAM_VIDIOCSSTYLE: 4
ioctl WCAM_VIDIOCSSTYLE: 0
ioctl WCAM_VIDIOCSLIGHT: 1
ioctl WCAM_VIDIOCSLIGHT: 2
ioctl WCAM_VIDIOCSLIGHT: 3
ioctl WCAM_VIDIOCSLIGHT: 0
destroy ShareImage Object
UTIL_ShareImage::destroy()
UTIL_ShareImage::destroy() : data detched

Time to sleep…

MOTOMING Camera: More V4L Bytes

According to the tests, the CIF cannot convert the data that comes from camera module contrary to what pxa_camera.h is telling us and CIF works with RAW data only. But camera produces images in different colorspaces. Having read some Intel PXA27x white papers I acquired the power to capture the real images…

/galleries/dropbox/a1200_caming_test1.jpg

The sensor settings are incorrect and the colorspace conversion from YCbCr 4:2:2 to RGB888 does not use the second Y value, but I think this is a nice start :).

Update: There seems to be yet another application for the camera called camcap but I am not sure that the sources are available. I have also found code for video capture and it appears to produce results, but I was not able to decode the results to a viewable movie. I do not like the EZX-based approach because while it provides greater integration with the phone functions, the code will not be used in openmoko running on a1200 :). And I really hope to get it running on my phone and running fully featured… :)