[chronojump] person photo preview and capture with ffmpeg done (at least on Linux)



commit 5c7c44880c89d193c21ce782d9115dcb2e3546c4
Author: Xavier de Blas <xaviblas gmail com>
Date:   Fri Feb 15 18:33:48 2019 +0100

    person photo preview and capture with ffmpeg done (at least on Linux)

 glade/person_win.glade | 111 +++++++++++++++++++++++++++++++++++--------------
 src/gui/person.cs      |  60 ++++----------------------
 src/util.cs            |   6 +--
 src/webcam.cs          |  15 +++++++
 src/webcamFfmpeg.cs    |  81 +++++++++++++++++++++++++++++++-----
 src/webcamMplayer.cs   |  13 ++++--
 6 files changed, 187 insertions(+), 99 deletions(-)
---
diff --git a/glade/person_win.glade b/glade/person_win.glade
index 588d4323..6b173431 100644
--- a/glade/person_win.glade
+++ b/glade/person_win.glade
@@ -335,33 +335,12 @@
                               <widget class="GtkVBox" id="vbox3">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="spacing">4</property>
+                                <property name="spacing">6</property>
                                 <child>
                                   <widget class="GtkHBox" id="hbox6">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
                                     <property name="spacing">8</property>
-                                    <child>
-                                      <widget class="GtkButton" id="button_add_photo_file">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">True</property>
-                                        <property name="receives_default">True</property>
-                                        <property name="tooltip" translatable="yes">Add photo from 
file</property>
-                                        <signal name="clicked" handler="on_button_add_photo_file_clicked" 
swapped="no"/>
-                                        <child>
-                                          <widget class="GtkImage" id="image_photo_from_file">
-                                            <property name="visible">True</property>
-                                            <property name="can_focus">False</property>
-                                            <property name="stock">gtk-missing-image</property>
-                                          </widget>
-                                        </child>
-                                      </widget>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">False</property>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
                                     <child>
                                       <widget class="GtkHBox" id="hbox_camera">
                                         <property name="visible">True</property>
@@ -375,10 +354,34 @@
                                             <property name="tooltip" translatable="yes">Start 
webcam</property>
                                             <signal name="clicked" 
handler="on_button_take_photo_start_end_camera_clicked" swapped="no"/>
                                             <child>
-                                              <widget class="GtkImage" id="image_photo_start_end_camera">
+                                              <widget class="GtkHBox" id="hbox7">
                                                 <property name="visible">True</property>
                                                 <property name="can_focus">False</property>
-                                                <property name="stock">gtk-missing-image</property>
+                                                <property name="spacing">4</property>
+                                                <child>
+                                                  <widget class="GtkImage" id="image_photo_start_end_camera">
+                                                    <property name="visible">True</property>
+                                                    <property name="can_focus">False</property>
+                                                    <property name="stock">gtk-missing-image</property>
+                                                  </widget>
+                                                  <packing>
+                                                    <property name="expand">True</property>
+                                                    <property name="fill">True</property>
+                                                    <property name="position">0</property>
+                                                  </packing>
+                                                </child>
+                                                <child>
+                                                  <widget class="GtkLabel" id="label10">
+                                                    <property name="visible">True</property>
+                                                    <property name="can_focus">False</property>
+                                                    <property name="label" 
translatable="yes">Preview</property>
+                                                  </widget>
+                                                  <packing>
+                                                    <property name="expand">True</property>
+                                                    <property name="fill">True</property>
+                                                    <property name="position">1</property>
+                                                  </packing>
+                                                </child>
                                               </widget>
                                             </child>
                                           </widget>
@@ -406,15 +409,15 @@
                                           <packing>
                                             <property name="expand">False</property>
                                             <property name="fill">False</property>
+                                            <property name="pack_type">end</property>
                                             <property name="position">1</property>
                                           </packing>
                                         </child>
                                       </widget>
                                       <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">False</property>
-                                        <property name="pack_type">end</property>
-                                        <property name="position">1</property>
+                                        <property name="expand">True</property>
+                                        <property name="fill">True</property>
+                                        <property name="position">0</property>
                                       </packing>
                                     </child>
                                   </widget>
