Skip to content

Commit

Permalink
V4L/DVB (13430): cx18: Fix YUV capture so that encoder passes a singl…
Browse files Browse the repository at this point in the history
…e 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>
  • Loading branch information
Andy Walls authored and Mauro Carvalho Chehab committed Dec 5, 2009
1 parent 52fcb3e commit 22dce18
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 22 deletions.
49 changes: 37 additions & 12 deletions drivers/media/video/cx18/cx18-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ MODULE_PARM_DESC(enc_yuv_buffers,
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
MODULE_PARM_DESC(enc_yuv_bufsize,
"Size of an encoder YUV buffer (kB)\n"
"\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE));
"\t\t\tAllowed values are multiples of 33.75 kB rounded up\n"
"\t\t\t(multiples of size required for 32 screen lines)\n"
"\t\t\tDefault: 102");
MODULE_PARM_DESC(enc_yuv_bufs,
"Number of encoder YUV buffers\n"
"\t\t\tDefault is computed from other enc_yuv_* parameters");
Expand Down Expand Up @@ -499,10 +501,27 @@ static void cx18_process_options(struct cx18 *cx)
continue;
}
/*
* YUV is a special case where the stream_buf_size needs to be
* an integral multiple of 33.75 kB (storage for 32 screens
* lines to maintain alignment in case of lost buffers
*/
if (i == CX18_ENC_STREAM_TYPE_YUV) {
cx->stream_buf_size[i] *= 1024;
cx->stream_buf_size[i] -=
(cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE);

if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE)
cx->stream_buf_size[i] =
CX18_UNIT_ENC_YUV_BUFSIZE;
}
/*
* YUV is a special case where the stream_buf_size is
* now in bytes.
* VBI is a special case where the stream_buf_size is fixed
* and already in bytes
*/
if (i == CX18_ENC_STREAM_TYPE_VBI) {
if (i == CX18_ENC_STREAM_TYPE_VBI ||
i == CX18_ENC_STREAM_TYPE_YUV) {
if (cx->stream_buffers[i] < 0) {
cx->stream_buffers[i] =
cx->options.megabytes[i] * 1024 * 1024
Expand All @@ -513,18 +532,24 @@ static void cx18_process_options(struct cx18 *cx)
cx->stream_buffers[i]
* cx->stream_buf_size[i]/(1024 * 1024);
}
continue;
}
/* All other streams have stream_buf_size in kB at this point */
if (cx->stream_buffers[i] < 0) {
cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
/ cx->stream_buf_size[i];
} else {
/* N.B. This might round down to 0 */
cx->options.megabytes[i] =
cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024;
/* All other streams have stream_buf_size in kB here */
if (cx->stream_buffers[i] < 0) {
cx->stream_buffers[i] =
cx->options.megabytes[i] * 1024
/ cx->stream_buf_size[i];
} else {
/* N.B. This might round down to 0 */
cx->options.megabytes[i] =
cx->stream_buffers[i]
* cx->stream_buf_size[i] / 1024;
}
/* convert from kB to bytes */
cx->stream_buf_size[i] *= 1024;
}
cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, "
"%d bytes\n", i, cx->options.megabytes[i],
cx->stream_buffers[i], cx->stream_buf_size[i]);
}

cx->options.cardtype = cardtype[cx->instance];
Expand Down
7 changes: 6 additions & 1 deletion drivers/media/video/cx18/cx18-driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,16 @@
/* Maximum firmware DMA buffers per stream */
#define CX18_MAX_FW_MDLS_PER_STREAM 63

/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */
#define CX18_UNIT_ENC_YUV_BUFSIZE (720 * 32 * 3 / 2) /* bytes */
#define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32)
#define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32)

/* DMA buffer, default size in kB allocated */
#define CX18_DEFAULT_ENC_TS_BUFSIZE 32
#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32
#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32
#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128
#define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1)
/* Default VBI bufsize based on standards supported by card tuner for now */
#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4

Expand Down
5 changes: 3 additions & 2 deletions drivers/media/video/cx18/cx18-dvb.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,10 @@ int cx18_dvb_register(struct cx18_stream *stream)
dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);

CX18_INFO("DVB Frontend registered\n");
CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n",
CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
stream->dvb.dvb_adapter.num, stream->name,
stream->buffers, stream->buf_size/1024);
stream->buffers, stream->buf_size/1024,
(stream->buf_size * 100 / 1024) % 100);

mutex_init(&dvb->feedlock);
dvb->enabled = 1;
Expand Down
6 changes: 4 additions & 2 deletions drivers/media/video/cx18/cx18-queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,11 @@ int cx18_stream_alloc(struct cx18_stream *s)
if (s->buffers == 0)
return 0;

CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n",
CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers "
"(%d.%02d kB total)\n",
s->name, s->buffers, s->buf_size,
s->buffers * s->buf_size / 1024);
s->buffers * s->buf_size / 1024,
(s->buffers * s->buf_size * 100 / 1024) % 100);

if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] -
(char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
Expand Down
26 changes: 21 additions & 5 deletions drivers/media/video/cx18/cx18-streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type)

switch (vfl_type) {
case VFL_TYPE_GRABBER:
CX18_INFO("Registered device video%d for %s (%d x %d kB)\n",
CX18_INFO("Registered device video%d for %s "
"(%d x %d.%02d kB)\n",
num, s->name, cx->stream_buffers[type],
cx->stream_buf_size[type]/1024);
cx->stream_buf_size[type] / 1024,
(cx->stream_buf_size[type] * 100 / 1024) % 100);
break;

case VFL_TYPE_RADIO:
Expand Down Expand Up @@ -501,9 +503,23 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
{
cx18_unload_queues(s);

/* For now */
s->bufs_per_mdl = 1;
s->mdl_size = s->buf_size * s->bufs_per_mdl;
switch (s->type) {
case CX18_ENC_STREAM_TYPE_YUV:
/*
* Height should be a multiple of 32 lines.
* Set the MDL size to the exact size needed for one frame.
* Use enough buffers per MDL to cover the MDL size
*/
s->mdl_size = 720 * s->cx->params.height * 3 / 2;
s->bufs_per_mdl = s->mdl_size / s->buf_size;
if (s->mdl_size % s->buf_size)
s->bufs_per_mdl++;
break;
default:
s->bufs_per_mdl = 1;
s->mdl_size = s->buf_size * s->bufs_per_mdl;
break;
}

cx18_load_queues(s);
}
Expand Down

0 comments on commit 22dce18

Please sign in to comment.