aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-11-09 21:55:30 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:41:52 -0500
commit22dce188ef3e1e058ceabe3b3072640d7568f764 (patch)
tree6a5ee29e5b7cdf9125bea7456c8de75ab0861b92
parent52fcb3ecc6707f52dfe4297f96b7609d4ba517fb (diff)
V4L/DVB (13430): cx18: Fix YUV capture so that encoder passes a single frame per transfer
Fix YUV capture such that the encoder will pass one frame per transfer. This will allow the application to maintain frame alignment when a transfer from the encoder is missed due to high system latency in service the CX23418 IRQ. Also force YUV buffer sizes to be specified in multiples of 33.75 kB, the smalled amount of buffer sizes need to store a complete set of HM12 4:2:0 macroblocks specifying 32 lines of the frame. A full 60Hz/525 line screen requires 15 * 33.75 kB per frame and a full 50Hz/625 line screen requires 18 * 33.75 kB per frame so the default buffer size is 3 * 33.75 kB, requiring exactly 5 or 6 buffers per MDL respectively. The bytes needed per frame and hence MDL need not be the bytes in an integer number of buffers. However, if frame artifacts are seen with scaled screen sizes, the YUV buffer size can be set 34 kB (33.75 kB) to get rid of the artifacts at the cost of more copies between the kernel and userspace. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/cx18/cx18-driver.c49
-rw-r--r--drivers/media/video/cx18/cx18-driver.h7
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c5
-rw-r--r--drivers/media/video/cx18/cx18-queue.c6
-rw-r--r--drivers/media/video/cx18/cx18-streams.c26
5 files changed, 71 insertions, 22 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index ba4c3ceffbb3..87a735f1ee9e 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -211,7 +211,9 @@ MODULE_PARM_DESC(enc_yuv_buffers,
211 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); 211 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
212MODULE_PARM_DESC(enc_yuv_bufsize, 212MODULE_PARM_DESC(enc_yuv_bufsize,
213 "Size of an encoder YUV buffer (kB)\n" 213 "Size of an encoder YUV buffer (kB)\n"
214 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE)); 214 "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
215 "\t\t\t(multiples of size required for 32 screen lines)\n"
216 "\t\t\tDefault: 102");
215MODULE_PARM_DESC(enc_yuv_bufs, 217MODULE_PARM_DESC(enc_yuv_bufs,
216 "Number of encoder YUV buffers\n" 218 "Number of encoder YUV buffers\n"
217 "\t\t\tDefault is computed from other enc_yuv_* parameters"); 219 "\t\t\tDefault is computed from other enc_yuv_* parameters");
@@ -499,10 +501,27 @@ static void cx18_process_options(struct cx18 *cx)
499 continue; 501 continue;
500 } 502 }
501 /* 503 /*
504 * YUV is a special case where the stream_buf_size needs to be
505 * an integral multiple of 33.75 kB (storage for 32 screens
506 * lines to maintain alignment in case of lost buffers
507 */
508 if (i == CX18_ENC_STREAM_TYPE_YUV) {
509 cx->stream_buf_size[i] *= 1024;
510 cx->stream_buf_size[i] -=
511 (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);
512
513 if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
514 cx->stream_buf_size[i] =
515 CX18_UNIT_ENC_YUV_BUFSIZE;
516 }
517 /*
518 * YUV is a special case where the stream_buf_size is
519 * now in bytes.
502 * VBI is a special case where the stream_buf_size is fixed 520 * VBI is a special case where the stream_buf_size is fixed
503 * and already in bytes 521 * and already in bytes
504 */ 522 */
505 if (i == CX18_ENC_STREAM_TYPE_VBI) { 523 if (i == CX18_ENC_STREAM_TYPE_VBI ||
524 i == CX18_ENC_STREAM_TYPE_YUV) {
506 if (cx->stream_buffers[i] < 0) { 525 if (cx->stream_buffers[i] < 0) {
507 cx->stream_buffers[i] = 526 cx->stream_buffers[i] =
508 cx->options.megabytes[i] * 1024 * 1024 527 cx->options.megabytes[i] * 1024 * 1024
@@ -513,18 +532,24 @@ static void cx18_process_options(struct cx18 *cx)
513 cx->stream_buffers[i] 532 cx->stream_buffers[i]
514 * cx->stream_buf_size[i]/(1024 * 1024); 533 * cx->stream_buf_size[i]/(1024 * 1024);
515 } 534 }
516 continue;
517 }
518 /* All other streams have stream_buf_size in kB at this point */
519 if (cx->stream_buffers[i] < 0) {
520 cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
521 / cx->stream_buf_size[i];
522 } else { 535 } else {
523 /* N.B. This might round down to 0 */ 536 /* All other streams have stream_buf_size in kB here */
524 cx->options.megabytes[i] = 537 if (cx->stream_buffers[i] < 0) {
525 cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024; 538 cx->stream_buffers[i] =
539 cx->options.megabytes[i] * 1024
540 / cx->stream_buf_size[i];
541 } else {
542 /* N.B. This might round down to 0 */
543 cx->options.megabytes[i] =
544 cx->stream_buffers[i]
545 * cx->stream_buf_size[i] / 1024;
546 }
547 /* convert from kB to bytes */
548 cx->stream_buf_size[i] *= 1024;
526 } 549 }
527 cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */ 550 CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, "
551 "%d bytes\n", i, cx->options.megabytes[i],
552 cx->stream_buffers[i], cx->stream_buf_size[i]);
528 } 553 }
529 554
530 cx->options.cardtype = cardtype[cx->instance]; 555 cx->options.cardtype = cardtype[cx->instance];
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index bed8bcc65411..5c78b014dbc0 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -120,11 +120,16 @@
120/* Maximum firmware DMA buffers per stream */ 120/* Maximum firmware DMA buffers per stream */
121#define CX18_MAX_FW_MDLS_PER_STREAM 63 121#define CX18_MAX_FW_MDLS_PER_STREAM 63
122 122
123/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */
124#define CX18_UNIT_ENC_YUV_BUFSIZE (720 * 32 * 3 / 2) /* bytes */
125#define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32)
126#define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32)
127
123/* DMA buffer, default size in kB allocated */ 128/* DMA buffer, default size in kB allocated */
124#define CX18_DEFAULT_ENC_TS_BUFSIZE 32 129#define CX18_DEFAULT_ENC_TS_BUFSIZE 32
125#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 130#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32
126#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32 131#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32
127#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128 132#define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1)
128/* Default VBI bufsize based on standards supported by card tuner for now */ 133/* Default VBI bufsize based on standards supported by card tuner for now */
129#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 134#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4
130 135
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 54a6fd3f7af5..71ad2d1b4c2c 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -362,9 +362,10 @@ int cx18_dvb_register(struct cx18_stream *stream)
362 dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); 362 dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
363 363
364 CX18_INFO("DVB Frontend registered\n"); 364 CX18_INFO("DVB Frontend registered\n");
365 CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n", 365 CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
366 stream->dvb.dvb_adapter.num, stream->name, 366 stream->dvb.dvb_adapter.num, stream->name,
367 stream->buffers, stream->buf_size/1024); 367 stream->buffers, stream->buf_size/1024,
368 (stream->buf_size * 100 / 1024) % 100);
368 369
369 mutex_init(&dvb->feedlock); 370 mutex_init(&dvb->feedlock);
370 dvb->enabled = 1; 371 dvb->enabled = 1;
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index c1a49ecf9d98..98cbf001f8da 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -348,9 +348,11 @@ int cx18_stream_alloc(struct cx18_stream *s)
348 if (s->buffers == 0) 348 if (s->buffers == 0)
349 return 0; 349 return 0;
350 350
351 CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n", 351 CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers "
352 "(%d.%02d kB total)\n",
352 s->name, s->buffers, s->buf_size, 353 s->name, s->buffers, s->buf_size,
353 s->buffers * s->buf_size / 1024); 354 s->buffers * s->buf_size / 1024,
355 (s->buffers * s->buf_size * 100 / 1024) % 100);
354 356
355 if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] - 357 if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] -
356 (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { 358 (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 9f8adda6f261..7755937fc521 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -262,9 +262,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
262 262
263 switch (vfl_type) { 263 switch (vfl_type) {
264 case VFL_TYPE_GRABBER: 264 case VFL_TYPE_GRABBER:
265 CX18_INFO("Registered device video%d for %s (%d x %d kB)\n", 265 CX18_INFO("Registered device video%d for %s "
266 "(%d x %d.%02d kB)\n",
266 num, s->name, cx->stream_buffers[type], 267 num, s->name, cx->stream_buffers[type],
267 cx->stream_buf_size[type]/1024); 268 cx->stream_buf_size[type] / 1024,
269 (cx->stream_buf_size[type] * 100 / 1024) % 100);
268 break; 270 break;
269 271
270 case VFL_TYPE_RADIO: 272 case VFL_TYPE_RADIO:
@@ -501,9 +503,23 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
501{ 503{
502 cx18_unload_queues(s); 504 cx18_unload_queues(s);
503 505
504 /* For now */ 506 switch (s->type) {
505 s->bufs_per_mdl = 1; 507 case CX18_ENC_STREAM_TYPE_YUV:
506 s->mdl_size = s->buf_size * s->bufs_per_mdl; 508 /*
509 * Height should be a multiple of 32 lines.
510 * Set the MDL size to the exact size needed for one frame.
511 * Use enough buffers per MDL to cover the MDL size
512 */
513 s->mdl_size = 720 * s->cx->params.height * 3 / 2;
514 s->bufs_per_mdl = s->mdl_size / s->buf_size;
515 if (s->mdl_size % s->buf_size)
516 s->bufs_per_mdl++;
517 break;
518 default:
519 s->bufs_per_mdl = 1;
520 s->mdl_size = s->buf_size * s->bufs_per_mdl;
521 break;
522 }
507 523
508 cx18_load_queues(s); 524 cx18_load_queues(s);
509} 525}