Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da8ec560 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] ivtv: implement new decoder command ioctls

parent 6b4f1252
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);
	}
	}
+1 −1
Original line number Original line Diff line number Diff line
@@ -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. */
+67 −39
Original line number Original line Diff line number Diff line
@@ -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,
+2 −2
Original line number Original line Diff line number Diff line
@@ -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);