comparison libvo/vo_pnm.c @ 13394:455a5056801f

New generic 'portable anymap' video output driver. It supports portable pixmaps and graymaps in both raw and ASCII mode. Besides PPM and PGM, it can also output PGMYUV files which are PGM files with the U and V plane appended to the bottom of the Y image (bottom left and bottom right). All files can be written to the current directory, to a specified output directory or to multiple subdirectories if the filesystem can't handle the amount of files in one directory anymore. Note: This driver is not yet activated and will not be compiled and linked to libvo. A separate patch will take care of that. This is just for adding the file to the repository.
author ivo
date Mon, 20 Sep 2004 00:54:57 +0000
parents
children e394a9cfaf3f
comparison
equal deleted inserted replaced
13393:74fa728e6fc2 13394:455a5056801f
1 /* ------------------------------------------------------------------------- */
2
3 /*
4 * vo_pnm.c, PPM/PGM/PGMYUV Video Output Driver for MPlayer
5 *
6 *
7 * Written by Ivo van Poorten. (GPL)2004
8 *
9 *
10 * Changelog
11 *
12 * 2004-09-09 First draft.
13 * 2004-09-16 Second draft. It now acts on VOCTRL_DRAW_IMAGE and does not
14 * maintain a local copy of the image if the format is YV12.
15 * Speed improvement and uses less memory.
16 *
17 *
18 */
19
20 /* ------------------------------------------------------------------------- */
21
22 /* Global Includes */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/stat.h>
29 #include <math.h> /* for log10() */
30
31 /* ------------------------------------------------------------------------- */
32
33 /* Local Includes */
34
35 #include "config.h"
36 #include "mp_msg.h"
37 #include "video_out.h"
38 #include "video_out_internal.h"
39 #include "mplayer.h" /* for exit_player() */
40 #include "help_mp.h"
41
42 /* ------------------------------------------------------------------------- */
43
44 /* Defines */
45
46 /* Used for temporary buffers to store file- and pathnames */
47 #define BUFLENGTH 512
48
49 #define PNM_ASCII_MODE 0
50 #define PNM_RAW_MODE 1
51 #define PNM_TYPE_PPM 0
52 #define PNM_TYPE_PGM 1
53 #define PNM_TYPE_PGMYUV 2
54
55 #define PNM_LINE_OF_ASCII "%03d %03d %03d %03d %03d %03d %03d %03d %03d %03d %03d %03d %03d %03d %03d\n"
56 #define PNM_LINE15(a,b) a[b], a[b+1], a[b+2], a[b+3], a[b+4], a[b+5], a[b+6], \
57 a[b+7], a[b+8], a[b+9], a[b+10], a[b+11], a[b+12], \
58 a[b+13], a[b+14]
59
60 /* ------------------------------------------------------------------------- */
61
62 /* Info */
63
64 static vo_info_t info=
65 {
66 "PPM/PGM/PGMYUV file",
67 "pnm",
68 "Ivo van Poorten (ivop@euronet.nl)",
69 ""
70 };
71
72 LIBVO_EXTERN (pnm)
73
74 /* ------------------------------------------------------------------------- */
75
76 /* Global Variables */
77
78 int pnm_type = PNM_TYPE_PPM;
79 int pnm_mode = PNM_RAW_MODE;
80
81 char *pnm_outdir = NULL;
82 char *pnm_subdirs = NULL;
83 int pnm_maxfiles = 1000;
84 char *pnm_file_extension = NULL;
85
86 /* ------------------------------------------------------------------------- */
87
88 /** \brief Memory allocation failed.
89 *
90 * The video output driver failed to allocate a block of memory it needed.
91 * It displays a message and exits the player.
92 *
93 * \return nothing It does not return.
94 */
95
96 void pnm_malloc_failed(void) {
97 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s\n", info.short_name,
98 MSGTR_MemAllocFailed);
99 exit_player(MSGTR_Exit_error);
100 }
101
102 /* ------------------------------------------------------------------------- */
103
104 /** \brief An error occured while writing to a file.
105 *
106 * The program failed to write data to a file.
107 * It displays a message and exits the player.
108 *
109 * \return nothing It does not return.
110 */
111
112 void pnm_write_error(void) {
113 mp_msg(MSGT_VO, MSGL_ERR, MSGTR_ErrorWritingFile, info.short_name);
114 exit_player(MSGTR_Exit_error);
115 }
116
117 /* ------------------------------------------------------------------------- */
118
119 /** \brief Pre-initialisation.
120 *
121 * This function is called before initialising the video output driver. It
122 * parses all suboptions and sets variables accordingly. If an error occurs
123 * (like an option being out of range, not having any value or an unknown
124 * option is stumbled upon) the player will exit.
125 *
126 * \param arg A string containing all the suboptions passed to the video
127 * output driver.
128 *
129 * \return 0 All went well.
130 */
131
132 static uint32_t preinit(const char *arg)
133 {
134 char *buf; /* buf is used to store parsed string values */
135 int value; /* storage for parsed integer values */
136
137 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
138 MSGTR_VO_ParsingSuboptions);
139
140 if (arg) {
141
142 while (*arg != '\0') {
143 if (!strncmp(arg, ":", 1)) {
144 arg++;
145 continue; /* multiple ':' is not really an error */
146 } if (!strncmp(arg, "ascii", 5)) {
147 arg += 5;
148 pnm_mode = PNM_ASCII_MODE;
149 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
150 MSGTR_VO_PNM_ASCIIMode);
151 } else if (!strncmp(arg, "raw", 3)) {
152 arg += 3;
153 pnm_mode = PNM_RAW_MODE;
154 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
155 MSGTR_VO_PNM_RawMode);
156 } else if (!strncmp(arg, "ppm", 3)) {
157 arg += 3;
158 pnm_type = PNM_TYPE_PPM;
159 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
160 MSGTR_VO_PNM_PPMType);
161 } else if (!strncmp(arg, "pgmyuv", 6)) {
162 arg += 6;
163 pnm_type = PNM_TYPE_PGMYUV;
164 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
165 MSGTR_VO_PNM_PGMYUVType);
166 } else if (!strncmp(arg, "pgm", 3)) {
167 arg += 3;
168 pnm_type = PNM_TYPE_PGM;
169 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
170 MSGTR_VO_PNM_PGMType);
171 } else if (!strncmp(arg, "outdir=", 7)) {
172 arg += 7;
173 buf = malloc(strlen(arg)+1); /* maximum length possible */
174 if (!buf) {
175 pnm_malloc_failed(); /* message and exit_player! */
176 }
177 if (sscanf(arg, "%[^:]", buf) == 1) {
178 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s --> %s\n",
179 info.short_name, "outdir", buf);
180 arg += strlen(buf);
181 pnm_outdir = strdup(buf);
182 if (!pnm_outdir) pnm_malloc_failed();
183 free(buf);
184 } else {
185 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n",
186 info.short_name, "outdir",
187 MSGTR_VO_NoValueSpecified);
188 exit_player(MSGTR_Exit_error);
189 }
190 } else if (!strncmp(arg, "subdirs=", 8)) {
191 arg += 8;
192 buf = malloc(strlen(arg)+1); /* maximum length possible */
193 if (!buf) {
194 pnm_malloc_failed();
195 }
196 if (sscanf(arg, "%[^:]", buf) == 1) {
197 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s --> %s\n",
198 info.short_name, "subdirs", buf);
199 arg += strlen(buf);
200 pnm_subdirs = strdup(buf);
201 if (!pnm_subdirs) pnm_malloc_failed();
202 free(buf);
203 } else {
204 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n",
205 info.short_name, "subdirs",
206 MSGTR_VO_NoValueSpecified);
207 exit_player(MSGTR_Exit_error);
208 }
209 } else if (!strncmp(arg, "maxfiles=", 9)) {
210 arg += 9;
211 if (sscanf(arg, "%d", &value) == 1) {
212 if (value < 1) {
213 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s %s.\n",
214 info.short_name, "maxfiles",
215 MSGTR_VO_ValueOutOfRange, ">=1");
216 exit_player(MSGTR_Exit_error);
217 } else {
218 pnm_maxfiles = value;
219 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s --> %d\n",
220 info.short_name, "maxfiles", value);
221 }
222 } else {
223 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n",
224 info.short_name, "maxfiles",
225 MSGTR_VO_NoValueSpecified);
226 exit_player(MSGTR_Exit_error);
227 }
228 /* only here if value is set and sane */
229 if (value) {
230 arg += (int)log10(value) + 1;
231 } else {
232 arg++; /* log10(0) fails */
233 }
234 } else {
235 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s %-20s...\n", info.short_name,
236 MSGTR_VO_UnknownSuboptions, arg);
237 exit_player(MSGTR_Exit_error);
238 }
239 } /* end while */
240 } /* endif */
241
242 /* If pnm_outdir is not set by an option, resort to default of "." */
243 if (!pnm_outdir) {
244 pnm_outdir = strdup(".");
245 if (!pnm_outdir) pnm_malloc_failed();
246 }
247
248 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s\n", info.short_name,
249 MSGTR_VO_SuboptionsParsedOK);
250 return 0;
251 }
252
253 /* ------------------------------------------------------------------------- */
254
255 /** \brief Create a directory.
256 *
257 * This function creates a directory. If it already exists, it tests if
258 * it's a directory and not something else, and if it is, it tests whether
259 * the directory is writable or not.
260 *
261 * \param buf Pointer to directory name.
262 * \param verbose Verbose on success. If verbose is non-zero, it will print
263 * a message if it was successful in creating the directory.
264 *
265 * \return nothing In case anything fails, the player will exit. If it
266 * returns, everything went well.
267 */
268
269 void pnm_mkdir(char *buf, int verbose) {
270 struct stat stat_p;
271
272 /* Silly MING32 bug workaround */
273 #ifndef __MINGW32__
274 if ( mkdir(buf, 0755) < 0 ) {
275 #else
276 if ( mkdir(buf) < 0 ) {
277 #endif
278 switch (errno) { /* use switch in case other errors need to be caught
279 and handled in the future */
280 case EEXIST:
281 if ( stat(buf, &stat_p ) < 0 ) {
282 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n", info.short_name,
283 MSGTR_VO_GenericError, strerror(errno) );
284 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s %s\n", info.short_name,
285 MSGTR_VO_UnableToAccess,buf);
286 exit_player(MSGTR_Exit_error);
287 }
288 if ( !S_ISDIR(stat_p.st_mode) ) {
289 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s %s\n", info.short_name,
290 buf, MSGTR_VO_ExistsButNoDirectory);
291 exit_player(MSGTR_Exit_error);
292 }
293 if ( !(stat_p.st_mode & S_IWUSR) ) {
294 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n", info.short_name,
295 buf, MSGTR_VO_DirExistsButNotWritable);
296 exit_player(MSGTR_Exit_error);
297 }
298
299 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s - %s\n", info.short_name,
300 buf, MSGTR_VO_DirExistsAndIsWritable);
301 break;
302
303 default:
304 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n", info.short_name,
305 MSGTR_VO_GenericError, strerror(errno) );
306 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s - %s\n", info.short_name,
307 buf, MSGTR_VO_CantCreateDirectory);
308 exit_player(MSGTR_Exit_error);
309 } /* end switch */
310 } else if ( verbose ) {
311 mp_msg(MSGT_VO, MSGL_INFO, "%s: %s - %s\n", info.short_name,
312 buf, MSGTR_VO_DirectoryCreateSuccess);
313 } /* end if */
314 }
315
316 /* ------------------------------------------------------------------------- */
317
318 /** \brief Configure the video output driver.
319 *
320 * This functions configures the video output driver. It determines the
321 * width and height of the image(s) and creates the output directory.
322 *
323 * \return 0 All went well.
324 */
325
326 static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width,
327 uint32_t d_height, uint32_t fullscreen, char *title,
328 uint32_t format)
329 {
330 char buf[BUFLENGTH];
331
332 if (vo_config_count > 0 ) { /* Already configured */
333 return 0;
334 }
335
336 /* Create outdir. */
337
338 snprintf(buf, BUFLENGTH, "%s", pnm_outdir);
339 pnm_mkdir(buf, 1); /* This function only returns if creation was
340 successful. If not, the player will exit. */
341
342 if (pnm_type == PNM_TYPE_PPM) {
343 pnm_file_extension = strdup("ppm");
344 } else if (pnm_type == PNM_TYPE_PGM) {
345 pnm_file_extension = strdup("pgm");
346 } else if (pnm_type == PNM_TYPE_PGMYUV) {
347 pnm_file_extension = strdup("pgmyuv");
348 }
349 if (!pnm_file_extension) pnm_malloc_failed();
350
351 return 0;
352 }
353
354 /* ------------------------------------------------------------------------- */
355
356 /** \brief Write PNM file to output file
357 *
358 * This function writes PPM, PGM or PGMYUV data to an output file, depending
359 * on which type was selected on the commandline. pnm_type and pnm_mode are
360 * global variables. Depending on which mode was selected, it will write
361 * a RAW or an ASCII file.
362 *
363 * \param outfile Filedescriptor of output file.
364 * \param mpi The image to write.
365 *
366 * \return none The player will exit if anything goes wrong.
367 */
368
369 void pnm_write_pnm(FILE *outfile, mp_image_t *mpi)
370 {
371 uint32_t w = mpi->w;
372 uint32_t h = mpi->h;
373 uint8_t *rgbimage = mpi->planes[0];
374 uint8_t *planeY = mpi->planes[0];
375 uint8_t *planeU = mpi->planes[1];
376 uint8_t *planeV = mpi->planes[2];
377 uint8_t *curline;
378 uint32_t strideY = mpi->stride[0];
379 uint32_t strideU = mpi->stride[1];
380 uint32_t strideV = mpi->stride[2];
381
382 int i, j;
383
384 if (pnm_mode == PNM_RAW_MODE) {
385
386 if (pnm_type == PNM_TYPE_PPM) {
387 if ( fprintf(outfile, "P6\n%d %d\n255\n", w, h) < 0 )
388 pnm_write_error();
389 if ( fwrite(rgbimage, w * 3, h, outfile) < h ) pnm_write_error();
390 } else if (pnm_type == PNM_TYPE_PGM) {
391 if ( fprintf(outfile, "P5\n%d %d\n255\n", w, h) < 0 )
392 pnm_write_error();
393 for (i=0; i<h; i++) {
394 if ( fwrite(planeY + i * strideY, w, 1, outfile) < 1 )
395 pnm_write_error();
396 }
397 } else if (pnm_type == PNM_TYPE_PGMYUV) {
398 if ( fprintf(outfile, "P5\n%d %d\n255\n", w, h*3/2) < 0 )
399 pnm_write_error();
400 for (i=0; i<h; i++) {
401 if ( fwrite(planeY + i * strideY, w, 1, outfile) < 1 )
402 pnm_write_error();
403 }
404 w = w / 2;
405 h = h / 2;
406 for (i=0; i<h; i++) {
407 if ( fwrite(planeU + i * strideU, w, 1, outfile) < 1 )
408 pnm_write_error();
409 if ( fwrite(planeV + i * strideV, w, 1, outfile) < 1 )
410 pnm_write_error();
411 }
412 } /* end if pnm_type */
413
414 } else if (pnm_mode == PNM_ASCII_MODE) {
415
416 if (pnm_type == PNM_TYPE_PPM) {
417 if ( fprintf(outfile, "P3\n%d %d\n255\n", w, h) < 0 )
418 pnm_write_error();
419 for (i=0; i <= w * h * 3 - 16 ; i += 15) {
420 if ( fprintf(outfile, PNM_LINE_OF_ASCII,
421 PNM_LINE15(rgbimage,i) ) < 0 ) pnm_write_error();
422 }
423 while (i < (w * h * 3) ) {
424 if ( fprintf(outfile, "%03d ", rgbimage[i]) < 0 )
425 pnm_write_error();
426 i++;
427 }
428 if ( fputc('\n', outfile) < 0 ) pnm_write_error();
429 } else if ( (pnm_type == PNM_TYPE_PGM) ||
430 (pnm_type == PNM_TYPE_PGMYUV) ) {
431
432 /* different header for pgm and pgmyuv. pgmyuv is 'higher' */
433 if (pnm_type == PNM_TYPE_PGM) {
434 if ( fprintf(outfile, "P2\n%d %d\n255\n", w, h) < 0 )
435 pnm_write_error();
436 } else { /* PNM_TYPE_PGMYUV */
437 if ( fprintf(outfile, "P2\n%d %d\n255\n", w, h*3/2) < 0 )
438 pnm_write_error();
439 }
440
441 /* output Y plane for both PGM and PGMYUV */
442 for (j=0; j<h; j++) {
443 curline = planeY + strideY * j;
444 for (i=0; i <= w - 16; i+=15) {
445 if ( fprintf(outfile, PNM_LINE_OF_ASCII,
446 PNM_LINE15(curline,i) ) < 0 ) pnm_write_error();
447 }
448 while (i < w ) {
449 if ( fprintf(outfile, "%03d ", curline[i]) < 0 )
450 pnm_write_error();
451 i++;
452 }
453 if ( fputc('\n', outfile) < 0 ) pnm_write_error();
454 }
455
456 /* also output U and V planes fpr PGMYUV */
457 if (pnm_type == PNM_TYPE_PGMYUV) {
458 w = w / 2;
459 h = h / 2;
460 for (j=0; j<h; j++) {
461 curline = planeU + strideU * j;
462 for (i=0; i<= w-16; i+=15) {
463 if ( fprintf(outfile, PNM_LINE_OF_ASCII,
464 PNM_LINE15(curline,i) ) < 0 ) pnm_write_error();
465 }
466 while (i < w ) {
467 if ( fprintf(outfile, "%03d ", curline[i]) < 0 )
468 pnm_write_error();
469 i++;
470 }
471 if ( fputc('\n', outfile) < 0 ) pnm_write_error();
472
473 curline = planeV + strideV * j;
474 for (i=0; i<= w-16; i+=15) {
475 if ( fprintf(outfile, PNM_LINE_OF_ASCII,
476 PNM_LINE15(curline,i) ) < 0 ) pnm_write_error();
477 }
478 while (i < w ) {
479 if ( fprintf(outfile, "%03d ", curline[i]) < 0 )
480 pnm_write_error();
481 i++;
482 }
483 if ( fputc('\n', outfile) < 0 ) pnm_write_error();
484 }
485 }
486
487 } /* end if pnm_type */
488 } /* end if pnm_mode */
489 }
490
491 /* ------------------------------------------------------------------------- */
492
493 /** \brief Write a PNM image.
494 *
495 * This function gets called first if a PNM image has to be written to disk.
496 * It contains the subdirectory framework and it calls pnm_write_pnm() to
497 * actually write the image to disk.
498 *
499 * \param mpi The image to write.
500 *
501 * \return none The player will exit if anything goes wrong.
502 */
503
504 void pnm_write_image(mp_image_t *mpi)
505 {
506 static uint32_t framenum = 0, framecounter = 0, subdircounter = 0;
507 char buf[BUFLENGTH];
508 static char subdirname[BUFLENGTH] = "";
509 FILE *outfile;
510
511 if (!mpi) {
512 mp_msg(MSGT_VO, MSGL_ERR, "%s: No image data suplied to video output driver\n", info.short_name );
513 exit_player(MSGTR_Exit_error);
514 }
515
516 /* Start writing to new subdirectory after a certain amount of frames */
517 if ( framecounter == pnm_maxfiles ) {
518 framecounter = 0;
519 }
520
521 /* If framecounter is zero (or reset to zero), increment subdirectory
522 * number and create the subdirectory.
523 * If pnm_subdirs is not set, do nothing. */
524 if ( !framecounter && pnm_subdirs ) {
525 subdircounter++;
526 snprintf(subdirname, BUFLENGTH, "%s%08d", pnm_subdirs, subdircounter);
527 snprintf(buf, BUFLENGTH, "%s/%s", pnm_outdir, subdirname);
528 pnm_mkdir(buf, 0); /* This function only returns if creation was
529 successful. If not, the player will exit. */
530 }
531
532 framenum++;
533 framecounter++;
534
535 /* snprintf the full pathname of the outputfile */
536 snprintf(buf, BUFLENGTH, "%s/%s/%08d.%s", pnm_outdir, subdirname,
537 framenum, pnm_file_extension);
538
539 if ( (outfile = fopen(buf, "wb") ) == NULL ) {
540 mp_msg(MSGT_VO, MSGL_ERR, "\n%s: %s\n", info.short_name,
541 MSGTR_VO_CantCreateFile);
542 mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n",
543 info.short_name, MSGTR_VO_GenericError,
544 strerror(errno) );
545 exit_player(MSGTR_Exit_error);
546 }
547
548 pnm_write_pnm(outfile, mpi);
549
550 fclose(outfile);
551 }
552
553 /* ------------------------------------------------------------------------- */
554
555 static uint32_t draw_image(mp_image_t *mpi)
556 {
557 if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Planar */
558 if (mpi->flags & MP_IMGFLAG_YUV) { /* Planar YUV */
559 pnm_write_image(mpi);
560 return VO_TRUE;
561 } else { /* Planar RGB */
562 return VO_FALSE;
563 }
564 } else { /* Packed */
565 if (mpi->flags & MP_IMGFLAG_YUV) { /* Packed YUV */
566 return VO_FALSE;
567 } else { /* Packed RGB */
568 pnm_write_image(mpi);
569 return VO_TRUE;
570 }
571 }
572
573 return VO_FALSE;
574 }
575
576 /* ------------------------------------------------------------------------- */
577
578 static uint32_t draw_frame(uint8_t *src[])
579 {
580 mp_msg(MSGT_VO, MSGL_V, "%s: draw_frame() is called!\n", info.short_name);
581 return -1;
582 }
583
584 /* ------------------------------------------------------------------------- */
585
586 static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h,
587 int x, int y)
588 {
589 return 0;
590 }
591
592 /* ------------------------------------------------------------------------- */
593
594 static uint32_t query_format(uint32_t format)
595 {
596 /* Ensure that for PPM we get Packed RGB and for PGM(YUV) we get
597 * Planar YUV */
598 if (pnm_type == PNM_TYPE_PPM) {
599 if (format == IMGFMT_RGB24) {
600 return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW;
601 }
602 } else if ( (pnm_type == PNM_TYPE_PGM) || (pnm_type == PNM_TYPE_PGMYUV) ) {
603 if (format == IMGFMT_YV12) {
604 return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW;
605 }
606 }
607
608 return 0;
609 }
610
611 /* ------------------------------------------------------------------------- */
612
613 static uint32_t control(uint32_t request, void *data, ...)
614 {
615 switch (request) {
616 case VOCTRL_QUERY_FORMAT:
617 return query_format(*((uint32_t*)data));
618 case VOCTRL_DRAW_IMAGE:
619 return draw_image(data);
620 }
621 return VO_NOTIMPL;
622 }
623
624 /* ------------------------------------------------------------------------- */
625
626 static void uninit(void)
627 {
628 if (pnm_subdirs) {
629 free(pnm_subdirs);
630 pnm_subdirs = NULL;
631 }
632 if (pnm_outdir) {
633 free(pnm_outdir);
634 pnm_outdir = NULL;
635 }
636 }
637
638 /* ------------------------------------------------------------------------- */
639
640 static void check_events(void)
641 {
642 }
643
644 /* ------------------------------------------------------------------------- */
645
646 static void draw_osd(void)
647 {
648 }
649
650 /* ------------------------------------------------------------------------- */
651
652 static void flip_page (void)
653 {
654 }
655
656 /* ------------------------------------------------------------------------- */
657
658 #undef BUFLENGTH
659 #undef PNM_RAW_MODE
660 #undef PNM_ASCII_MODE
661 #undef PNM_TYPE_PPM
662 #undef PNM_TYPE_PGM
663 #undef PNM_TYPE_PGMYUV
664
665 /* ------------------------------------------------------------------------- */
666