Commit 86b79d66 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (4197): Port new MPEG API to saa7134-empress with saa6752hs

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent f022156b
...@@ -39,6 +39,23 @@ enum saa6752hs_videoformat { ...@@ -39,6 +39,23 @@ enum saa6752hs_videoformat {
SAA6752HS_VF_UNKNOWN, SAA6752HS_VF_UNKNOWN,
}; };
struct saa6752hs_mpeg_params {
/* transport streams */
__u16 ts_pid_pmt;
__u16 ts_pid_audio;
__u16 ts_pid_video;
__u16 ts_pid_pcr;
/* audio */
enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
/* video */
enum v4l2_mpeg_video_aspect vi_aspect;
enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
__u32 vi_bitrate;
__u32 vi_bitrate_peak;
};
static const struct v4l2_format v4l2_format_table[] = static const struct v4l2_format v4l2_format_table[] =
{ {
[SAA6752HS_VF_D1] = [SAA6752HS_VF_D1] =
...@@ -55,7 +72,8 @@ static const struct v4l2_format v4l2_format_table[] = ...@@ -55,7 +72,8 @@ static const struct v4l2_format v4l2_format_table[] =
struct saa6752hs_state { struct saa6752hs_state {
struct i2c_client client; struct i2c_client client;
struct v4l2_mpeg_compression params; struct v4l2_mpeg_compression old_params;
struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format; enum saa6752hs_videoformat video_format;
v4l2_std_id standard; v4l2_std_id standard;
}; };
...@@ -129,7 +147,22 @@ static u8 PMT[] = { ...@@ -129,7 +147,22 @@ static u8 PMT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */ 0x00, 0x00, 0x00, 0x00 /* CRC32 */
}; };
static struct v4l2_mpeg_compression param_defaults = static struct saa6752hs_mpeg_params param_defaults =
{
.ts_pid_pmt = 16,
.ts_pid_video = 260,
.ts_pid_audio = 256,
.ts_pid_pcr = 259,
.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
.vi_bitrate = 4000,
.vi_bitrate_peak = 6000,
.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
};
static struct v4l2_mpeg_compression old_param_defaults =
{ {
.st_type = V4L2_MPEG_TS_2, .st_type = V4L2_MPEG_TS_2,
.st_bitrate = { .st_bitrate = {
...@@ -318,50 +351,188 @@ static void saa6752hs_set_subsampling(struct i2c_client* client, ...@@ -318,50 +351,188 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
} }
static void saa6752hs_set_params(struct i2c_client* client, static void saa6752hs_old_set_params(struct i2c_client* client,
struct v4l2_mpeg_compression* params) struct v4l2_mpeg_compression* params)
{ {
struct saa6752hs_state *h = i2c_get_clientdata(client); struct saa6752hs_state *h = i2c_get_clientdata(client);
/* check PIDs */ /* check PIDs */
if (params->ts_pid_pmt <= MPEG_PID_MAX) if (params->ts_pid_pmt <= MPEG_PID_MAX) {
h->old_params.ts_pid_pmt = params->ts_pid_pmt;
h->params.ts_pid_pmt = params->ts_pid_pmt; h->params.ts_pid_pmt = params->ts_pid_pmt;
if (params->ts_pid_pcr <= MPEG_PID_MAX) }
if (params->ts_pid_pcr <= MPEG_PID_MAX) {
h->old_params.ts_pid_pcr = params->ts_pid_pcr;
h->params.ts_pid_pcr = params->ts_pid_pcr; h->params.ts_pid_pcr = params->ts_pid_pcr;
if (params->ts_pid_video <= MPEG_PID_MAX) }
if (params->ts_pid_video <= MPEG_PID_MAX) {
h->old_params.ts_pid_video = params->ts_pid_video;
h->params.ts_pid_video = params->ts_pid_video; h->params.ts_pid_video = params->ts_pid_video;
if (params->ts_pid_audio <= MPEG_PID_MAX) }
if (params->ts_pid_audio <= MPEG_PID_MAX) {
h->old_params.ts_pid_audio = params->ts_pid_audio;
h->params.ts_pid_audio = params->ts_pid_audio; h->params.ts_pid_audio = params->ts_pid_audio;
}
/* check bitrate parameters */ /* check bitrate parameters */
if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) || if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
(params->vi_bitrate.mode == V4L2_BITRATE_VBR)) (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
h->params.vi_bitrate.mode = params->vi_bitrate.mode; h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
}
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE) if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
h->params.st_bitrate.target = params->st_bitrate.target; h->old_params.st_bitrate.target = params->st_bitrate.target;
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE) if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
h->params.vi_bitrate.target = params->vi_bitrate.target; h->old_params.vi_bitrate.target = params->vi_bitrate.target;
if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
h->params.vi_bitrate.max = params->vi_bitrate.max; h->old_params.vi_bitrate.max = params->vi_bitrate.max;
if (params->au_bitrate.mode != V4L2_BITRATE_NONE) if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
h->params.au_bitrate.target = params->au_bitrate.target; h->old_params.au_bitrate.target = params->au_bitrate.target;
/* aspect ratio */ /* aspect ratio */
if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 || if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
h->params.vi_aspect_ratio = params->vi_aspect_ratio; h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
else
h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
}
/* range checks */ /* range checks */
if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX) if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX; h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX) if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX; h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX) if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX; h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
if (h->params.au_bitrate.target <= 256) h->params.vi_bitrate = params->vi_bitrate.target;
h->params.au_bitrate.target = 256; h->params.vi_bitrate_peak = params->vi_bitrate.max;
if (h->old_params.au_bitrate.target <= 256) {
h->old_params.au_bitrate.target = 256;
h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
}
else {
h->old_params.au_bitrate.target = 384;
h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
}
}
static int handle_ctrl(struct saa6752hs_mpeg_params *params,
struct v4l2_ext_control *ctrl, int cmd)
{
int old = 0, new;
int set = cmd == VIDIOC_S_EXT_CTRLS;
new = ctrl->value;
switch (ctrl->id) {
case V4L2_CID_MPEG_STREAM_TYPE:
old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
if (set && new != old)
return -ERANGE;
new = old;
break;
case V4L2_CID_MPEG_STREAM_PID_PMT:
old = params->ts_pid_pmt;
if (set && new > MPEG_PID_MAX)
return -ERANGE;
if (new > MPEG_PID_MAX)
new = MPEG_PID_MAX;
params->ts_pid_pmt = new;
break;
case V4L2_CID_MPEG_STREAM_PID_AUDIO:
old = params->ts_pid_audio;
if (set && new > MPEG_PID_MAX)
return -ERANGE;
if (new > MPEG_PID_MAX)
new = MPEG_PID_MAX;
params->ts_pid_audio = new;
break;
case V4L2_CID_MPEG_STREAM_PID_VIDEO:
old = params->ts_pid_video;
if (set && new > MPEG_PID_MAX)
return -ERANGE;
if (new > MPEG_PID_MAX)
new = MPEG_PID_MAX;
params->ts_pid_video = new;
break;
case V4L2_CID_MPEG_STREAM_PID_PCR:
old = params->ts_pid_pcr;
if (set && new > MPEG_PID_MAX)
return -ERANGE;
if (new > MPEG_PID_MAX)
new = MPEG_PID_MAX;
params->ts_pid_pcr = new;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
if (set && new != old)
return -ERANGE;
new = old;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
old = params->au_l2_bitrate;
if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
return -ERANGE;
if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
else
new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
params->au_l2_bitrate = new;
break;
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
if (set && new != old)
return -ERANGE;
new = old;
break;
case V4L2_CID_MPEG_VIDEO_ENCODING:
old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
if (set && new != old)
return -ERANGE;
new = old;
break;
case V4L2_CID_MPEG_VIDEO_ASPECT:
old = params->vi_aspect;
if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
new != V4L2_MPEG_VIDEO_ASPECT_4x3)
return -ERANGE;
if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
new = V4L2_MPEG_VIDEO_ASPECT_4x3;
params->vi_aspect = new;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
old = params->vi_bitrate * 1000;
new = 1000 * (new / 1000);
if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
return -ERANGE;
if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
params->vi_bitrate = new / 1000;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
old = params->vi_bitrate_peak * 1000;
new = 1000 * (new / 1000);
if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
return -ERANGE;
if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
params->vi_bitrate_peak = new / 1000;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
old = params->vi_bitrate_mode;
params->vi_bitrate_mode = new;
break;
default:
return -EINVAL;
}
if (cmd == VIDIOC_G_EXT_CTRLS)
ctrl->value = old;
else else
h->params.au_bitrate.target = 384; ctrl->value = new;
return 0;
} }
static int saa6752hs_init(struct i2c_client* client) static int saa6752hs_init(struct i2c_client* client)
...@@ -489,11 +660,11 @@ static int saa6752hs_init(struct i2c_client* client) ...@@ -489,11 +660,11 @@ static int saa6752hs_init(struct i2c_client* client)
buf[3] = 0x82; buf[3] = 0x82;
buf[4] = 0xB0; buf[4] = 0xB0;
buf[5] = buf2[0]; buf[5] = buf2[0];
switch(h->params.vi_aspect_ratio) { switch(h->params.vi_aspect) {
case V4L2_MPEG_ASPECT_16_9: case V4L2_MPEG_VIDEO_ASPECT_16x9:
buf[6] = buf2[1] | 0x40; buf[6] = buf2[1] | 0x40;
break; break;
case V4L2_MPEG_ASPECT_4_3: case V4L2_MPEG_VIDEO_ASPECT_4x3:
default: default:
buf[6] = buf2[1] & 0xBF; buf[6] = buf2[1] & 0xBF;
break; break;
...@@ -515,6 +686,7 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) ...@@ -515,6 +686,7 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM; return -ENOMEM;
h->client = client_template; h->client = client_template;
h->params = param_defaults; h->params = param_defaults;
h->old_params = old_param_defaults;
h->client.adapter = adap; h->client.adapter = adap;
h->client.addr = addr; h->client.addr = addr;
...@@ -550,20 +722,45 @@ static int ...@@ -550,20 +722,45 @@ static int
saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{ {
struct saa6752hs_state *h = i2c_get_clientdata(client); struct saa6752hs_state *h = i2c_get_clientdata(client);
struct v4l2_mpeg_compression *params = arg; struct v4l2_ext_controls *ctrls = arg;
struct v4l2_mpeg_compression *old_params = arg;
struct saa6752hs_mpeg_params params;
int err = 0; int err = 0;
int i;
switch (cmd) { switch (cmd) {
case VIDIOC_S_MPEGCOMP: case VIDIOC_S_MPEGCOMP:
if (NULL == params) { if (NULL == old_params) {
/* apply settings and start encoder */ /* apply settings and start encoder */
saa6752hs_init(client); saa6752hs_init(client);
break; break;
} }
saa6752hs_set_params(client, params); saa6752hs_old_set_params(client, old_params);
/* fall through */ /* fall through */
case VIDIOC_G_MPEGCOMP: case VIDIOC_G_MPEGCOMP:
*params = h->params; *old_params = h->old_params;
break;
case VIDIOC_S_EXT_CTRLS:
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
if (ctrls->count == 0) {
/* apply settings and start encoder */
saa6752hs_init(client);
break;
}
/* fall through */
case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_G_EXT_CTRLS:
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
params = h->params;
for (i = 0; i < ctrls->count; i++) {
if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
ctrls->error_idx = i;
return err;
}
}
h->params = params;
break; break;
case VIDIOC_G_FMT: case VIDIOC_G_FMT:
{ {
......
...@@ -64,8 +64,10 @@ static void ts_reset_encoder(struct saa7134_dev* dev) ...@@ -64,8 +64,10 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
static int ts_init_encoder(struct saa7134_dev* dev) static int ts_init_encoder(struct saa7134_dev* dev)
{ {
struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
ts_reset_encoder(dev); ts_reset_encoder(dev);
saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL); saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
dev->empress_started = 1; dev->empress_started = 1;
return 0; return 0;
} }
...@@ -162,6 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file, ...@@ -162,6 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
struct saa7134_dev *dev = file->private_data; struct saa7134_dev *dev = file->private_data;
struct v4l2_ext_controls *ctrls = arg;
if (debug > 1) if (debug > 1)
v4l_print_ioctl(dev->name,cmd); v4l_print_ioctl(dev->name,cmd);
...@@ -284,6 +287,21 @@ static int ts_do_ioctl(struct inode *inode, struct file *file, ...@@ -284,6 +287,21 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_MPEGCOMP: case VIDIOC_G_MPEGCOMP:
saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg); saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
return 0; return 0;
case VIDIOC_S_EXT_CTRLS:
/* count == 0 is abused in saa6752hs.c, so that special
case is handled here explicitly. */
if (ctrls->count == 0)
return 0;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
ts_init_encoder(dev);
return 0;
case VIDIOC_G_EXT_CTRLS:
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
return 0;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment