#include "ivtv-queue.h"
#include "ivtv-fileops.h"
#include "ivtv-vbi.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
+#include "ivtv-routing.h"
#include "ivtv-streams.h"
#include "ivtv-yuv.h"
#include "ivtv-ioctl.h"
{
ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
- ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key);
+ ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);
}
int ivtv_set_speed(struct ivtv *itv, int speed)
fmt->fmt.pix.height = itv->main_rect.height;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
- if (itv->output_mode == OUT_UDMA_YUV) {
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
case IVTV_YUV_MODE_INTERLACED:
fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
break;
}
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+ fmt->fmt.pix.bytesperline = 720;
+ fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
+ fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
- fmt->fmt.pix.height * fmt->fmt.pix.width +
- fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
- }
- else if (itv->output_mode == OUT_YUV ||
- streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
- streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ 1080 * ((fmt->fmt.pix.height + 31) & ~31);
+ } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
- fmt->fmt.win.chromakey = itv->osd_color_key;
+ fmt->fmt.win.chromakey = itv->osd_chroma_key;
fmt->fmt.win.global_alpha = itv->osd_global_alpha;
break;
static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
struct v4l2_format *fmt, int set_fmt)
{
+ struct yuv_playback_info *yi = &itv->yuv_info;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
u16 set;
r.width = fmt->fmt.pix.width;
r.height = fmt->fmt.pix.height;
ivtv_get_fmt(itv, streamtype, fmt);
- if (itv->output_mode != OUT_UDMA_YUV) {
- /* TODO: would setting the rect also be valid for this mode? */
- fmt->fmt.pix.width = r.width;
- fmt->fmt.pix.height = r.height;
- }
- if (itv->output_mode == OUT_UDMA_YUV) {
- /* TODO: add checks for validity */
+ fmt->fmt.pix.width = r.width;
+ fmt->fmt.pix.height = r.height;
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
fmt->fmt.pix.field = field;
+ if (fmt->fmt.pix.width < 2)
+ fmt->fmt.pix.width = 2;
+ if (fmt->fmt.pix.width > 720)
+ fmt->fmt.pix.width = 720;
+ if (fmt->fmt.pix.height < 2)
+ fmt->fmt.pix.height = 2;
+ if (fmt->fmt.pix.height > 576)
+ fmt->fmt.pix.height = 576;
}
- if (set_fmt) {
- if (itv->output_mode == OUT_UDMA_YUV) {
- switch (field) {
- case V4L2_FIELD_NONE:
- itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
- break;
- case V4L2_FIELD_ANY:
- itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
- break;
- case V4L2_FIELD_INTERLACED_BT:
- itv->yuv_info.lace_mode =
- IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
- break;
- case V4L2_FIELD_INTERLACED_TB:
- default:
- itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
- break;
- }
- itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+ if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ /* Return now if we already have some frame data */
+ if (yi->stream_size)
+ return -EBUSY;
- /* Force update of yuv registers */
- itv->yuv_info.yuv_forced_update = 1;
- return 0;
+ yi->v4l2_src_w = r.width;
+ yi->v4l2_src_h = r.height;
+
+ switch (field) {
+ case V4L2_FIELD_NONE:
+ yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+ break;
+ case V4L2_FIELD_ANY:
+ yi->lace_mode = IVTV_YUV_MODE_AUTO;
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ yi->lace_mode =
+ IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+ break;
+ case V4L2_FIELD_INTERLACED_TB:
+ default:
+ yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+ break;
}
+ yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+ if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+ itv->dma_data_req_size =
+ 1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+ /* Force update of yuv registers */
+ yi->yuv_forced_update = 1;
+ return 0;
}
return 0;
}
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
if (set_fmt) {
- itv->osd_color_key = fmt->fmt.win.chromakey;
+ itv->osd_chroma_key = fmt->fmt.win.chromakey;
itv->osd_global_alpha = fmt->fmt.win.global_alpha;
ivtv_set_osd_alpha(itv);
}
/* set window size */
if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ struct cx2341x_mpeg_params *p = &itv->params;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
- if (!set_fmt || (itv->params.width == w && itv->params.height == h))
+ if (!set_fmt || (p->width == w && p->height == h))
return 0;
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
- itv->params.width = w;
- itv->params.height = h;
+ p->width = w;
+ p->height = h;
if (w != 720 || h != (itv->is_50hz ? 576 : 480))
- itv->params.video_temporal_filter = 0;
+ p->video_temporal_filter = 0;
else
- itv->params.video_temporal_filter = 8;
+ p->video_temporal_filter = 8;
+ if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ fmt->fmt.pix.width /= 2;
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
return ivtv_get_fmt(itv, streamtype, fmt);
}
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
- struct v4l2_chip_ident *chip = arg;
-
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
- }
return 0;
}
if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
- ivtv_audio_set_route(itv, route);
+ ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
break;
}
ivtv_reset_ir_gpio(itv);
}
if (val & 0x02) {
- itv->video_dec_func(itv, cmd, 0);
+ itv->video_dec_func(itv, cmd, NULL);
}
break;
}
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
{
struct ivtv_open_id *id = NULL;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int streamtype = 0;
- if (filp) id = (struct ivtv_open_id *)filp->private_data;
+ if (filp) {
+ id = (struct ivtv_open_id *)filp->private_data;
+ streamtype = id->type;
+ }
switch (cmd) {
case VIDIOC_G_PRIORITY:
cropcap->bounds.height = itv->is_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+ } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ cropcap->bounds.width = itv->yuv_info.osd_full_w;
+ cropcap->bounds.height = itv->yuv_info.osd_full_h;
+ cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
} else {
cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
- if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
- crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
- itv->main_rect = crop->c;
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+ itv->yuv_info.main_rect = crop->c;
return 0;
+ } else {
+ if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+ crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+ itv->main_rect = crop->c;
+ return 0;
+ }
}
return -EINVAL;
}
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
- crop->c = itv->main_rect;
+ if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+ crop->c = itv->yuv_info.main_rect;
+ else
+ crop->c = itv->main_rect;
return 0;
}
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
case VIDIOC_ENUM_FMT: {
static struct v4l2_fmtdesc formats[] = {
{ 0, 0, 0,
- "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+ "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
{ 0, 0, 0, 0 }
},
{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
itv->main_rect.height = itv->params.height;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
+ itv->yuv_info.main_rect = itv->main_rect;
+ if (!itv->osd_info) {
+ itv->yuv_info.osd_full_w = 720;
+ itv->yuv_info.osd_full_h =
+ itv->is_out_50hz ? 576 : 480;
+ }
}
break;
}
case VIDIOC_G_FBUF: {
struct v4l2_framebuffer *fb = arg;
+ int pixfmt;
+ static u32 pixel_format[16] = {
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+ V4L2_PIX_FMT_RGB565,
+ V4L2_PIX_FMT_RGB555,
+ V4L2_PIX_FMT_RGB444,
+ V4L2_PIX_FMT_RGB32,
+ 0,
+ 0,
+ 0,
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+ V4L2_PIX_FMT_YUV565,
+ V4L2_PIX_FMT_YUV555,
+ V4L2_PIX_FMT_YUV444,
+ V4L2_PIX_FMT_YUV32,
+ 0,
+ 0,
+ 0,
+ };
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
- V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
- fb->fmt.pixelformat = itv->osd_pixelformat;
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ pixfmt = (data[0] >> 3) & 0xf;
+ fb->fmt.pixelformat = pixel_format[pixfmt];
fb->fmt.width = itv->osd_rect.width;
fb->fmt.height = itv->osd_rect.height;
fb->base = (void *)itv->osd_video_pbase;
+ if (itv->osd_chroma_key_state)
+ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
if (itv->osd_global_alpha_state)
fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
- if (itv->osd_local_alpha_state)
- fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
- if (itv->osd_color_key_state)
- fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ pixfmt &= 7;
+ /* no local alpha for RGB565 or unknown formats */
+ if (pixfmt == 1 || pixfmt > 4)
+ break;
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+ else
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
+ if (itv->osd_local_alpha_state) {
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+ else
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ }
break;
}
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
- itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
- itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+ itv->osd_local_alpha_state =
+ (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+ itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
ivtv_set_osd_alpha(itv);
break;
}
case VIDIOC_LOG_STATUS:
{
int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
- u32 data[CX2341X_MBOX_MAX_DATA];
struct v4l2_input vidin;
struct v4l2_audio audin;
int i;
struct v4l2_output vidout;
struct v4l2_audioout audout;
int mode = itv->output_mode;
- static const char * const output_modes[] = {
+ static const char * const output_modes[5] = {
"None",
"MPEG Streaming",
"YUV Streaming",
"YUV Frames",
"Passthrough",
};
- static const char * const audio_modes[] = {
+ static const char * const audio_modes[5] = {
"Stereo",
"Left",
"Right",
"Mono",
"Swapped"
};
- static const char * const alpha_mode[] = {
+ static const char * const alpha_mode[4] = {
"None",
"Global",
"Local",
"Global and Local"
};
- static const char * const pixel_format[] = {
- "Indexed",
+ static const char * const pixel_format[16] = {
+ "ARGB Indexed",
"RGB 5:6:5",
"ARGB 1:5:5:5",
"ARGB 1:4:4:4",
"5",
"6",
"7",
+ "AYUV Indexed",
+ "YUV 5:6:5",
+ "AYUV 1:5:5:5",
+ "AYUV 1:4:4:4",
+ "AYUV 8:8:8:8",
+ "13",
+ "14",
+ "15",
};
ivtv_get_output(itv, itv->active_output, &vidout);
mode = OUT_NONE;
IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
data[0] & 1 ? "On" : "Off",
alpha_mode[(data[0] >> 1) & 0x3],
- pixel_format[(data[0] >> 3) & 0x7]);
+ pixel_format[(data[0] >> 3) & 0xf]);
}
IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");