aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtv-ioctl.c
diff options
context:
space:
mode:
authorIan Armstrong <ian@iarmst.demon.co.uk>2007-11-05 12:27:09 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:03:11 -0500
commit77aded6ba51f01335840ce8e18b413067810b68e (patch)
tree2763dd287dd0f40bed5a1ba5262e0e13f58bf4e4 /drivers/media/video/ivtv/ivtv-ioctl.c
parent3b5c1c8e71eb8fe2297a5884db59108e3c8b44c5 (diff)
V4L/DVB (6717): ivtv: Initial merge of video48 yuv handling into the IVTV_IOC_DMA_FRAME framework
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 <ian@iarmst.demon.co.uk> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-ioctl.c')
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c120
1 files changed, 78 insertions, 42 deletions
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index fd6826f472e3..57eb8dfe53fa 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
372 fmt->fmt.pix.height = itv->main_rect.height; 372 fmt->fmt.pix.height = itv->main_rect.height;
373 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 373 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
374 fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; 374 fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
375 if (itv->output_mode == OUT_UDMA_YUV) { 375 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
376 switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { 376 switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
377 case IVTV_YUV_MODE_INTERLACED: 377 case IVTV_YUV_MODE_INTERLACED:
378 fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? 378 fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
@@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
386 break; 386 break;
387 } 387 }
388 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; 388 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
389 fmt->fmt.pix.bytesperline = 720;
390 fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
391 fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
389 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ 392 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
390 fmt->fmt.pix.sizeimage = 393 fmt->fmt.pix.sizeimage =
391 fmt->fmt.pix.height * fmt->fmt.pix.width + 394 1080 * ((fmt->fmt.pix.height + 31) & ~31);
392 fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); 395 } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
393 }
394 else if (itv->output_mode == OUT_YUV ||
395 streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
396 streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
397 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; 396 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
398 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ 397 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
399 fmt->fmt.pix.sizeimage = 398 fmt->fmt.pix.sizeimage =
@@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
490static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, 489static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
491 struct v4l2_format *fmt, int set_fmt) 490 struct v4l2_format *fmt, int set_fmt)
492{ 491{
492 struct yuv_playback_info *yi = &itv->yuv_info;
493 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 493 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
494 u16 set; 494 u16 set;
495 495
@@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
505 r.width = fmt->fmt.pix.width; 505 r.width = fmt->fmt.pix.width;
506 r.height = fmt->fmt.pix.height; 506 r.height = fmt->fmt.pix.height;
507 ivtv_get_fmt(itv, streamtype, fmt); 507 ivtv_get_fmt(itv, streamtype, fmt);
508 if (itv->output_mode != OUT_UDMA_YUV) { 508 fmt->fmt.pix.width = r.width;
509 /* TODO: would setting the rect also be valid for this mode? */ 509 fmt->fmt.pix.height = r.height;
510 fmt->fmt.pix.width = r.width; 510 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
511 fmt->fmt.pix.height = r.height;
512 }
513 if (itv->output_mode == OUT_UDMA_YUV) {
514 /* TODO: add checks for validity */
515 fmt->fmt.pix.field = field; 511 fmt->fmt.pix.field = field;
512 if (fmt->fmt.pix.width < 2)
513 fmt->fmt.pix.width = 2;
514 if (fmt->fmt.pix.width > 720)
515 fmt->fmt.pix.width = 720;
516 if (fmt->fmt.pix.height < 2)
517 fmt->fmt.pix.height = 2;
518 if (fmt->fmt.pix.height > 576)
519 fmt->fmt.pix.height = 576;
516 } 520 }
517 if (set_fmt) { 521 if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
518 if (itv->output_mode == OUT_UDMA_YUV) { 522 /* Return now if we already have some frame data */
519 switch (field) { 523 if (yi->stream_size)
520 case V4L2_FIELD_NONE: 524 return -EBUSY;
521 itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
522 break;
523 case V4L2_FIELD_ANY:
524 itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
525 break;
526 case V4L2_FIELD_INTERLACED_BT:
527 itv->yuv_info.lace_mode =
528 IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
529 break;
530 case V4L2_FIELD_INTERLACED_TB:
531 default:
532 itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
533 break;
534 }
535 itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
536 525
537 /* Force update of yuv registers */ 526 yi->v4l2_src_w = r.width;
538 itv->yuv_info.yuv_forced_update = 1; 527 yi->v4l2_src_h = r.height;
539 return 0; 528
529 switch (field) {
530 case V4L2_FIELD_NONE:
531 yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
532 break;
533 case V4L2_FIELD_ANY:
534 yi->lace_mode = IVTV_YUV_MODE_AUTO;
535 break;
536 case V4L2_FIELD_INTERLACED_BT:
537 yi->lace_mode =
538 IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
539 break;
540 case V4L2_FIELD_INTERLACED_TB:
541 default:
542 yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
543 break;
540 } 544 }
545 yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
546
547 if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
548 itv->dma_data_req_size =
549 1080 * ((yi->v4l2_src_h + 31) & ~31);
550
551 /* Force update of yuv registers */
552 yi->yuv_forced_update = 1;
553 return 0;
541 } 554 }
542 return 0; 555 return 0;
543 } 556 }
@@ -703,8 +716,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
703{ 716{
704 struct ivtv_open_id *id = NULL; 717 struct ivtv_open_id *id = NULL;
705 u32 data[CX2341X_MBOX_MAX_DATA]; 718 u32 data[CX2341X_MBOX_MAX_DATA];
719 int streamtype = 0;
706 720
707 if (filp) id = (struct ivtv_open_id *)filp->private_data; 721 if (filp) {
722 id = (struct ivtv_open_id *)filp->private_data;
723 streamtype = id->type;
724 }
708 725
709 switch (cmd) { 726 switch (cmd) {
710 case VIDIOC_G_PRIORITY: 727 case VIDIOC_G_PRIORITY:
@@ -822,6 +839,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
822 cropcap->bounds.height = itv->is_50hz ? 576 : 480; 839 cropcap->bounds.height = itv->is_50hz ? 576 : 480;
823 cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; 840 cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
824 cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; 841 cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
842 } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
843 cropcap->bounds.width = itv->yuv_info.osd_full_w;
844 cropcap->bounds.height = itv->yuv_info.osd_full_h;
845 cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
846 cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
825 } else { 847 } else {
826 cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; 848 cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
827 cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; 849 cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
@@ -836,10 +858,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
836 858
837 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && 859 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
838 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { 860 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
839 if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 861 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
840 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { 862 itv->yuv_info.main_rect = crop->c;
841 itv->main_rect = crop->c;
842 return 0; 863 return 0;
864 } else {
865 if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
866 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
867 itv->main_rect = crop->c;
868 return 0;
869 }
843 } 870 }
844 return -EINVAL; 871 return -EINVAL;
845 } 872 }
@@ -853,7 +880,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
853 880
854 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && 881 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
855 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { 882 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
856 crop->c = itv->main_rect; 883 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
884 crop->c = itv->yuv_info.main_rect;
885 else
886 crop->c = itv->main_rect;
857 return 0; 887 return 0;
858 } 888 }
859 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 889 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -864,7 +894,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
864 case VIDIOC_ENUM_FMT: { 894 case VIDIOC_ENUM_FMT: {
865 static struct v4l2_fmtdesc formats[] = { 895 static struct v4l2_fmtdesc formats[] = {
866 { 0, 0, 0, 896 { 0, 0, 0,
867 "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, 897 "HM12 (YUV 4:2:2)", V4L2_PIX_FMT_HM12,
868 { 0, 0, 0, 0 } 898 { 0, 0, 0, 0 }
869 }, 899 },
870 { 1, 0, V4L2_FMT_FLAG_COMPRESSED, 900 { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
@@ -1043,6 +1073,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
1043 itv->main_rect.height = itv->params.height; 1073 itv->main_rect.height = itv->params.height;
1044 ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 1074 ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
1045 720, itv->main_rect.height, 0, 0); 1075 720, itv->main_rect.height, 0, 0);
1076 itv->yuv_info.main_rect = itv->main_rect;
1077 if (!itv->osd_info) {
1078 itv->yuv_info.osd_full_w = 720;
1079 itv->yuv_info.osd_full_h =
1080 itv->is_out_50hz ? 576 : 480;
1081 }
1046 } 1082 }
1047 break; 1083 break;
1048 } 1084 }