diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2013-07-02 06:56:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-07-26 09:29:52 -0400 |
commit | a34cacab1565fdee77544b12407274ffb4d9daa0 (patch) | |
tree | e5a8bd2aa38281401f3be684edae3e3b59daf6b4 /drivers/media | |
parent | 81913283c80be8c0b7e038c26e2a611ab38394f1 (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>
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 bf43f874685e..9dcc677f3015 100644 --- a/drivers/media/usb/usbtv/usbtv.c +++ b/drivers/media/usb/usbtv/usbtv.c | |||
@@ -57,7 +57,7 @@ | |||
57 | #define USBTV_CHUNK_SIZE 256 | 57 | #define USBTV_CHUNK_SIZE 256 |
58 | #define USBTV_CHUNK 240 | 58 | #define USBTV_CHUNK 240 |
59 | #define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ | 59 | #define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ |
60 | / 2 / USBTV_CHUNK) | 60 | / 4 / USBTV_CHUNK) |
61 | 61 | ||
62 | /* Chunk header. */ | 62 | /* Chunk header. */ |
63 | #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ | 63 | #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ |
@@ -202,6 +202,26 @@ static int usbtv_setup_capture(struct usbtv *usbtv) | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | /* Copy data from chunk into a frame buffer, deinterlacing the data | ||
206 | * into every second line. Unfortunately, they don't align nicely into | ||
207 | * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels. | ||
208 | * Therefore, we break down the chunk into two halves before copyting, | ||
209 | * so that we can interleave a line if needed. */ | ||
210 | static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd) | ||
211 | { | ||
212 | int half; | ||
213 | |||
214 | for (half = 0; half < 2; half++) { | ||
215 | int part_no = chunk_no * 2 + half; | ||
216 | int line = part_no / 3; | ||
217 | int part_index = (line * 2 + !odd) * 3 + (part_no % 3); | ||
218 | |||
219 | u32 *dst = &frame[part_index * USBTV_CHUNK/2]; | ||
220 | memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src)); | ||
221 | src += USBTV_CHUNK/2; | ||
222 | } | ||
223 | } | ||
224 | |||
205 | /* Called for each 256-byte image chunk. | 225 | /* Called for each 256-byte image chunk. |
206 | * First word identifies the chunk, followed by 240 words of image | 226 | * First word identifies the chunk, followed by 240 words of image |
207 | * data and padding. */ | 227 | * data and padding. */ |
@@ -218,11 +238,6 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) | |||
218 | frame_id = USBTV_FRAME_ID(chunk); | 238 | frame_id = USBTV_FRAME_ID(chunk); |
219 | odd = USBTV_ODD(chunk); | 239 | odd = USBTV_ODD(chunk); |
220 | chunk_no = USBTV_CHUNK_NO(chunk); | 240 | chunk_no = USBTV_CHUNK_NO(chunk); |
221 | |||
222 | /* Deinterlace. TODO: Use interlaced frame format. */ | ||
223 | chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3; | ||
224 | chunk_no += !odd * 3; | ||
225 | |||
226 | if (chunk_no >= USBTV_CHUNKS) | 241 | if (chunk_no >= USBTV_CHUNKS) |
227 | return; | 242 | return; |
228 | 243 | ||
@@ -241,12 +256,11 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) | |||
241 | buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); | 256 | buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list); |
242 | frame = vb2_plane_vaddr(&buf->vb, 0); | 257 | frame = vb2_plane_vaddr(&buf->vb, 0); |
243 | 258 | ||
244 | /* Copy the chunk. */ | 259 | /* Copy the chunk data. */ |
245 | memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1], | 260 | usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd); |
246 | USBTV_CHUNK * sizeof(chunk[1])); | ||
247 | 261 | ||
248 | /* Last chunk in a frame, signalling an end */ | 262 | /* Last chunk in a frame, signalling an end */ |
249 | if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) { | 263 | if (odd && chunk_no == USBTV_CHUNKS-1) { |
250 | int size = vb2_plane_size(&buf->vb, 0); | 264 | int size = vb2_plane_size(&buf->vb, 0); |
251 | 265 | ||
252 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; | 266 | buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; |
@@ -518,7 +532,7 @@ static int usbtv_queue_setup(struct vb2_queue *vq, | |||
518 | if (*nbuffers < 2) | 532 | if (*nbuffers < 2) |
519 | *nbuffers = 2; | 533 | *nbuffers = 2; |
520 | *nplanes = 1; | 534 | *nplanes = 1; |
521 | sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32); | 535 | sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32); |
522 | 536 | ||
523 | return 0; | 537 | return 0; |
524 | } | 538 | } |