From 39446d1c76c5ebb42b424060c502ba0a57494476 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 5 Nov 2007 18:27:09 +0100 Subject: ivtv: Initial merge of video48 yuv handling into the IVTV_IOC_DMA_FRAME framework From: Ian Armstrong Previously, all yuv data written to /dev/video48 had only basic support with no double buffering to avoid display tearing. With this patch, yuv frames written to video48 are now handled by the existing IVTV_IOC_DMA_FRAME framework. As such, the frames are hardware buffered to avoid tearing, and honour scaling mode & field order options. Unlike the proprietary IVTV_IOC_DMA_FRAME ioctl, all parameters are controlled by the V4L2 API. Due to mpeg & yuv output restrictions being different, their V4L2 output controls have been separated. To control the yuv output, the V4L2 calls must be done via video48. If the ivtvfb module is loaded, there will be one side effect to this merge. The yuv output window will be constrained to the visible framebuffer area. In the event that a virtual framebuffer size is being used, the limit to the output size will be the virtual dimensions, but only the portion that falls within the currently visible area of the framebuffer will be shown. Like the IVTV_IOC_DMA_FRAME ioctl, the supplied frames must be padded to 720 pixels wide. However the height must only be padded up the nearest multiple of 32. This would mean an image of 102 lines must be padded to 128. As long as the true source image size is given, the padding will not be visible in the final output. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-fileops.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video/ivtv/ivtv-fileops.c') diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index 58ad0d9c6..6fb96f19a 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -581,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c set_bit(IVTV_F_S_APPL_IO, &s->s_flags); retry: + /* If possible, just DMA the entire frame - Check the data transfer size + since we may get here before the stream has been fully set-up */ + if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { + while (count >= itv->dma_data_req_size) { + if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) { + bytes_written += itv->dma_data_req_size; + user_buf += itv->dma_data_req_size; + count -= itv->dma_data_req_size; + } else { + break; + } + } + if (count == 0) { + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + return bytes_written; + } + } + for (;;) { /* Gather buffers */ while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) @@ -660,6 +678,9 @@ retry: if (s->q_full.length >= itv->dma_data_req_size) { int got_sig; + if (mode == OUT_YUV) + ivtv_yuv_setup_stream_frame(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (!(got_sig = signal_pending(current)) && test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { @@ -946,7 +967,7 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); /* For yuv, we need to know the dma size before we start */ itv->dma_data_req_size = - itv->params.width * itv->params.height * 3 / 2; + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); itv->yuv_info.stream_size = 0; } return 0; -- cgit v1.2.3