@@ -425,6 +428,52 @@
                                     <property name="position">0</property>
                                   </packing>
                                 </child>
+                                <child>
+                                  <widget class="GtkHBox" id="hbox10">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <widget class="GtkLabel" id="label11">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="label" translatable="yes">Change</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <widget class="GtkButton" id="button_add_photo_file">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="tooltip" translatable="yes">Add photo from 
file</property>
+                                        <signal name="clicked" handler="on_button_add_photo_file_clicked" 
swapped="no"/>
+                                        <child>
+                                          <widget class="GtkImage" id="image_photo_from_file">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="stock">gtk-missing-image</property>
+                                          </widget>
+                                        </child>
+                                      </widget>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="pack_type">end</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
                               </widget>
                               <packing>
                                 <property name="expand">False</property>
@@ -607,9 +656,6 @@
                                     <child>
                                       <placeholder/>
                                     </child>
-                                    <child>
-                                      <placeholder/>
-                                    </child>
                                     <child>
                                       <widget class="GtkLabel" id="label218">
                                         <property name="visible">True</property>
@@ -2030,6 +2076,9 @@
                                     <child>
                                       <placeholder/>
                                     </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
                                   </widget>
                                 </child>
                               </widget>
diff --git a/src/gui/person.cs b/src/gui/person.cs
index 321b59b2..ca013d96 100644
--- a/src/gui/person.cs
+++ b/src/gui/person.cs
@@ -1074,73 +1074,33 @@ public class PersonAddModifyWindow
                {
                        webcam.ExitCamera();
                        image_photo_start_end_camera.Pixbuf = new Pixbuf (null, Util.GetImagePath(false) + 
"image_photo_start_camera.png");
-                       button_take_photo_do.Sensitive = false;
                        button_take_photo_start_end_camera.TooltipText = Catalog.GetString("Start webcam");
 
                        return;
                }
 
                // B) start if it's not running
-               webcam = new WebcamMplayer (videoDevice);
-               Webcam.Result result = webcam.CapturePrepare (Webcam.CaptureTypes.PHOTO);
+               //webcam = new WebcamMplayer (videoDevice);
+               //Webcam.Result result = webcam.CapturePrepare (Webcam.CaptureTypes.PHOTO);
+               //constructor for playpreview
+               webcam = new WebcamFfmpeg (Webcam.Action.PLAYPREVIEW, UtilAll.GetOSEnum(), videoDevice);
+               Webcam.Result result = webcam.PlayPreviewNoBackground ();
+
                if (! result.success)
                {
-                       LogB.Debug ("Webcam Mplayer error: ", result.error);
+                       LogB.Debug ("Webcam Ffmpeg error: ", result.error);
                        new DialogMessage (Constants.MessageTypes.WARNING, result.error);
                        return;
                }
