[media] ivtv: implement new decoder command ioctls
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Родитель
6b4f12523d
Коммит
da8ec560e3
|
@ -1375,7 +1375,7 @@ static void ivtv_remove(struct pci_dev *pdev)
|
||||||
else
|
else
|
||||||
type = IVTV_DEC_STREAM_TYPE_MPG;
|
type = IVTV_DEC_STREAM_TYPE_MPG;
|
||||||
ivtv_stop_v4l2_decode_stream(&itv->streams[type],
|
ivtv_stop_v4l2_decode_stream(&itv->streams[type],
|
||||||
VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
|
V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
|
||||||
}
|
}
|
||||||
ivtv_halt_firmware(itv);
|
ivtv_halt_firmware(itv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -900,7 +900,7 @@ int ivtv_v4l2_close(struct file *filp)
|
||||||
if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
|
if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
|
||||||
struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
|
struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
|
||||||
|
|
||||||
ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
|
ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
|
||||||
|
|
||||||
/* If all output streams are closed, and if the user doesn't have
|
/* If all output streams are closed, and if the user doesn't have
|
||||||
IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
|
IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
|
||||||
|
|
|
@ -246,34 +246,40 @@ static int ivtv_validate_speed(int cur_speed, int new_speed)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
|
static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
|
||||||
struct video_command *vc, int try)
|
struct v4l2_decoder_cmd *dc, int try)
|
||||||
{
|
{
|
||||||
struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
|
struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
|
||||||
|
|
||||||
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
|
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
switch (vc->cmd) {
|
switch (dc->cmd) {
|
||||||
case VIDEO_CMD_PLAY: {
|
case V4L2_DEC_CMD_START: {
|
||||||
vc->flags = 0;
|
dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO;
|
||||||
vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed);
|
dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed);
|
||||||
if (vc->play.speed < 0)
|
if (dc->start.speed < 0)
|
||||||
vc->play.format = VIDEO_PLAY_FMT_GOP;
|
dc->start.format = V4L2_DEC_START_FMT_GOP;
|
||||||
|
else
|
||||||
|
dc->start.format = V4L2_DEC_START_FMT_NONE;
|
||||||
|
if (dc->start.speed != 500 && dc->start.speed != 1500)
|
||||||
|
dc->flags = dc->start.speed == 1000 ? 0 :
|
||||||
|
V4L2_DEC_CMD_START_MUTE_AUDIO;
|
||||||
if (try) break;
|
if (try) break;
|
||||||
|
|
||||||
|
itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO;
|
||||||
if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
|
if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
|
if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
|
||||||
/* forces ivtv_set_speed to be called */
|
/* forces ivtv_set_speed to be called */
|
||||||
itv->speed = 0;
|
itv->speed = 0;
|
||||||
}
|
}
|
||||||
return ivtv_start_decoding(id, vc->play.speed);
|
return ivtv_start_decoding(id, dc->start.speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_CMD_STOP:
|
case V4L2_DEC_CMD_STOP:
|
||||||
vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK;
|
dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK;
|
||||||
if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY)
|
if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY)
|
||||||
vc->stop.pts = 0;
|
dc->stop.pts = 0;
|
||||||
if (try) break;
|
if (try) break;
|
||||||
if (atomic_read(&itv->decoding) == 0)
|
if (atomic_read(&itv->decoding) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -281,22 +287,22 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
itv->output_mode = OUT_NONE;
|
itv->output_mode = OUT_NONE;
|
||||||
return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts);
|
return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts);
|
||||||
|
|
||||||
case VIDEO_CMD_FREEZE:
|
case V4L2_DEC_CMD_PAUSE:
|
||||||
vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK;
|
dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK;
|
||||||
if (try) break;
|
if (try) break;
|
||||||
if (itv->output_mode != OUT_MPG)
|
if (itv->output_mode != OUT_MPG)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
if (atomic_read(&itv->decoding) > 0) {
|
if (atomic_read(&itv->decoding) > 0) {
|
||||||
ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
|
ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
|
||||||
(vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
|
(dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0);
|
||||||
set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
|
set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIDEO_CMD_CONTINUE:
|
case V4L2_DEC_CMD_RESUME:
|
||||||
vc->flags = 0;
|
dc->flags = 0;
|
||||||
if (try) break;
|
if (try) break;
|
||||||
if (itv->output_mode != OUT_MPG)
|
if (itv->output_mode != OUT_MPG)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -1575,6 +1581,24 @@ static int ivtv_log_status(struct file *file, void *fh)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
|
||||||
|
{
|
||||||
|
struct ivtv_open_id *id = fh2id(file->private_data);
|
||||||
|
struct ivtv *itv = id->itv;
|
||||||
|
|
||||||
|
IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd);
|
||||||
|
return ivtv_video_command(itv, id, dec, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
|
||||||
|
{
|
||||||
|
struct ivtv_open_id *id = fh2id(file->private_data);
|
||||||
|
struct ivtv *itv = id->itv;
|
||||||
|
|
||||||
|
IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd);
|
||||||
|
return ivtv_video_command(itv, id, dec, true);
|
||||||
|
}
|
||||||
|
|
||||||
static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
|
static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
|
||||||
{
|
{
|
||||||
struct ivtv_open_id *id = fh2id(filp->private_data);
|
struct ivtv_open_id *id = fh2id(filp->private_data);
|
||||||
|
@ -1669,52 +1693,54 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_PLAY: {
|
case VIDEO_PLAY: {
|
||||||
struct video_command vc;
|
struct v4l2_decoder_cmd dc;
|
||||||
|
|
||||||
IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
|
IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
|
||||||
memset(&vc, 0, sizeof(vc));
|
memset(&dc, 0, sizeof(dc));
|
||||||
vc.cmd = VIDEO_CMD_PLAY;
|
dc.cmd = V4L2_DEC_CMD_START;
|
||||||
return ivtv_video_command(itv, id, &vc, 0);
|
return ivtv_video_command(itv, id, &dc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_STOP: {
|
case VIDEO_STOP: {
|
||||||
struct video_command vc;
|
struct v4l2_decoder_cmd dc;
|
||||||
|
|
||||||
IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
|
IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
|
||||||
memset(&vc, 0, sizeof(vc));
|
memset(&dc, 0, sizeof(dc));
|
||||||
vc.cmd = VIDEO_CMD_STOP;
|
dc.cmd = V4L2_DEC_CMD_STOP;
|
||||||
vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY;
|
dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
|
||||||
return ivtv_video_command(itv, id, &vc, 0);
|
return ivtv_video_command(itv, id, &dc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_FREEZE: {
|
case VIDEO_FREEZE: {
|
||||||
struct video_command vc;
|
struct v4l2_decoder_cmd dc;
|
||||||
|
|
||||||
IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
|
IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
|
||||||
memset(&vc, 0, sizeof(vc));
|
memset(&dc, 0, sizeof(dc));
|
||||||
vc.cmd = VIDEO_CMD_FREEZE;
|
dc.cmd = V4L2_DEC_CMD_PAUSE;
|
||||||
return ivtv_video_command(itv, id, &vc, 0);
|
return ivtv_video_command(itv, id, &dc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_CONTINUE: {
|
case VIDEO_CONTINUE: {
|
||||||
struct video_command vc;
|
struct v4l2_decoder_cmd dc;
|
||||||
|
|
||||||
IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
|
IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
|
||||||
memset(&vc, 0, sizeof(vc));
|
memset(&dc, 0, sizeof(dc));
|
||||||
vc.cmd = VIDEO_CMD_CONTINUE;
|
dc.cmd = V4L2_DEC_CMD_RESUME;
|
||||||
return ivtv_video_command(itv, id, &vc, 0);
|
return ivtv_video_command(itv, id, &dc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_COMMAND:
|
case VIDEO_COMMAND:
|
||||||
case VIDEO_TRY_COMMAND: {
|
case VIDEO_TRY_COMMAND: {
|
||||||
struct video_command *vc = arg;
|
/* Note: struct v4l2_decoder_cmd has the same layout as
|
||||||
|
struct video_command */
|
||||||
|
struct v4l2_decoder_cmd *dc = arg;
|
||||||
int try = (cmd == VIDEO_TRY_COMMAND);
|
int try = (cmd == VIDEO_TRY_COMMAND);
|
||||||
|
|
||||||
if (try)
|
if (try)
|
||||||
IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
|
IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd);
|
||||||
else
|
else
|
||||||
IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
|
IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd);
|
||||||
return ivtv_video_command(itv, id, vc, try);
|
return ivtv_video_command(itv, id, dc, try);
|
||||||
}
|
}
|
||||||
|
|
||||||
case VIDEO_GET_EVENT: {
|
case VIDEO_GET_EVENT: {
|
||||||
|
@ -1892,6 +1918,8 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
|
||||||
.vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap,
|
.vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap,
|
||||||
.vidioc_encoder_cmd = ivtv_encoder_cmd,
|
.vidioc_encoder_cmd = ivtv_encoder_cmd,
|
||||||
.vidioc_try_encoder_cmd = ivtv_try_encoder_cmd,
|
.vidioc_try_encoder_cmd = ivtv_try_encoder_cmd,
|
||||||
|
.vidioc_decoder_cmd = ivtv_decoder_cmd,
|
||||||
|
.vidioc_try_decoder_cmd = ivtv_try_decoder_cmd,
|
||||||
.vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out,
|
.vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out,
|
||||||
.vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap,
|
.vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap,
|
||||||
.vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap,
|
.vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap,
|
||||||
|
|
|
@ -905,7 +905,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
|
||||||
IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
|
IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
|
||||||
|
|
||||||
/* Stop Decoder */
|
/* Stop Decoder */
|
||||||
if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) {
|
if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
|
||||||
u32 tmp = 0;
|
u32 tmp = 0;
|
||||||
|
|
||||||
/* Wait until the decoder is no longer running */
|
/* Wait until the decoder is no longer running */
|
||||||
|
@ -925,7 +925,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0);
|
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0);
|
||||||
|
|
||||||
/* turn off notification of dual/stereo mode change */
|
/* turn off notification of dual/stereo mode change */
|
||||||
ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
|
ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче