Mercurial > mplayer.hg
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 |