-
-               image_photo_start_end_camera.Pixbuf = new Pixbuf (null, Util.GetImagePath(false) + 
"image_photo_end_camera.png");
-               button_take_photo_do.Sensitive = true;
-               button_take_photo_start_end_camera.TooltipText = Catalog.GetString("Stop webcam");
-
-               /*
-                * TODO: reimplement this with ffmpeg
-                *
-               List<LongoMatch.Video.Utils.Device> devices = 
LongoMatch.Video.Utils.Device.ListVideoDevices();
-               if(devices.Count == 0) {
-                       new DialogMessage(Constants.MessageTypes.WARNING, Constants.CameraNotFound);
-                       return;
-               }
-
-               //deactivate camera to allow camera on edit person. videoOn will have same value to light 
checkbutton again later
-               app1_checkbutton_video.Active = false;
-
-               capturer = new CapturerBin();
-               CapturePropertiesStruct s = new CapturePropertiesStruct();
-
-               s.DeviceID = devices[0].ID;
-
-               s.CaptureSourceType = CaptureSourceType.System;
-
-               capturer.CaptureProperties = s;
-               capturer.Type = CapturerType.Snapshot;
-               capturer.Visible=true;
-               capturer.NewSnapshot += on_snapshot_done;
-               capturer.NewSnapshotMini += on_snapshot_mini_done;
-
-               capturerWindow = new Gtk.Window("Capturer");
-               capturerWindow.Add(capturer);
-               capturerWindow.Modal=true;
-               capturerWindow.SetDefaultSize(400,400);
-
-               person_win.Hide();
-
-               capturerWindow.ShowAll();
-               capturerWindow.Present();
-               capturerWindow.DeleteEvent += delegate(object sender, DeleteEventArgs e) {capturer.Close(); 
capturer.Dispose(); person_win.Show(); };
-               
-               capturer.Run();
-               */
        }
        void on_button_take_photo_do_clicked (object o, EventArgs args)
        {
                if(webcam == null)
-                       return;
+                       webcam = new WebcamFfmpeg (Webcam.Action.PLAYPREVIEW, UtilAll.GetOSEnum(), 
videoDevice);
 
                if(webcam.Snapshot())
                {
-                       File.Copy(Util.GetMplayerPhotoTempFileNamePost(Util.ChangeChars(videoDevice, "/", 
"_")),
+                       File.Copy(Util.GetWebcamPhotoTempFileNamePost(Util.ChangeChars(videoDevice, "/", 
"_")),
                                                Util.GetPhotoPngFileName(false, currentPerson.UniqueID), 
true); //overwrite
 
                        string filenameMini = Util.GetPhotoPngFileName(true, currentPerson.UniqueID);
@@ -1152,7 +1112,6 @@ public class PersonAddModifyWindow
                }
 
                image_photo_start_end_camera.Pixbuf = new Pixbuf (null, Util.GetImagePath(false) + 
"image_photo_start_camera.png");
-               button_take_photo_do.Sensitive = false;
        }
 
        //libCesarplayer method, jpeg
@@ -1271,7 +1230,6 @@ public class PersonAddModifyWindow
 
                PersonAddModifyWindowBox.pDN = pDN;
                PersonAddModifyWindowBox.app1_checkbutton_video = app1_checkbutton_video;
-               PersonAddModifyWindowBox.button_take_photo_do.Sensitive = false;
                PersonAddModifyWindowBox.videoDevice = videoDevice;
 
                PersonAddModifyWindowBox.person_win.Show ();
diff --git a/src/util.cs b/src/util.cs
index faa6036a..bb839962 100644
--- a/src/util.cs
+++ b/src/util.cs
@@ -1081,7 +1081,7 @@ public class Util
         */
 
        //Pre: filename without 0001.png
-       public static string GetMplayerPhotoTempFileNamePre(string videoDevice)
+       public static string GetWebcamPhotoTempFileNamePre(string videoDevice)
        {
                string fileName = Constants.PhotoTemp;
 
@@ -1089,9 +1089,9 @@ public class Util
        }
 
        //Pre: filename with 0001.png
-       public static string GetMplayerPhotoTempFileNamePost(string videoDevice)
+       public static string GetWebcamPhotoTempFileNamePost(string videoDevice)
        {
-               return GetMplayerPhotoTempFileNamePre(videoDevice) + "0001.png";
+               return GetWebcamPhotoTempFileNamePre(videoDevice) + "0001.png";
        }
 
 
diff --git a/src/webcam.cs b/src/webcam.cs
index 94592aa7..c51ff555 100644
--- a/src/webcam.cs
+++ b/src/webcam.cs
@@ -1,5 +1,19 @@
 /*
 
+15 Feb 2019
+
+//play 2 seconds of video and autoexit. works:
+//ffplay JUMP_RJ-252.mp4 -autoexit -t 2
+//but on webcam show it does not exit
+//ffplay /dev/video0 -autoexit -t 2
+
+//one solution will be to open camera with ffplay, close it pressing any button (keyboard or mouse):
+//ffplay /dev/video0 -exitonkeydown -exitonmousedown
+//and then press make photo that will be:
+//webcam make picture on second two
+//ffmpeg -f video4linux2 -s 640x480 -i /dev/video0 -ss 0:0:2 -frames 1 /tmp/out.jpg
+
+
 17 setembre 2018
 
 ffmpeg builds on windows only work on Windows 7 and above
@@ -126,6 +140,7 @@ public abstract class Webcam
        public abstract Result CapturePrepare (CaptureTypes captureType);
 
        public abstract Result PlayPreview();
+       public abstract Result PlayPreviewNoBackground();
 
        public abstract Result PlayFile(string filename);
 
diff --git a/src/webcamFfmpeg.cs b/src/webcamFfmpeg.cs
index 8f1a804f..e2f9a069 100644
--- a/src/webcamFfmpeg.cs
+++ b/src/webcamFfmpeg.cs
@@ -72,16 +72,43 @@ public class WebcamFfmpeg : Webcam
                List<string> parameters = createParametersPlayPreview();
 
                process = new Process();
-               bool success = ExecuteProcess.RunAtBackground (ref process, executable, parameters, true, 
false, false, false, false);
+               bool success = ExecuteProcess.RunAtBackground (ref process, executable, parameters, true, 
false, true, false, false);
                if(! success)
                {
                        process = null;
                        return new Result (false, "", programFfmpegNotInstalled);
                }
 
+               streamWriter = process.StandardInput;
                Running = true;
                return new Result (true, "");
        }
+       public override Result PlayPreviewNoBackground () //experimental
+       {
+               List<string> parameters = createParametersPlayPreview();
+
+               process = new Process();
+               ExecuteProcess.Result execute_result = ExecuteProcess.run (executable, parameters, false, 
false);
+               if(! execute_result.success)
+               {
+                       return new Result (false, "", programFfmpegNotInstalled);
+               }
+
+               return new Result (true, "");
+       }
+
+       //snapshot in 2 seconds
+       public override bool Snapshot ()
+       {
+               executable = "ffmpeg";
+               List<string> parameters = createParametersSnapshot();
+
+               process = new Process();
+               ExecuteProcess.Result execute_result = ExecuteProcess.run (executable, parameters, false, 
false);
+               return execute_result.success;
+       }
+
+
 
        public override Result PlayFile (string filename)
        {
@@ -102,12 +129,6 @@ public class WebcamFfmpeg : Webcam
                return new Result (true, "");
        }
 
-       public override bool Snapshot()
-       {
-               //only implemented on mplayer
-               return true;
-       }
-
        public override Result VideoCaptureStart()
        {
                process = new Process();
@@ -147,8 +168,42 @@ public class WebcamFfmpeg : Webcam
                else
                        parameters.Insert (i ++, "video=" + videoDevice);
 
+               parameters.Insert (i++, "-exitonkeydown");
+               parameters.Insert (i++, "-exitonmousedown");
                parameters.Insert (i++, "-window_title");
-               parameters.Insert (i++, "Chronojump webcam preview");
+               parameters.Insert (i++, "Preview. Press any key to exit.");
+               return parameters;
+       }
+
+       //ffmpeg -f v4l2 -s 400x400 -i /dev/video0 -ss 0:0:2 -frames 1 /tmp/out.jpg
+       private List<string> createParametersSnapshot()
+       {
+               // ffplay /dev/video0
+               List<string> parameters = new List<string>();
+               int i=0;
+
+               parameters.Insert (i ++, "-f");
+               if(os == UtilAll.OperatingSystems.LINUX)
+                       parameters.Insert (i ++, "v4l2");
+               else    //windows
+                       parameters.Insert (i ++, "dshow");
+
+               parameters.Insert (i ++, "-s");
+               parameters.Insert (i ++, "400x400");
+
+               parameters.Insert (i ++, "-i");
+               if(os == UtilAll.OperatingSystems.LINUX)
+                       parameters.Insert (i ++, videoDevice);
+               else
+                       parameters.Insert (i ++, "video=" + videoDevice);
+
+               parameters.Insert (i ++, "-ss");
+               parameters.Insert (i ++, "0:0:2");
+               parameters.Insert (i ++, "-frames");
+               parameters.Insert (i ++, "1");
+               parameters.Insert (i ++, Util.GetWebcamPhotoTempFileNamePost(videoDeviceToFilename()));
+               parameters.Insert (i ++, "-y"); //overwrite
+
                return parameters;
        }
 
@@ -272,7 +327,7 @@ public class WebcamFfmpeg : Webcam
                LogB.Information("streamWriter is null: " + (streamWriter == null).ToString());
                try {
                        streamWriter.Write('q');
-                       //streamWriter.Flush(); //seems is not needed
+                       streamWriter.Flush(); //seems is not needed
                } catch {
                        //maybe capturer process (could be a window) has been closed by user
                        process = null;
@@ -289,10 +344,16 @@ public class WebcamFfmpeg : Webcam
                 * without using this file copied from /tmp maybe is not finished, so a bad ended file is 
copied to .local/share/Chronojump/multimedia/video
                */
 
+               bool exitBucle = false;
                do {
                        LogB.Information("waiting 100 ms to tmp capture file being unlocked");
                        System.Threading.Thread.Sleep(100);
-               } while( ExecuteProcess.IsFileLocked(new System.IO.FileInfo(Util.GetVideoTempFileName())) );
+
+                       if (! File.Exists(Util.GetVideoTempFileName())) //PlayPreview does not have tmp file
+                               exitBucle = true;
+                       else if( ! ExecuteProcess.IsFileLocked(new 
System.IO.FileInfo(Util.GetVideoTempFileName())) ) //we are capturing, wait file is not locked
+                               exitBucle = true;
+               } while(! exitBucle);
 
                do {
                        LogB.Information("waiting 100 ms to end Ffmpeg");
diff --git a/src/webcamMplayer.cs b/src/webcamMplayer.cs
index b63512a4..155fee87 100644
--- a/src/webcamMplayer.cs
+++ b/src/webcamMplayer.cs
@@ -45,7 +45,7 @@ public class WebcamMplayer : Webcam
                if(process != null)
                        return new Result (false, "");
 
-               string tempFile = Util.GetMplayerPhotoTempFileNamePost(videoDeviceToFilename());
+               string tempFile = Util.GetWebcamPhotoTempFileNamePost(videoDeviceToFilename());
                Util.FileDelete(tempFile);
 
                List<string> parameters = new List<string>();
@@ -68,7 +68,7 @@ public class WebcamMplayer : Webcam
                parameters.Insert (i ++, "driver=v4l2:gain=1:width=400:height=400:device=" + videoDevice + 
":fps=10:outfmt=rgb16");
                parameters.Insert (i ++, "tv://");
                parameters.Insert (i ++, "-vf");
-               parameters.Insert (i ++, "screenshot=" + 
Util.GetMplayerPhotoTempFileNamePre(videoDeviceToFilename()));
+               parameters.Insert (i ++, "screenshot=" + 
Util.GetWebcamPhotoTempFileNamePre(videoDeviceToFilename()));
 
                process = new Process();
                bool success = ExecuteProcess.RunAtBackground (ref process, executable, parameters, true, 
false, true, true, true); //redirectInput, redirectOutput, redirectError
@@ -105,6 +105,11 @@ public class WebcamMplayer : Webcam
                //not implemented
                return new Result (false, "");
        }
