diff options
author | Ian Armstrong <ian@iarmst.demon.co.uk> | 2007-11-05 12:27:09 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:03:11 -0500 |
commit | 77aded6ba51f01335840ce8e18b413067810b68e (patch) | |
tree | 2763dd287dd0f40bed5a1ba5262e0e13f58bf4e4 /drivers/media/video/ivtv/ivtv-ioctl.c | |
parent | 3b5c1c8e71eb8fe2297a5884db59108e3c8b44c5 (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.c | 120 |
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 | |||
490 | static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, | 489 | static 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 | } |