Browse Source

Pipe for scripts<->application communication, write UYVY files

Got pipe to work between movie subprocess and main code. We use it to
display progress from the scripts. Write "gstreamer raw" files, that
can be worked with easily from gstreamer.
Pavel Machek 10 months ago
parent
commit
f0d8834b4a
4 changed files with 102 additions and 14 deletions
  1. 5 2
      movie.sh.in
  2. 6 0
      src/main.c
  3. 3 1
      src/main.h
  4. 88 11
      src/process_pipeline.c

+ 5 - 2
movie.sh.in

@@ -22,8 +22,8 @@ jpegize() {
 	done
 
 	for DNG in *.dng; do
-		PERC=$[(100*$I)/$NUM]
-		echo $PERC
+		PERC=$[(50*$I)/$NUM]
+		echo Message: ${PERC}%
 		BASE=${DNG%%.dng}
 		# -w		Use camera white balance
 		# +M		use embedded color matrix
@@ -67,10 +67,13 @@ elif [ "-$1" == "-stop" ]; then
 	mkdir $GIGA_DIR/sm
 	kill `cat $2/audio.pid`
 	jpegize $2 # | zenity --progress "--text=Converting, phase 1, dng -> jpeg" --time-remaining
+	echo Message: Mp
 	cd $GIGA_DIR/sm
 	@LIBEXECDIR@/mpegize.py convertall $GIGA_DIR/ $FPS
+	echo Message: Cl
 	mv $GIGA_DIR/smo/*.mp4 $DEST_NAME
 	rm -r $GIGA_DIR
+	echo Message: Ok
 else
 	echo "Unrecognized command"
 fi

+ 6 - 0
src/main.c

@@ -914,6 +914,12 @@ notify_movie_progress(void)
 		gtk_button_set_label(GTK_BUTTON(movie), "Rec");
 }
 
+void
+notify_movie_message(gchar *msg)
+{
+	gtk_button_set_label(GTK_BUTTON(movie), msg);
+}
+
 void
 on_movie_clicked(GtkWidget *widget, gpointer user_data)
 {

+ 3 - 1
src/main.h

@@ -34,4 +34,6 @@ void mp_main_set_zbar_result(MPZBarScanResult *result);
 
 int remap(int value, int input_min, int input_max, int output_min, int output_max);
 
-bool check_window_active();
+bool check_window_active();
+
+void notify_movie_message(gchar *msg);

+ 88 - 11
src/process_pipeline.c

@@ -638,18 +638,56 @@ format_movie_name(char *capture_fname)
 
 int movie_recording;
 static char movie_fname[255];
+static char stdout_buf[1024];
+
+static void on_read_complete(GObject *source_object, GAsyncResult *res, gpointer user_data) {
+	GInputStream *stream = G_INPUT_STREAM(source_object);
+	GError *error = NULL;
+	gssize bytes_read;
+
+	// Read the output from the stream
+	bytes_read = g_input_stream_read_finish(stream, res, &error);
+
+	if (bytes_read == 0) {
+		// End of file reached, close the stream
+		g_input_stream_close(stream, NULL, NULL);
+		g_object_unref(stream);
+		notify_movie_progress();
+		return;
+	}
+	if (bytes_read < 0) {
+		// Error occurred
+		g_print("Error reading subprocess output: %s\n", error->message);
+		g_error_free(error);
+		g_object_unref(stream);
+		return;
+	}	
+
+	//g_print("Got buffer: %.*s", (int)bytes_read, stdout_buf);
+	stdout_buf[bytes_read] = 0;
+
+	{
+		char msg[] = "Message: ";
+		int l = sizeof(msg);
+		if (!strncmp(stdout_buf, msg, l-1)) {
+			char *c = strchr(stdout_buf, '\n');
+			if (!c)
+				return;
+			*c = 0;
+			notify_movie_message(strdup(stdout_buf + l - 1));
+		}
+	}
 
-static void
-on_movie_finished(GSubprocess *proc, GAsyncResult *res, GdkTexture *thumb)
-{
-	notify_movie_progress();
+	// Continue reading asynchronously
+	g_input_stream_read_async(stream, stdout_buf, sizeof(stdout_buf), G_PRIORITY_DEFAULT, NULL,
+				  on_read_complete, NULL);
 }
 
 static void
 spawn_movie(char *cmd)
 {
         g_autoptr(GError) error = NULL;
-        GSubprocess *proc = g_subprocess_new(0,
+        GSubprocess *proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE,
                                              &error,
                                              movie_script,
 					     cmd,
@@ -664,8 +702,14 @@ spawn_movie(char *cmd)
                 return;
         }
 
-        g_subprocess_communicate_utf8_async(
-                proc, NULL, NULL, (GAsyncReadyCallback)on_movie_finished, NULL);
+	
+	GInputStream *stdout_stream;	
+	// Get the stdout stream of the subprocess
+	stdout_stream = g_subprocess_get_stdout_pipe(proc);
+
+	// Read the output of the subprocess asynchronously
+	g_input_stream_read_async(stdout_stream, stdout_buf, sizeof(stdout_buf), G_PRIORITY_DEFAULT, NULL,
+				  on_read_complete, NULL);
 }
 
 
@@ -687,6 +731,28 @@ on_movie_stop(void)
 	spawn_movie("stop");
 }
 
+static void
+save_grw(const uint8_t *image, char *fname)
+{
+	FILE *outfile;
+        if ((outfile = fopen(fname, "wb")) == NULL) {
+                g_printerr("grw open %s: error %d, %s\n",
+                           fname,
+                           errno,
+                           strerror(errno));
+                return;
+        }
+        int width = state_proc.mode->width;
+        int height = state_proc.mode->height;
+	int size = width*height*2;
+	fwrite(image, size, 1, outfile);
+	char buf[1024];
+	buf[0] = 0;
+	int header = sprintf(buf+1, "Caps: video/x-raw,format=YUY2,width=%d,height=%d\nSize: %d\nGRW", width, height, size);
+	fwrite(buf, header+1, 1, outfile);
+        fclose(outfile);
+}
+
 static void
 save_jpeg(const uint8_t *image, char *fname)
 {
@@ -707,9 +773,8 @@ save_jpeg(const uint8_t *image, char *fname)
         jpeg_create_compress(&cinfo);
         jpeg_stdio_dest(&cinfo, outfile);
 
-	//printf("Saving jpeg, %d x %d\n", cinfo.image_width, cinfo.image_height);
         cinfo.image_width = state_proc.mode->width & -1;
-        cinfo.image_height = state_proc.mode->height & -1; // FIXME?
+        cinfo.image_height = state_proc.mode->height & -1;
         cinfo.input_components = 3;
         cinfo.in_color_space = JCS_YCbCr;
         jpeg_set_defaults(&cinfo);
@@ -1005,8 +1070,20 @@ process_image(MPPipeline *pipeline, const MPBuffer *buffer)
 
 	if (movie_recording) {
 		char name[1024];
-		get_name(name, burst_dir, "dng");
-		save_dng(image, name, 1);
+
+		switch (state_proc.mode->v4l_pixfmt) {
+		case V4L2_PIX_FMT_UYVY:
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_YVYU:
+		case V4L2_PIX_FMT_VYUY:
+			get_name(name, burst_dir, "grw");
+			save_grw(image, name);
+			break;
+		default:
+			get_name(name, burst_dir, "dng");
+			save_dng(image, name, 1);
+			break;
+		}
 	}
 
         MPZBarImage *zbar_image = mp_zbar_image_new(image,