From 5c79cc3a436672df39875565419126381b3f778f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Aug 2006 08:05:17 +0200 Subject: Add missing v4l2_buf_type to struct v4l2_sliced_vbi_cap. --- linux/include/linux/videodev2.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h index 9eccad749..a2c663daf 100644 --- a/linux/include/linux/videodev2.h +++ b/linux/include/linux/videodev2.h @@ -1203,7 +1203,8 @@ struct v4l2_sliced_vbi_cap (equals frame lines 313-336 for 625 line video standards, 263-286 for 525 line standards) */ __u16 service_lines[2][24]; - __u32 reserved[4]; /* must be 0 */ + enum v4l2_buf_type type; + __u32 reserved[3]; /* must be 0 */ }; struct v4l2_sliced_vbi_data -- cgit v1.2.3 From 9f92cbb8f321d094a6276bd64f3a53913aa62937 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Aug 2006 08:17:58 +0200 Subject: Add u32 argument to VIDIOC_INT_RESET. From: Hans Verkuil The extra argument makes it possible to reset subsystems of a chip if that is supported. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/em28xx/em28xx-video.c | 2 +- linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 2 +- linux/drivers/media/video/v4l2-common.c | 1 + linux/include/media/v4l2-common.h | 5 +++-- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index e7a104098..6aaafc023 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -196,7 +196,7 @@ static void em28xx_config_i2c(struct em28xx *dev) route.input = INPUT(dev->ctl_input)->vmux; route.output = 0; - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index c80c26be6..df8feac16 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -221,7 +221,7 @@ static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt, static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt) { int ret; - ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL); + ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0); pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret); } diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 47b932809..e6c821745 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -969,6 +969,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) case VIDIOC_INT_AUDIO_CLOCK_FREQ: case VIDIOC_INT_I2S_CLOCK_FREQ: case VIDIOC_INT_S_STANDBY: + case VIDIOC_INT_RESET: { u32 *p=arg; diff --git a/linux/include/media/v4l2-common.h b/linux/include/media/v4l2-common.h index 98976fd3b..ca40bca45 100644 --- a/linux/include/media/v4l2-common.h +++ b/linux/include/media/v4l2-common.h @@ -175,8 +175,9 @@ enum v4l2_chip_ident { #define VIDIOC_INT_S_REGISTER _IOR ('d', 100, struct v4l2_register) #define VIDIOC_INT_G_REGISTER _IOWR('d', 101, struct v4l2_register) -/* Reset the I2C chip */ -#define VIDIOC_INT_RESET _IO ('d', 102) +/* Generic reset command. The argument selects which subsystems to reset. + Passing 0 will always reset the whole chip. */ +#define VIDIOC_INT_RESET _IOW ('d', 102, u32) /* Set the frequency (in Hz) of the audio clock output. Used to slave an audio processor to the video decoder, ensuring that audio -- cgit v1.2.3 From 64c4c22a50a776b1fcd46f2cec0e82e6d6a21ec2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Aug 2006 10:00:12 +0200 Subject: Add YUV HM12 and VBI IVTV format documentation. From: Hans Verkuil README.hm12: documentation on the HM12 YUV format used by the cx23415/6 chip. README.vbi: documentation on the V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI format used in MPEG streams. Signed-off-by: Hans Verkuil --- .../Documentation/video4linux/cx2341x/README.hm12 | 116 +++++++++++++++++++++ linux/Documentation/video4linux/cx2341x/README.vbi | 45 ++++++++ 2 files changed, 161 insertions(+) create mode 100644 linux/Documentation/video4linux/cx2341x/README.hm12 create mode 100644 linux/Documentation/video4linux/cx2341x/README.vbi (limited to 'linux') diff --git a/linux/Documentation/video4linux/cx2341x/README.hm12 b/linux/Documentation/video4linux/cx2341x/README.hm12 new file mode 100644 index 000000000..0e213ed09 --- /dev/null +++ b/linux/Documentation/video4linux/cx2341x/README.hm12 @@ -0,0 +1,116 @@ +The cx23416 can produce (and the cx23415 can also read) raw YUV output. The +format of a YUV frame is specific to this chip and is called HM12. 'HM' stands +for 'Hauppauge Macroblock', which is a misnomer as 'Conexant Macroblock' would +be more accurate. + +The format is YUV 4:2:0 which uses 1 Y byte per pixel and 1 U and V byte per +four pixels. + +The data is encoded as two macroblock planes, the first containing the Y +values, the second containing UV macroblocks. + +The Y plane is divided into blocks of 16x16 pixels from left to right +and from top to bottom. Each block is transmitted in turn, line-by-line. + +So the first 16 bytes are the first line of the top-left block, the +second 16 bytes are the second line of the top-left block, etc. After +transmitting this block the first line of the block on the right to the +first block is transmitted, etc. + +The UV plane is divided into blocks of 16x8 UV values going from left +to right, top to bottom. Each block is transmitted in turn, line-by-line. + +So the first 16 bytes are the first line of the top-left block and +contain 8 UV value pairs (16 bytes in total). The second 16 bytes are the +second line of 8 UV pairs of the top-left block, etc. After transmitting +this block the first line of the block on the right to the first block is +transmitted, etc. + +The code below is given as an example on how to convert HM12 to separate +Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels. + +The width of a frame is always 720 pixels, regardless of the actual specified +width. + +-------------------------------------------------------------------------- + +#include +#include +#include + +static unsigned char frame[576*720*3/2]; +static unsigned char framey[576*720]; +static unsigned char frameu[576*720 / 4]; +static unsigned char framev[576*720 / 4]; + +static void de_macro_y(unsigned char* dst, unsigned char *src, int dstride, int w, int h) +{ + unsigned int y, x, i; + + // descramble Y plane + // dstride = 720 = w + // The Y plane is divided into blocks of 16x16 pixels + // Each block in transmitted in turn, line-by-line. + for (y = 0; y < h; y += 16) { + for (x = 0; x < w; x += 16) { + for (i = 0; i < 16; i++) { + memcpy(dst + x + (y + i) * dstride, src, 16); + src += 16; + } + } + } +} + +static void de_macro_uv(unsigned char *dstu, unsigned char *dstv, unsigned char *src, int dstride, int w, int h) +{ + unsigned int y, x, i; + + // descramble U/V plane + // dstride = 720 / 2 = w + // The U/V values are interlaced (UVUV...). + // Again, the UV plane is divided into blocks of 16x16 UV values. + // Each block in transmitted in turn, line-by-line. + for (y = 0; y < h; y += 16) { + for (x = 0; x < w; x += 8) { + for (i = 0; i < 16; i++) { + int idx = x + (y + i) * dstride; + + dstu[idx+0] = src[0]; dstv[idx+0] = src[1]; + dstu[idx+1] = src[2]; dstv[idx+1] = src[3]; + dstu[idx+2] = src[4]; dstv[idx+2] = src[5]; + dstu[idx+3] = src[6]; dstv[idx+3] = src[7]; + dstu[idx+4] = src[8]; dstv[idx+4] = src[9]; + dstu[idx+5] = src[10]; dstv[idx+5] = src[11]; + dstu[idx+6] = src[12]; dstv[idx+6] = src[13]; + dstu[idx+7] = src[14]; dstv[idx+7] = src[15]; + src += 16; + } + } + } +} + +/*************************************************************************/ +int main(int argc, char **argv) +{ + FILE *fin; + int i; + + if (argc == 1) fin = stdin; + else fin = fopen(argv[1], "r"); + + if (fin == NULL) { + fprintf(stderr, "cannot open input\n"); + exit(-1); + } + while (fread(frame, sizeof(frame), 1, fin) == 1) { + de_macro_y(framey, frame, 720, 720, 576); + de_macro_uv(frameu, framev, frame + 720 * 576, 720 / 2, 720 / 2, 576 / 2); + fwrite(framey, sizeof(framey), 1, stdout); + fwrite(framev, sizeof(framev), 1, stdout); + fwrite(frameu, sizeof(frameu), 1, stdout); + } + fclose(fin); + return 0; +} + +-------------------------------------------------------------------------- diff --git a/linux/Documentation/video4linux/cx2341x/README.vbi b/linux/Documentation/video4linux/cx2341x/README.vbi new file mode 100644 index 000000000..5807cf156 --- /dev/null +++ b/linux/Documentation/video4linux/cx2341x/README.vbi @@ -0,0 +1,45 @@ + +Format of embedded V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data +========================================================= + +This document describes the V4L2_MPEG_STREAM_VBI_FMT_IVTV format of the VBI data +embedded in an MPEG-2 program stream. This format is in part dictated by some +hardware limitations of the ivtv driver (the driver for the Conexant cx23415/6 +chips), in particular a maximum size for the VBI data. Anything longer is cut +off when the MPEG stream is played back through the cx23415. + +The advantage of this format is it is very compact and that all VBI data for +all lines can be stored while still fitting within the maximum allowed size. + +The stream ID of the VBI data is 0xBD. The maximum size of the embedded data is +4 + 43 * 36, which is 4 bytes for a header and 2 * 18 VBI lines with a 1 byte +header and a 42 bytes payload each. Anything beyond this limit is cut off by +the cx23415/6 firmware. Besides the data for the VBI lines we also need 36 bits +for a bitmask determining which lines are captured and 4 bytes for a magic cookie, +signifying that this data package contains V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data. +If all lines are used, then there is no longer room for the bitmask. To solve this +two different magic numbers were introduced: + +'itv0': After this magic number two unsigned longs follow. Bits 0-17 of the first +unsigned long denote which lines of the first field are captured. Bits 18-31 of +the first unsigned long and bits 0-3 of the second unsigned long are used for the +second field. + +'ITV0': This magic number assumes all VBI lines are captured, i.e. it implicitly +implies that the bitmasks are 0xffffffff and 0xf. + +After these magic cookies (and the 8 byte bitmask in case of cookie 'itv0') the +captured VBI lines start: + +For each line the least significant 4 bits of the first byte contain the data type. +Possible values are shown in the table below. The payload is in the following 42 +bytes. + +Here is the list of possible data types: + +#define IVTV_SLICED_TYPE_TELETEXT 0x1 // Teletext (uses lines 6-22 for PAL) +#define IVTV_SLICED_TYPE_CC 0x4 // Closed Captions (line 21 NTSC) +#define IVTV_SLICED_TYPE_WSS 0x5 // Wide Screen Signal (line 23 PAL) +#define IVTV_SLICED_TYPE_VPS 0x7 // Video Programming System (PAL) (line 16) + +Hans Verkuil -- cgit v1.2.3 From e62da4f3647592717616864fd8e60b7f27566953 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 28 Aug 2006 00:22:15 +0200 Subject: Better temporal filter handling. From: Hans Verkuil Adjust temporal filter if necessary. The problem with the temporal filter is that it works well with full resolution capturing, but not when the capture window is scaled (the filter introduces a ghosting effect). So if the capture window changed, and there is no updated filter value, then the filter is set depending on whether the new window is full resolution or not. For full resolution a setting of 8 really improves the video quality, especially if the original video quality is suboptimal. Also report VBI Format in VIDIOC_LOG_STATUS, it was missing. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/cx2341x.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c index f4da970a0..8fc5dc0b5 100644 --- a/linux/drivers/media/video/cx2341x.c +++ b/linux/drivers/media/video/cx2341x.c @@ -695,7 +695,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - .video_temporal_filter = 0, + .video_temporal_filter = 8, .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, .video_luma_median_filter_top = 255, .video_luma_median_filter_bottom = 0, @@ -735,6 +735,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, }; int err = 0; + u16 temporal = new->video_temporal_filter; cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); @@ -745,6 +746,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, if (old == NULL || old->width != new->width || old->height != new->height || old->video_encoding != new->video_encoding) { + int is_scaling; u16 w = new->width; u16 h = new->height; @@ -754,6 +756,20 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, } err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); if (err) return err; + + /* Adjust temporal filter if necessary. The problem with the temporal + filter is that it works well with full resolution capturing, but + not when the capture window is scaled (the filter introduces + a ghosting effect). So if the capture window changed, and there is + no updated filter value, then the filter is set depending on whether + the new window is full resolution or not. + + For full resolution a setting of 8 really improves the video + quality, especially if the original video quality is suboptimal. */ + is_scaling = new->width != 720 || new->height != (new->is_50hz ? 576 : 480); + if (old && old->video_temporal_filter == temporal) { + temporal = is_scaling ? 0 : 8; + } } if (old == NULL || old->stream_type != new->stream_type) { @@ -819,9 +835,9 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, } if (old == NULL || old->video_spatial_filter != new->video_spatial_filter || - old->video_temporal_filter != new->video_temporal_filter) { + old->video_temporal_filter != temporal) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, - new->video_spatial_filter, new->video_temporal_filter); + new->video_spatial_filter, temporal); if (err) return err; } if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) { @@ -859,6 +875,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) printk(KERN_INFO "%s: Stream: %s\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); + printk(KERN_INFO "%s: VBI Format: %s\n", + prefix, + cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); /* Video */ printk(KERN_INFO "%s: Video: %dx%d, %d fps\n", -- cgit v1.2.3