On Thu, 2008-01-31 at 08:20 +0100, Hans Verkuil wrote:

> On the one hand this could be solved in a similar way (pause, change 
> input, resume) inside the driver, but I rather disliked introducing 
> such an unexpected side-effect and since the v4l spec clearly allowed 
> returning EBUSY I decided to do that.

I've attached a patch which I believe addresses the stop, change input,
restart procedure within the driver in just a few lines of code. The
application writer still has the option of putting ivtv specific code
in their V4L2 handling code, but doesn't have to. If they do put the
ivtv driver code in their application this patch doesn't change the
behaviour at all.

My only concern is whether this is atomic, i.e. can ivtv_try_or_set_fmt
be called by the application via an ioctl on a different file descriptor
while the input switching ioctl is operating?

-- Daniel

diff -r 1a1258f9ba2d linux/drivers/media/video/ivtv/ivtv-ioctl.c
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c	Wed Jan 30 17:23:00 2008 +0000
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c	Thu Jan 31 18:04:38 2008 -0500
@@ -932,6 +932,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, s
 
 	case VIDIOC_S_INPUT:{
 		int inp = *(int *)arg;
+		int restart = 0;
+		int restarts[IVTV_MAX_STREAMS];
 
 		if (inp < 0 || inp >= itv->nof_inputs)
 			return -EINVAL;
@@ -941,7 +943,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, s
 			break;
 		}
 		if (atomic_read(&itv->capturing) > 0) {
-			return -EBUSY;
+			IVTV_DEBUG_INFO("We're doing an input switch "
+					"while capturing..\n");
+			restart = ivtv_stop_all_captures_temp(itv,0,restarts);
 		}
 		IVTV_DEBUG_INFO("Changing input from %d to %d\n",
 				itv->active_input, inp);
@@ -957,6 +961,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, s
 		ivtv_video_set_io(itv);
 		ivtv_audio_set_io(itv);
 		ivtv_unmute(itv);
+
+		if (restart) {
+			int ok = ivtv_restart_all_captures(itv, restarts);
+			/* TODO handle errors */
+		}
+
 		break;
 	}
 
diff -r 1a1258f9ba2d linux/drivers/media/video/ivtv/ivtv-streams.c
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c	Wed Jan 30 17:23:00 2008 +0000
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c	Thu Jan 31 18:04:38 2008 -0500
@@ -709,6 +709,48 @@ void ivtv_stop_all_captures(struct ivtv 
 	}
 }
 
+int ivtv_stop_all_captures_temp(struct ivtv *itv, int gop_end, int *stopped)
+{
+	int i;
+	int total = 0;
+
+	for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
+		struct ivtv_stream *s = &itv->streams[i];
+
+		stopped[i] = 0;
+
+		if (s->v4l2dev == NULL)
+			continue;
+		if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+			stopped[i] = 1;
+			total++;
+			ivtv_stop_v4l2_encode_stream(s, gop_end);
+		}
+	}
+
+	return total;
+}
+
+int ivtv_restart_all_captures(struct ivtv *itv, int *stopped)
+{
+	int i;
+	int errors = 0;
+
+	for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
+		struct ivtv_stream *s = &itv->streams[i];
+
+		if (s->v4l2dev == NULL)
+			continue;
+
+		if (!stopped[i])
+			continue;
+
+		errors += (0 == ivtv_start_v4l2_encode_stream(s)) ? 0 : 1;
+	}
+
+	return errors;
+}
+
 int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
 {
 	struct ivtv *itv = s->itv;
diff -r 1a1258f9ba2d linux/drivers/media/video/ivtv/ivtv-streams.h
--- a/linux/drivers/media/video/ivtv/ivtv-streams.h	Wed Jan 30 17:23:00 2008 +0000
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.h	Thu Jan 31 18:04:38 2008 -0500
@@ -34,4 +34,7 @@ void ivtv_stop_all_captures(struct ivtv 
 void ivtv_stop_all_captures(struct ivtv *itv);
 int ivtv_passthrough_mode(struct ivtv *itv, int enable);
 
+int ivtv_stop_all_captures_temp(struct ivtv *itv, int gop_end, int *stopped);
+int ivtv_restart_all_captures(struct ivtv *itv, int *stopped);
+
 #endif
_______________________________________________
ivtv-devel mailing list
[email protected]
http://ivtvdriver.org/mailman/listinfo/ivtv-devel

Reply via email to