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