#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/videodev2.h>
-#include <linux/i2c.h>
#include <media/tuner.h>
#include <media/cx2341x.h>
V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
V4L2_CID_MPEG_AUDIO_EMPHASIS,
V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_CID_MPEG_AUDIO_MUTE,
V4L2_CID_MPEG_VIDEO_ENCODING,
V4L2_CID_MPEG_VIDEO_ASPECT,
V4L2_CID_MPEG_VIDEO_B_FRAMES,
V4L2_CID_MPEG_VIDEO_GOP_SIZE,
V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- V4L2_CID_MPEG_VIDEO_PULLDOWN,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_CID_MPEG_VIDEO_BITRATE,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ V4L2_CID_MPEG_VIDEO_MUTE,
+ V4L2_CID_MPEG_VIDEO_MUTE_YUV,
V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
0
};
case V4L2_CID_MPEG_AUDIO_CRC:
ctrl->value = params->audio_crc;
break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ ctrl->value = params->audio_mute;
+ break;
case V4L2_CID_MPEG_VIDEO_ENCODING:
ctrl->value = params->video_encoding;
break;
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
ctrl->value = params->video_gop_closure;
break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- ctrl->value = params->video_pulldown;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
ctrl->value = params->video_bitrate_mode;
break;
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
ctrl->value = params->video_temporal_decimation;
break;
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ ctrl->value = params->video_mute;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+ ctrl->value = params->video_mute_yuv;
+ break;
case V4L2_CID_MPEG_STREAM_TYPE:
ctrl->value = params->stream_type;
break;
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
ctrl->value = params->video_chroma_median_filter_bottom;
break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ ctrl->value = params->stream_insert_nav_packets;
+ break;
default:
return -EINVAL;
}
/* Map the control ID to the correct field in the cx2341x_mpeg_params
struct. Return -EINVAL if the ID is unknown, else return 0. */
-static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ if (busy)
+ return -EBUSY;
params->audio_sampling_freq = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
params->audio_encoding = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ if (busy)
+ return -EBUSY;
params->audio_l2_bitrate = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_MODE:
case V4L2_CID_MPEG_AUDIO_CRC:
params->audio_crc = ctrl->value;
break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ params->audio_mute = ctrl->value;
+ break;
case V4L2_CID_MPEG_VIDEO_ASPECT:
params->video_aspect = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
params->video_gop_closure = ctrl->value;
break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- params->video_pulldown = ctrl->value;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (busy)
+ return -EBUSY;
/* MPEG-1 only allows CBR */
if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
params->video_bitrate_mode = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
+ if (busy)
+ return -EBUSY;
params->video_bitrate = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ if (busy)
+ return -EBUSY;
params->video_bitrate_peak = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
params->video_temporal_decimation = ctrl->value;
break;
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ params->video_mute = (ctrl->value != 0);
+ break;
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+ params->video_mute_yuv = ctrl->value;
+ break;
case V4L2_CID_MPEG_STREAM_TYPE:
+ if (busy)
+ return -EBUSY;
params->stream_type = ctrl->value;
params->video_encoding =
(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
params->video_chroma_median_filter_bottom = ctrl->value;
break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ params->stream_insert_nav_packets = ctrl->value;
+ break;
default:
return -EINVAL;
}
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
name = "Median Chroma Filter Minimum";
break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ name = "Insert Navigation Packets";
+ break;
default:
return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
min = 0;
step = 1;
break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ min = 0;
+ max = 1;
+ step = 1;
+ break;
default:
qctrl->type = V4L2_CTRL_TYPE_INTEGER;
break;
qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
return 0;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
default:
return v4l2_ctrl_query_fill_std(qctrl);
(params->audio_crc << 14);
}
-int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_controls *ctrls, unsigned int cmd)
{
int err = 0;
err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
if (err)
break;
- err = cx2341x_set_ctrl(params, ctrl);
+ err = cx2341x_set_ctrl(params, busy, ctrl);
if (err)
break;
}
/* stream */
.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ .stream_insert_nav_packets = 0,
/* audio */
.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+ .audio_mute = 0,
/* video */
.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
.video_b_frames = 2,
.video_gop_size = 12,
.video_gop_closure = 1,
- .video_pulldown = 0,
.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
.video_bitrate = 6000000,
.video_bitrate_peak = 8000000,
.video_temporal_decimation = 0,
+ .video_mute = 0,
+ .video_mute_yuv = 0x008080, /* YCbCr value for black */
/* encoding filters */
.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
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;
}
err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
if (err) return err;
+ }
+ if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
/* 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.
+ a ghosting effect). So if the capture window is scaled, then
+ force the filter to 0.
- For full resolution a setting of 8 really improves the video
+ For full resolution the filter 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;
- }
+ temporal = 0;
}
if (old == NULL || old->stream_type != new->stream_type) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
if (err) return err;
}
- if (old == NULL || old->video_pulldown != new->video_pulldown) {
- err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
- if (err) return err;
- }
if (old == NULL || old->audio_properties != new->audio_properties) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
if (err) return err;
}
+ if (old == NULL || old->audio_mute != new->audio_mute) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
+ if (err) return err;
+ }
if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
old->video_bitrate != new->video_bitrate ||
old->video_bitrate_peak != new->video_bitrate_peak) {
new->video_temporal_decimation);
if (err) return err;
}
+ if (old == NULL || old->video_mute != new->video_mute ||
+ (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
+ if (err) return err;
+ }
+ if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
+ if (err) return err;
+ }
return 0;
}
void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
{
int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ int temporal = p->video_temporal_filter;
/* Stream */
- printk(KERN_INFO "%s: Stream: %s\n",
+ printk(KERN_INFO "%s: Stream: %s",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+ if (p->stream_insert_nav_packets)
+ printk(" (with navigation packets)");
+ printk("\n");
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",
+ printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
prefix,
p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
- p->is_50hz ? 25 : 30);
+ p->is_50hz ? 25 : 30,
+ (p->video_mute) ? " (muted)" : "");
printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
printk(", Peak %d", p->video_bitrate_peak);
}
printk("\n");
- printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+ printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
prefix,
p->video_gop_size, p->video_b_frames,
- p->video_gop_closure ? "" : "No ",
- p->video_pulldown ? "" : "No ");
+ p->video_gop_closure ? "" : "No ");
if (p->video_temporal_decimation) {
printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
prefix, p->video_temporal_decimation);
}
/* Audio */
- printk(KERN_INFO "%s: Audio: %s, %s, %s, %s",
+ printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
- cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
+ p->audio_mute ? " (muted)" : "");
if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
printk(", %s",
cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
p->video_spatial_filter);
+ if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
+ temporal = 0;
+ }
printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
- p->video_temporal_filter);
+ temporal);
printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),