1 /*
2 * dwfa.c: Decoding of WFA-files
3 *
4 * Written by: Ullrich Hafner
5 * Michael Unger
6 *
7 * This file is part of FIASCO (Fractal Image And Sequence COdec)
8 * Copyright (C) 1994-2000 Ullrich Hafner
9 */
10
11 /*
12 * $Date: 2000/10/28 17:39:29 $
13 * $Author: hafner $
14 * $Revision: 5.7 $
15 * $State: Exp $
16 */
17
18 #define _DEFAULT_SOURCE 1 /* New name for SVID & BSD source defines */
19 #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */
20 #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
21
22 #include "config.h"
23 #include "pnm.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28
29 #include "nstring.h"
30
31 #include "types.h"
32 #include "macros.h"
33
34 #include <getopt.h>
35
36 #include "binerror.h"
37 #include "misc.h"
38 #include "params.h"
39 #include "fiasco.h"
40
41 #ifndef X_DISPLAY_MISSING
42
43 # include "display.h"
44 # include "buttons.h"
45
46 static x11_info_t *xinfo = NULL;
47
48 #endif /* not X_DISPLAY_MISSING */
49
50 /*****************************************************************************
51
52 prototypes
53
54 *****************************************************************************/
55
56 static int
57 checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel,
58 int *fps, char **image_name, fiasco_d_options_t **options);
59 static void
60 video_decoder (const char *wfa_name, const char *image_name, bool_t panel,
61 bool_t double_resolution, int fps, fiasco_d_options_t *options);
62 static void
63 get_output_template (const char *image_name, const char *wfa_name,
64 bool_t color, char **basename, char **suffix);
65
66 #ifndef X_DISPLAY_MISSING
67
68 static void
69 show_stored_frames (unsigned char * const *frame_buffer, int last_frame,
70 x11_info_t *xinfo, binfo_t *binfo, size_t size,
71 unsigned frame_time);
72
73 #endif /* not X_DISPLAY_MISSING */
74
75 /*****************************************************************************
76
77 public code
78
79 *****************************************************************************/
80
81 int
main(int argc,char ** argv)82 main (int argc, char **argv)
83 {
84 char *image_name = NULL; /* output filename */
85 bool_t double_resolution = NO; /* double resolution of image */
86 bool_t panel = NO; /* control panel */
87 int fps = -1; /* frame display rate */
88 fiasco_d_options_t *options = NULL; /* additional coder options */
89 int last_arg; /* last processed cmdline parameter */
90
91 init_error_handling (argv[0]);
92
93 last_arg = checkargs (argc, argv, &double_resolution, &panel, &fps,
94 &image_name, &options);
95
96 if (last_arg >= argc)
97 video_decoder ("-", image_name, panel, double_resolution, fps, options);
98 else
99 while (last_arg++ < argc)
100 video_decoder (argv [last_arg - 1], image_name, panel,
101 double_resolution, fps, options);
102
103 return 0;
104 }
105
106 /*****************************************************************************
107
108 private code
109
110 *****************************************************************************/
111
112 static param_t params [] =
113 {
114 #ifdef X_DISPLAY_MISSING
115 {"output", "FILE", 'o', PSTR, {0}, "-",
116 "Write raw PNM frame(s) to `%s'."},
117 #else /* not X_DISPLAY_MISSING */
118 {"output", "FILE", 'o', POSTR, {0}, NULL,
119 "Write raw PNM frame(s) to INPUT.ppm/pgm [or `%s']."},
120 #endif /* not X_DISPLAY_MISSING */
121 {"double", NULL, 'd', PFLAG, {0}, "FALSE",
122 "Interpolate images to double size before display."},
123 {"fast", NULL, 'r', PFLAG, {0}, "FALSE",
124 "Use 4:2:0 format for fast, low quality output."},
125 {"panel", NULL, 'p', PFLAG, {0}, "FALSE",
126 "Display control panel."},
127 {"magnify", "NUM", 'm', PINT, {0}, "0",
128 "Magnify/reduce image size by a factor of 4^`%s'."},
129 {"framerate", "NUM", 'F', PINT, {0}, "-1",
130 "Set display rate to `%s' frames per second."},
131 {"smoothing", "NUM", 's', PINT, {0}, "-1",
132 "Smooth image(s) by factor `%s' (0-100)"},
133 {NULL, NULL, 0, 0, {0}, NULL, NULL }
134 };
135
136 static int
checkargs(int argc,char ** argv,bool_t * double_resolution,bool_t * panel,int * fps,char ** image_name,fiasco_d_options_t ** options)137 checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel,
138 int *fps, char **image_name, fiasco_d_options_t **options)
139 /*
140 * Check validness of command line parameters and of the parameter files.
141 *
142 * Return value.
143 * index in argv of the first argv-element that is not an option.
144 *
145 * Side effects:
146 * 'double_resolution', 'panel', 'fps', 'image_name' and 'options'
147 * are modified.
148 */
149 {
150 int optind; /* last processed commandline param */
151
152 optind = parseargs (params, argc, argv,
153 #ifdef X_DISPLAY_MISSING
154 "Decode FIASCO-FILEs and write frame(s) to disk.",
155 #else /* not X_DISPLAY_MISSING */
156 "Decode and display FIASCO-FILEs using X11.",
157 #endif /* not X_DISPLAY_MISSING */
158 "With no FIASCO-FILE, or if FIASCO-FILE is -, "
159 "read standard input.\n"
160 #ifndef X_DISPLAY_MISSING
161 "With --output=[FILE] specified, "
162 "write frames without displaying them.\n\n"
163 #endif /* not X_DISPLAY_MISSING */
164 "Environment:\n"
165 "FIASCO_DATA Search path for automata files. "
166 "Default: ./\n"
167 "FIASCO_IMAGES Save path for image files. "
168 "Default: ./", " [FIASCO-FILE]...",
169 FIASCO_SHARE, "system.fiascorc", ".fiascorc");
170
171 *image_name = (char *) parameter_value (params, "output");
172 *double_resolution = *((bool_t *) parameter_value (params, "double"));
173 *panel = *((bool_t *) parameter_value (params, "panel"));
174 *fps = *((int *) parameter_value (params, "framerate"));
175
176 /*
177 * Additional options ... (have to be set with the fiasco_set_... methods)
178 */
179 *options = fiasco_d_options_new ();
180
181 {
182 int const n = *((int *) parameter_value (params, "smoothing"));
183
184 if (!fiasco_d_options_set_smoothing (*options, MAX(-1, n)))
185 error (fiasco_get_error_message ());
186 }
187
188 {
189 int const n = *((int *) parameter_value (params, "magnify"));
190
191 if (!fiasco_d_options_set_magnification (*options, n))
192 error (fiasco_get_error_message ());
193 }
194
195 {
196 bool_t const n = *((bool_t *) parameter_value (params, "fast"));
197
198 if (!fiasco_d_options_set_4_2_0_format (*options, n > 0 ? YES : NO))
199 error (fiasco_get_error_message ());
200 }
201
202 return optind;
203 }
204
205 static void
video_decoder(const char * wfa_name,const char * image_name,bool_t panel,bool_t double_resolution,int fps,fiasco_d_options_t * options)206 video_decoder (const char *wfa_name, const char *image_name, bool_t panel,
207 bool_t double_resolution, int fps, fiasco_d_options_t *options)
208 {
209 #ifndef X_DISPLAY_MISSING
210 fiasco_renderer_t *renderer = NULL;
211 unsigned char **frame_buffer = NULL;
212 binfo_t *binfo = NULL; /* buttons info */
213 #endif /* not X_DISPLAY_MISSING */
214
215 do
216 {
217 unsigned width, height, frames, n;
218 fiasco_decoder_t *decoder_state;
219 char *filename;
220 char *basename; /* basename of decoded frame */
221 char *suffix; /* suffix of decoded frame */
222 unsigned frame_time;
223
224 if (!(decoder_state = fiasco_decoder_new (wfa_name, options)))
225 error (fiasco_get_error_message ());
226
227 if (fps <= 0) /* then use value of FIASCO file */
228 fps = fiasco_decoder_get_rate (decoder_state);
229 frame_time = fps ? (1000 / fps) : (1000 / 25);
230
231 if (!(width = fiasco_decoder_get_width (decoder_state)))
232 error (fiasco_get_error_message ());
233
234 if (!(height = fiasco_decoder_get_height (decoder_state)))
235 error (fiasco_get_error_message ());
236
237 if (!(frames = fiasco_decoder_get_length (decoder_state)))
238 error (fiasco_get_error_message ());
239
240 get_output_template (image_name, wfa_name,
241 fiasco_decoder_is_color (decoder_state),
242 &basename, &suffix);
243
244 filename = calloc (strlen (basename) + strlen (suffix) + 2
245 + 10 + (int) (log10 (frames) + 1), sizeof (char));
246 if (!filename)
247 error ("Out of memory.");
248
249 for (n = 0; n < frames; n++)
250 {
251 clock_t fps_timer; /* frames per second timer struct */
252
253 prg_timer (&fps_timer, START);
254
255 if (image_name) /* just write frame to disk */
256 {
257 if (frames == 1) /* just one image */
258 {
259 if (streq (image_name, "-"))
260 strcpy (filename, "-");
261 else
262 sprintf (filename, "%s.%s", basename, suffix);
263 }
264 else
265 {
266 fprintf (stderr, "Decoding frame %d to file `%s.%0*d.%s\n",
267 n, basename, (int) (log10 (frames - 1) + 1),
268 n, suffix);
269 sprintf (filename, "%s.%0*d.%s", basename,
270 (int) (log10 (frames - 1) + 1), n, suffix);
271 }
272
273 if (!fiasco_decoder_write_frame (decoder_state, filename))
274 error (fiasco_get_error_message ());
275 }
276 #ifndef X_DISPLAY_MISSING
277 else
278 {
279 fiasco_image_t *frame;
280
281 if (!(frame = fiasco_decoder_get_frame (decoder_state)))
282 error (fiasco_get_error_message ());
283
284 if (frames == 1)
285 panel = NO;
286
287 if (xinfo == NULL) /* initialize X11 window */
288 {
289 const char * const title =
290 fiasco_decoder_get_title (decoder_state);
291 char titlename [MAXSTRLEN];
292
293
294 sprintf (titlename, "dfiasco " VERSION ": %s",
295 strlen (title) > 0 ? title : wfa_name);
296 xinfo =
297 open_window (titlename, "dfiasco",
298 (width << (double_resolution ? 1 : 0)),
299 (height << (double_resolution ? 1 : 0))
300 + (panel ? 30 : 0));
301 alloc_ximage (xinfo, width << (double_resolution ? 1 : 0),
302 height << (double_resolution ? 1 : 0));
303 if (panel) /* initialize button panel */
304 binfo = init_buttons (xinfo, n, frames, 30, 10);
305 renderer =
306 fiasco_renderer_new (xinfo->ximage->red_mask,
307 xinfo->ximage->green_mask,
308 xinfo->ximage->blue_mask,
309 xinfo->ximage->bits_per_pixel,
310 double_resolution);
311 if (!renderer)
312 error (fiasco_get_error_message ());
313 }
314 renderer->render (renderer, xinfo->pixels, frame);
315 frame->delete (frame);
316
317 if (frame_buffer != NULL) /* store next frame */
318 {
319 size_t size = (width << (double_resolution ? 1 : 0))
320 * (height << (double_resolution ? 1 : 0))
321 * (xinfo->ximage->depth <= 8
322 ? sizeof (byte_t)
323 : (xinfo->ximage->depth <= 16
324 ? sizeof (u_word_t)
325 : sizeof (unsigned int)));
326
327 frame_buffer [n] = malloc (size);
328 if (!frame_buffer [n])
329 error ("Out of memory.");
330 memcpy (frame_buffer [n], xinfo->pixels, size);
331
332 if (n == frames - 1)
333 {
334 show_stored_frames (frame_buffer, frames - 1,
335 xinfo, binfo, size, frame_time);
336 break;
337 }
338 }
339
340 display_image (0, 0, xinfo);
341 if (frames == 1)
342 wait_for_input (xinfo);
343 else if (panel)
344 {
345 check_events (xinfo, binfo, n, frames);
346 if (binfo->pressed [QUIT_BUTTON])
347 /* start from beginning */
348 break;
349 if (binfo->pressed [STOP_BUTTON])
350 /* start from beginning */
351 n = frames;
352
353 if (binfo->pressed [RECORD_BUTTON] && frame_buffer == NULL)
354 {
355 n = frames;
356 frame_buffer =
357 calloc (frames, sizeof (unsigned char *));
358 if (!frame_buffer)
359 error ("Out of memory.");
360 }
361 }
362 while (prg_timer (&fps_timer, STOP) < frame_time) /* wait */
363 ;
364 }
365 #else
366 if (frame_time) {/* defeat compiler warning */}
367 #endif /* not X_DISPLAY_MISSING */
368 }
369 free (filename);
370
371 fiasco_decoder_delete (decoder_state);
372 } while (panel
373
374 #ifndef X_DISPLAY_MISSING
375 && !binfo->pressed [QUIT_BUTTON]
376 #endif /* not X_DISPLAY_MISSING */
377
378 );
379
380 #ifndef X_DISPLAY_MISSING
381 if (renderer)
382 renderer->delete (renderer);
383
384 if (!image_name)
385 {
386 close_window (xinfo);
387 free (xinfo);
388 xinfo = NULL;
389 if (binfo)
390 free (binfo);
391 }
392 #endif /* not X_DISPLAY_MISSING */
393 }
394
395 static void
get_output_template(const char * image_name,const char * wfa_name,bool_t color,char ** basename,char ** suffix)396 get_output_template (const char *image_name, const char *wfa_name,
397 bool_t color, char **basename, char **suffix)
398 /*
399 * Generate image filename template for output of image sequences.
400 * 'wfa_name' is the filename of the WFA stream.
401 * Images are either saved with filename 'basename'.'suffix' (still images)
402 * or 'basename'.%03d.'suffix' (videos).
403 *
404 * No return value.
405 *
406 * Side effects:
407 * '*basename' and '*suffix' is set.
408 */
409 {
410 if (!wfa_name || streq (wfa_name, "-"))
411 wfa_name = "stdin";
412 /*
413 * Generate filename template
414 */
415 if (!image_name || streq (image_name, "") || streq (image_name, "-"))
416 {
417 *basename = strdup (wfa_name);
418 *suffix = NULL;
419 }
420 else
421 {
422 *basename = strdup (image_name);
423 *suffix = strrchr (*basename, '.');
424 }
425
426 if (*suffix) /* found name 'basename.suffix' */
427 {
428 **suffix = 0; /* remove dot */
429 (*suffix)++;
430 if (**suffix == 0)
431 *suffix = strdup (color ? "ppm" : "pgm");
432 }
433 else /* no suffix found, generate one */
434 *suffix = strdup (color ? "ppm" : "pgm");
435 }
436
437 #ifndef X_DISPLAY_MISSING
438
439 static void
show_stored_frames(unsigned char * const * frame_buffer,int last_frame,x11_info_t * xinfo,binfo_t * binfo,size_t size,unsigned frame_time)440 show_stored_frames (unsigned char * const *frame_buffer, int last_frame,
441 x11_info_t *xinfo, binfo_t *binfo, size_t size,
442 unsigned frame_time)
443 /*
444 * After a WFA video stream has been saved, all frames have been
445 * decoded and stored in memory. These frames are then displayed
446 * in an endless loop.
447 *
448 * This function never returns, the program is terminated if the
449 * STOP button is pressed.
450 */
451 {
452 int n = last_frame; /* frame number */
453
454 while (1)
455 {
456 clock_t fps_timer; /* frames per second timer struct */
457
458 prg_timer (&fps_timer, START);
459
460 display_image (0, 0, xinfo);
461 check_events (xinfo, binfo, n, last_frame + 1);
462
463 if (binfo->pressed [STOP_BUTTON])
464 n = 0;
465 else if (binfo->pressed [QUIT_BUTTON])
466 break;
467 else if (binfo->pressed [PLAY_BUTTON])
468 n++;
469 else if (binfo->pressed [RECORD_BUTTON]) /* REWIND is mapped RECORD */
470 n--;
471 if (n < 0)
472 n = last_frame;
473 if (n > last_frame)
474 n = 0;
475
476 memcpy (xinfo->pixels, frame_buffer [n], size);
477 while (prg_timer (&fps_timer, STOP) < frame_time) /* wait */
478 ;
479 };
480 }
481
482 #endif /* not X_DISPLAY_MISSING */
483