I am currently working on writing a free software replacement for the Galaxy S3 camera module, based on the Exynos Camera module I wrote a couple months ago for the Galaxy S2. Both are using V4L2, but the implementation differs in details. Especially, the Galaxy S3's back camera, the Samsung S5C73M3, uses an interleaved format for picture capture.
As an interleaved format, there is no standard and readily-usable implementation to decode the data. After searching for a long time, all I could find was a commit by one of Samsung's developers that introduced that format to mainline, through a LinuxTV patch. First of all, I can't seem to understand why such a patch was accepted mainline given that there is no decoder implementation for that format out there. Moreover, the only camera chip that uses it, the S5C73M3, has a driver that was also accepted in mainline. It seems to me like it was blindly included and nobody cared so much about how it works in practice. Moreover, it seems that this camera chip is mostly found in the Galaxy S3, and I doubt anyone tested mainline on the Galaxy S3 to see whether the S5C73M3 driver works and gives appropriate results.
However, let's not complain too much, that patch gave me crucial info to understand how to properly extract YUV and JPEG from the interleaved data. For reference, here are the explanations given with the patch:
Two-planar format used by Samsung S5C73MX cameras. The first plane contains interleaved JPEG and UYVY image data, followed by meta data in form of an array of offsets to the UYVY data blocks. The actual pointer array follows immediately the interleaved JPEG/UYVY data, the number of entries in this array equals the height of the UYVY image. Each entry is a 4-byte unsigned integer in big endian order and it's an offset to a single pixel line of the UYVY image. The first plane can start either with JPEG or UYVY data chunk. The size of a single UYVY block equals the UYVY image's width multiplied by 2. The size of a JPEG chunk depends on the image and can vary with each line. The second plane, at an offset of 4084 bytes, contains a 4-byte offset to the pointer array in the first plane. This offset is followed by a 4-byte value indicating size of the pointer array. All numbers in the second plane are also in big endian order. Remaining data in the second plane is undefined. The information in the second plane allows to easily find location of the pointer array, which can be different for each frame. The size of the pointer array is constant for given UYVY image height. In order to extract UYVY and JPEG frames an application can initially set a data pointer to the start of first plane and then add an offset from the first entry of the pointers table. Such a pointer indicates start of an UYVY image pixel line. Whole UYVY line can be copied to a separate buffer. These steps should be repeated for each line, i.e. the number of entries in the pointer array. Anything what's in between the UYVY lines is JPEG data and should be concatenated to form the JPEG stream.
At first, I was only getting the first 0xA00000 bytes, which is in fact only the first plane. Hence, I couldn't find the offset to that pointers array (even though I could locate it manually). I had to enable embeded data with the
V4L2_CID_EMBEDDEDDATA_ENABLE control. With that, the buffer gets 0x1000 more bytes: that's the second plane. Then by applying an offset of 4084 bytes to the start of that second plane, I could locate the offset to the pointers array.
Since I complained it was lacking, I wrote a reference implementation that separates the YUV (it's actually UYVY) and JPEG data from the interleaved format: s5c73m3_interleaved_decode.c.
2013-08-06 Update: As I sent an email to the Samsung developers involved in the mainline patch, I was given details on the format (that I already figured out though) as well as a C implementation to separate JPEG and UYVY. The developer also told me he is going to release sample code to decode the format, publicly. So I think things are going to be fine, and my criticism will soon no longer be valid. Yay!