+       public override Result PlayPreviewNoBackground () //experimental
+       {
+               //not implemented
+               return new Result (false, "");
+       }
 
        public override Result PlayFile (string filename)
        {
@@ -263,7 +268,7 @@ public class WebcamMplayer : Webcam
 
        private bool findIfThereAreImagesToConvert()
        {
-               return (File.Exists(Util.GetMplayerPhotoTempFileNamePre(videoDeviceToFilename()) + 
"0001.png"));
+               return (File.Exists(Util.GetWebcamPhotoTempFileNamePre(videoDeviceToFilename()) + 
"0001.png"));
        }
 
        private bool convertImagesToVideo()
@@ -275,7 +280,7 @@ public class WebcamMplayer : Webcam
                parameters.Insert (1, "20");
                parameters.Insert (2, "-y"); //force overwrite without asking
                parameters.Insert (3, "-i"); //input files
-               parameters.Insert (4, Util.GetMplayerPhotoTempFileNamePre(videoDeviceToFilename()) + 
"%04d.png");
+               parameters.Insert (4, Util.GetWebcamPhotoTempFileNamePre(videoDeviceToFilename()) + 
"%04d.png");
                parameters.Insert (5, Util.GetVideoTempFileName());
 
                ExecuteProcess.Result execute_result = ExecuteProcess.run (executable, parameters, true, 
true);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]