diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2013-07-02 06:56:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-09-03 08:24:19 -0400 |
commit | 3080072460bb0efd156e415bfea783279bf64e92 (patch) | |
tree | f368022fb18e38a2d6ed9d27264fb6bd18d1ecc0 /drivers/media | |
parent | a19dec6ea94c036af68c31930c1c92681f55af41 (diff) |
[media] usbtv: Fix deinterlacing
The image data is laid out a bit more weirdly and thus needs more work to
properly interlace. What we get from hardware is V4L2_FIELD_ALTERNATE, but
since userspace support for it is practically nonexistent, thus we make
V4L2_FIELD_INTERLACED from it so that it's more easily interpreted.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/usb/usbtv/usbtv.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c index 095231608d25..55a45d34df22 100644 --- a/drivers/media/usb/usbtv/usbtv.c +++ b/drivers/media/usb/usbtv/usbtv.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #define USBTV_CHUNK_SIZE 256 | 56 | #define USBTV_CHUNK_SIZE 256 |
57 | #define USBTV_CHUNK 240 | 57 | #define USBTV_CHUNK 240 |
58 | #define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ | 58 | #define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ |
59 | / 2 / USBTV_CHUNK) | 59 | / 4 / USBTV_CHUNK) |
60 | 60 | ||
61 | /* Chunk header. */ | 61 | /* Chunk header. */ |
62 | #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ | 62 | #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ |
@@ -259,6 +259,26 @@ static int usbtv_setup_capture(struct usbtv *usbtv) | |||
259 | return 0; | 259 | return 0; |
260 | } | 260 | } |
261 | 261 | ||
262 | /* Copy data from chunk into a frame buffer, deinterlacing the data | ||
263 | * into every second line. Unfortunately, they don't align nicely into | ||
264 | * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels. | ||
265 | * Therefore, we break down the chunk into two halves before copyting, | ||
266 | * so that we can interleave a line if needed. */ | ||
267 | static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd) | ||
268 | { | ||
269 | int half; | ||
270 | |||
271 | for (half = 0; half < 2; half++) { | ||
272 | int part_no = chunk_no * 2 + half; | ||
273 | int line = part_no / 3; | ||
274 | int part_index = (line * 2 + !odd) * 3 + (part_no % 3); | ||
275 | |||
276 | u32 *dst = &frame[part_index * USBTV_CHUNK/2]; | ||
277 | memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src)); | ||
278 | src += USBTV_CHUNK/2; | ||
279 | } | ||
280 | } | ||
281 | |||
262 | /* Called for each 256-byte image chunk. | 282 | /* Called for each 256-byte image chunk. |
263 | * First word identifies the chunk, followed by 240 words of image | 283 | * First word identifies the chunk, followed by 240 words of image |
264 | * data and padding. */ | 284 | * data and padding. */ |
@@ -275,11 +295,6 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) | |||
275 | frame_id = USBTV_FRAME_ID(chunk); | 295 | frame_id = USBTV_FRAME_ID(chunk); |
276 | odd = USBTV_ODD(chunk); | 296 | odd = USBTV_ODD(chunk); |
277 | chunk_no = USBTV_CHUNK_NO(chunk); | 297 | chunk_no = USBTV_CHUNK_NO(chunk); |
278 | |||
279 | /* Deinterlace. TODO: Use interlaced frame format. */ | ||
280 | chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3; | ||
281 | chunk_no += !odd * 3; | ||
282 | |||
283 | if (chunk_no >= USBTV_CHUNKS) | 298 | if (chunk_no >= USBTV_CHUNKS) |
284 | return; | 299 | return; |
285 | 300 | ||
@@ -298,12 +313,11 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) | |||
298 | buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); | 313 | buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); |
299 | frame = vb2_plane_vaddr(&buf->vb, 0); | 314 | frame = vb2_plane_vaddr(&buf->vb, 0); |
300 | 315 | ||
301 | /* Copy the chunk. */ | 316 | /* Copy the chunk data. */ |
302 | memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1], | 317 | usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd); |
303 | USBTV_CHUNK * sizeof(chunk[1])); | ||
304 | 318 | ||
305 | /* Last chunk in a frame, signalling an end */ | 319 | /* Last chunk in a frame, signalling an end */ |
306 | if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) { | 320 | if (odd && chunk_no == USBTV_CHUNKS-1) { |
307 | int size = vb2_plane_size(&buf->vb, 0); | 321 | int size = vb2_plane_size(&buf->vb, 0); |
308 | 322 | ||
309 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; | 323 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; |
@@ -582,7 +596,7 @@ static int usbtv_queue_setup(struct vb2_queue *vq, | |||
582 | if (*nbuffers < 2) | 596 | if (*nbuffers < 2) |
583 | *nbuffers = 2; | 597 | *nbuffers = 2; |
584 | *nplanes = 1; | 598 | *nplanes = 1; |
585 | sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32); | 599 | sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32); |
586 | 600 | ||
587 | return 0; | 601 | return 0; |
588 | } | 602 | } |