1 /*
2  *   gegl-video <video-file|frame-folder|frames|edl>
3  *
4  *      --output-frames path/image- --frame-extension png
5  *      --output-video  path/video.avi
6  *      --play (default)
7  *      -- gegl:threshold value=0.3
8  *
9  * the edl,. should be a list of frames.. and video with frame start->end bits
10  * 0001.png
11  * 0002.png
12  * 0003.png
13  * 0004.png
14  * foo.avi 3-210
15  * clip2.avi
16  *
17  *   image folders are folder containing image files to be played in sequence
18  *   each image file contains its own embedded PCM data, facilitating easy re-assembly.
19  *
20  */
21 
22 #include <gegl.h>
23 #include <gegl-audio-fragment.h>
24 #include <glib/gprintf.h>
25 #include <gexiv2/gexiv2.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 
31 int frame_start = 0;
32 int frame_end   = 0;
33 
34 char *frame_extension = ".png";
35 char *frame_path = NULL;
36 char *video_path = NULL;
37 int output_frame_no = -1;
38 int show_progress = 0;
39 
40 void
41 gegl_meta_set_audio (const char         *path,
42                      GeglAudioFragment  *audio);
43 void
44 gegl_meta_get_audio (const char         *path,
45                      GeglAudioFragment  *audio);
46 
47 void usage(void);
usage(void)48 void usage(void)
49 {
50       printf ("usage: negl [options] <video> [thumb]\n\n"
51 " -p, --progress   - display info about current frame/progress in terminal\n"
52 " -s <frame>, --start-frame <frame>\n"
53 "           - first frame to extract analysis from (default 0)\n"
54 " -e <frame>, --end-frame <frame>\n"
55 "           - last frame to extract analysis from (default is 0 which means auto end)\n"
56 " -of <output_path_prefix>, --output-path <path_prefix>\n"
57 " -fe <.ext> --frame-extension <.ext>\n"
58 "           - .png or .jpg are supported file formats, .jpg default\n"
59 "\n"
60 "Options can also follow then video (and thumb) arguments.\n"
61 "\n");
62   exit (0);
63 }
64 
parse_args(int argc,char ** argv)65 static void parse_args (int argc, char **argv)
66 {
67   int i;
68   int stage = 0;
69   for (i = 1; i < argc; i++)
70   {
71     if (g_str_equal (argv[i], "-p") ||
72         g_str_equal (argv[i], "--progress"))
73     {
74       show_progress = 1;
75     }
76     else if (g_str_equal (argv[i], "-s") ||
77              g_str_equal (argv[i], "--start-frame"))
78     {
79       frame_start = g_ascii_strtod (argv[i+1], NULL);
80       i++;
81     }
82     else if (g_str_equal (argv[i], "-c") ||
83              g_str_equal (argv[i], "--frame-count"))
84     {
85       frame_end = frame_start + g_ascii_strtod (argv[i+1], NULL) - 1;
86       i++;
87     }
88     else if (g_str_equal (argv[i], "--output-frames") ||
89              g_str_equal (argv[i], "-of"))
90     {
91       frame_path = g_strdup (argv[i+1]);
92       i++;
93     }
94     else if (g_str_equal (argv[i], "--output-frame-start") ||
95              g_str_equal (argv[i], "-ofs`"))
96     {
97       output_frame_no = g_ascii_strtod (argv[i+1], NULL);
98       i++;
99     }
100     else if (g_str_equal (argv[i], "--frame-extension") ||
101              g_str_equal (argv[i], "-fe"))
102     {
103       frame_extension = g_strdup (argv[i+1]);
104       i++;
105     }
106     else if (g_str_equal (argv[i], "-e") ||
107              g_str_equal (argv[i], "--end-frame"))
108     {
109       frame_end = g_ascii_strtod (argv[i+1], NULL);
110       i++;
111     }
112     else if (g_str_equal (argv[i], "-h") ||
113              g_str_equal (argv[i], "--help"))
114     {
115       usage();
116     }
117     else if (stage == 0)
118     {
119       video_path = g_strdup (argv[i]);
120       stage = 1;
121     }
122   }
123 }
124 
125 GeglNode   *gegl_decode  = NULL;
126 GeglNode   *display      = NULL;
127 
128 GeglBuffer *previous_video_frame  = NULL;
129 GeglBuffer *video_frame  = NULL;
130 
131 GeglNode *store, *load;
132 
decode_frame_no(int frame)133 static void decode_frame_no (int frame)
134 {
135   if (video_frame)
136   {
137     g_object_unref (video_frame);
138   }
139   video_frame = NULL;
140   gegl_node_set (load, "frame", frame, NULL);
141   gegl_node_process (store);
142 }
143 
144 GeglNode *translate = NULL;
145 
146 gint
main(gint argc,gchar ** argv)147 main (gint    argc,
148       gchar **argv)
149 {
150   if (argc < 2)
151     usage();
152 
153   gegl_init (&argc, &argv);
154   parse_args (argc, argv);
155 
156   gegl_decode = gegl_node_new ();
157 
158   store = gegl_node_new_child (gegl_decode,
159                                "operation", "gegl:buffer-sink",
160                                "buffer", &video_frame, NULL);
161   load = gegl_node_new_child (gegl_decode,
162                               "operation", "gegl:ff-load",
163                               "frame", 0,
164                               "path", video_path,
165                               NULL);
166   gegl_node_link_many (load, store, NULL);
167 
168   decode_frame_no (0);
169 
170   {
171     int frames = 0;
172     double frame_rate = 0;
173     gegl_node_get (load, "frames", &frames, NULL);
174     gegl_node_get (load, "frame-rate", &frame_rate, NULL);
175 
176     if (frame_end == 0)
177       frame_end = frames;
178   }
179 
180   if (output_frame_no == -1)
181     output_frame_no = frame_start;
182 
183   printf ("frames: %i - %i\n", frame_start, frame_end);
184   printf ("video: %s\n", video_path);
185 
186   {
187     gint frame;
188     for (frame = frame_start; frame <= frame_end; frame++)
189       {
190         if (show_progress)
191         {
192           fprintf (stdout, "\r%2.1f%% %i/%i (%i)",
193                    (frame-frame_start) * 100.0 / (frame_end-frame_start),
194                    frame-frame_start,
195                    frame_end-frame_start,
196                    frame);
197           fflush (stdout);
198         }
199 
200 	decode_frame_no (frame);
201         {
202         GeglAudioFragment *audio;
203         gdouble fps;
204         gegl_node_get (load, "audio", &audio,
205                              "frame-rate", &fps, NULL);
206 
207 	if (frame_path)
208 	{
209           char *path = g_strdup_printf ("%s%07i%s", frame_path, output_frame_no++, frame_extension);
210 	  GeglNode *save_graph = gegl_node_new ();
211 	  GeglNode *readbuf, *save;
212 
213 	  readbuf = gegl_node_new_child (save_graph, "operation", "gegl:buffer-source", "buffer", video_frame, NULL);
214 	  save = gegl_node_new_child (save_graph, "operation", "gegl:save",
215 	    "path", path, NULL);
216 	    gegl_node_link_many (readbuf, save, NULL);
217 	  gegl_node_process (save);
218 	  g_object_unref (save_graph);
219           gegl_meta_set_audio (path, audio);
220           g_free (path);
221 	}
222         g_object_unref (audio);
223         }
224 
225       }
226       if (show_progress)
227         fprintf (stdout, "\n");
228   }
229 
230   if (video_frame)
231     g_object_unref (video_frame);
232   video_frame = NULL;
233   g_object_unref (gegl_decode);
234 
235   gegl_exit ();
236   return 0;
237 }
238 
239 void
gegl_meta_set_audio(const char * path,GeglAudioFragment * audio)240 gegl_meta_set_audio (const char        *path,
241                      GeglAudioFragment *audio)
242 {
243   GError *error = NULL;
244   GExiv2Metadata *e2m = gexiv2_metadata_new ();
245   gexiv2_metadata_open_path (e2m, path, &error);
246   if (error)
247   {
248     g_warning ("%s", error->message);
249   }
250   else
251   {
252     int i, c;
253     GString *str = g_string_new ("");
254     int sample_count = gegl_audio_fragment_get_sample_count (audio);
255     int channels = gegl_audio_fragment_get_channels (audio);
256     if (gexiv2_metadata_has_tag (e2m, "Xmp.xmp.GEGL"))
257       gexiv2_metadata_clear_tag (e2m, "Xmp.xmp.GEGL");
258 
259     g_string_append_printf (str, "%i %i %i %i",
260                               gegl_audio_fragment_get_sample_rate (audio),
261                               gegl_audio_fragment_get_channels (audio),
262                               gegl_audio_fragment_get_channel_layout (audio),
263                               gegl_audio_fragment_get_sample_count (audio));
264 
265     for (i = 0; i < sample_count; i++)
266       for (c = 0; c < channels; c++)
267         g_string_append_printf (str, " %0.5f", audio->data[c][i]);
268 
269     gexiv2_metadata_set_tag_string (e2m, "Xmp.xmp.GeglAudio", str->str);
270     gexiv2_metadata_save_file (e2m, path, &error);
271     if (error)
272       g_warning ("%s", error->message);
273     g_string_free (str, TRUE);
274   }
275   g_object_unref (e2m);
276 }
277 
278 void
gegl_meta_get_audio(const char * path,GeglAudioFragment * audio)279 gegl_meta_get_audio (const char        *path,
280                      GeglAudioFragment *audio)
281 {
282   //gchar  *ret   = NULL;
283   GError *error = NULL;
284   GExiv2Metadata *e2m = gexiv2_metadata_new ();
285   gexiv2_metadata_open_path (e2m, path, &error);
286   if (!error)
287   {
288     gchar *ret = gexiv2_metadata_get_tag_string (e2m, "Xmp.xmp.GeglAudio");
289     fprintf (stderr, "should parse audio\n");
290     g_free (ret);
291   }
292   else
293     g_warning ("%s", error->message);
294   g_object_unref (e2m);
295 }
296