Mercurial > libavformat.hg
annotate img.c @ 8:995bb04e02f1 libavformat
* Add code to allow the img reader to read files at the nominal frame rate.
This (will) allow testing of ffserver in an automated way. The code is nasty
in that it uses a global.......
author | philipjsg |
---|---|
date | Wed, 11 Dec 2002 03:18:47 +0000 |
parents | 05318cf2e886 |
children | 7e1ff5580f27 |
rev | line source |
---|---|
0 | 1 /* |
2 * Image format | |
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
8
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
19 #include <unistd.h> |
0 | 20 #include "avformat.h" |
21 | |
22 extern AVInputFormat pgm_iformat; | |
23 extern AVOutputFormat pgm_oformat; | |
24 extern AVInputFormat pgmyuv_iformat; | |
25 extern AVOutputFormat pgmyuv_oformat; | |
26 extern AVInputFormat ppm_iformat; | |
27 extern AVOutputFormat ppm_oformat; | |
28 extern AVInputFormat imgyuv_iformat; | |
29 extern AVOutputFormat imgyuv_oformat; | |
30 extern AVInputFormat pgmpipe_iformat; | |
31 extern AVOutputFormat pgmpipe_oformat; | |
32 extern AVInputFormat pgmyuvpipe_iformat; | |
33 extern AVOutputFormat pgmyuvpipe_oformat; | |
34 extern AVInputFormat ppmpipe_iformat; | |
35 extern AVOutputFormat ppmpipe_oformat; | |
36 extern AVOutputFormat yuv4mpegpipe_oformat; | |
37 | |
38 #define IMGFMT_YUV 1 | |
39 #define IMGFMT_PGMYUV 2 | |
40 #define IMGFMT_PGM 3 | |
41 #define IMGFMT_PPM 4 | |
42 #define IMGFMT_YUV4MPEG 5 | |
43 | |
44 #define Y4M_MAGIC "YUV4MPEG2" | |
45 #define Y4M_FRAME_MAGIC "FRAME" | |
46 #define Y4M_LINE_MAX 256 | |
47 | |
48 typedef struct { | |
49 int width; | |
50 int height; | |
51 int img_number; | |
52 int img_size; | |
53 int img_fmt; | |
54 int is_pipe; | |
55 int header_written; | |
56 char path[1024]; | |
57 } VideoData; | |
58 | |
8
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
59 int emulate_frame_rate; |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
60 |
0 | 61 static inline int pnm_space(int c) |
62 { | |
63 return (c==' ' || c=='\n' || c=='\r' || c=='\t'); | |
64 } | |
65 | |
66 static void pnm_get(ByteIOContext *f, char *str, int buf_size) | |
67 { | |
68 char *s; | |
69 int c; | |
70 | |
71 do { | |
72 c=get_byte(f); | |
73 if (c=='#') { | |
74 do { | |
75 c=get_byte(f); | |
76 } while (c!='\n'); | |
77 c=get_byte(f); | |
78 } | |
79 } while (pnm_space(c)); | |
80 | |
81 s=str; | |
82 do { | |
83 if (url_feof(f)) | |
84 break; | |
85 if ((s - str) < buf_size - 1) | |
86 *s++=c; | |
87 c=get_byte(f); | |
88 } while (!pnm_space(c)); | |
89 *s = '\0'; | |
90 } | |
91 | |
92 static int pgm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size, int is_yuv) | |
93 { | |
94 int width, height, i; | |
95 char buf1[32]; | |
96 UINT8 *picture[3]; | |
97 | |
98 width = s->width; | |
99 height = s->height; | |
100 | |
101 pnm_get(f, buf1, sizeof(buf1)); | |
102 if (strcmp(buf1, "P5")) { | |
103 return -EIO; | |
104 } | |
105 pnm_get(f, buf1, sizeof(buf1)); | |
106 pnm_get(f, buf1, sizeof(buf1)); | |
107 pnm_get(f, buf1, sizeof(buf1)); | |
108 | |
109 picture[0] = buf; | |
110 picture[1] = buf + width * height; | |
111 picture[2] = buf + width * height + (width * height / 4); | |
112 get_buffer(f, picture[0], width * height); | |
113 | |
114 height>>=1; | |
115 width>>=1; | |
116 if (is_yuv) { | |
117 for(i=0;i<height;i++) { | |
118 get_buffer(f, picture[1] + i * width, width); | |
119 get_buffer(f, picture[2] + i * width, width); | |
120 } | |
121 } else { | |
122 for(i=0;i<height;i++) { | |
123 memset(picture[1] + i * width, 128, width); | |
124 memset(picture[2] + i * width, 128, width); | |
125 } | |
126 } | |
127 return 0; | |
128 } | |
129 | |
130 static int ppm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size) | |
131 { | |
132 int width, height; | |
133 char buf1[32]; | |
134 UINT8 *picture[3]; | |
135 | |
136 width = s->width; | |
137 height = s->height; | |
138 | |
139 pnm_get(f, buf1, sizeof(buf1)); | |
140 if (strcmp(buf1, "P6")) { | |
141 return -EIO; | |
142 } | |
143 | |
144 pnm_get(f, buf1, sizeof(buf1)); | |
145 pnm_get(f, buf1, sizeof(buf1)); | |
146 pnm_get(f, buf1, sizeof(buf1)); | |
147 | |
148 picture[0] = buf; | |
149 get_buffer(f, picture[0], width * height*3); | |
150 | |
151 return 0; | |
152 | |
153 } | |
154 | |
155 static int yuv_read(VideoData *s, const char *filename, UINT8 *buf, int size1) | |
156 { | |
157 ByteIOContext pb1, *pb = &pb1; | |
158 char fname[1024], *p; | |
159 int size; | |
160 | |
161 size = s->width * s->height; | |
162 | |
163 strcpy(fname, filename); | |
164 p = strrchr(fname, '.'); | |
165 if (!p || p[1] != 'Y') | |
166 return -EIO; | |
167 | |
168 if (url_fopen(pb, fname, URL_RDONLY) < 0) | |
169 return -EIO; | |
170 | |
171 get_buffer(pb, buf, size); | |
172 url_fclose(pb); | |
173 | |
174 p[1] = 'U'; | |
175 if (url_fopen(pb, fname, URL_RDONLY) < 0) | |
176 return -EIO; | |
177 | |
178 get_buffer(pb, buf + size, size / 4); | |
179 url_fclose(pb); | |
180 | |
181 p[1] = 'V'; | |
182 if (url_fopen(pb, fname, URL_RDONLY) < 0) | |
183 return -EIO; | |
184 | |
185 get_buffer(pb, buf + size + (size / 4), size / 4); | |
186 url_fclose(pb); | |
187 return 0; | |
188 } | |
189 | |
190 static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) | |
191 { | |
192 VideoData *s = s1->priv_data; | |
193 char filename[1024]; | |
194 int ret; | |
195 ByteIOContext f1, *f; | |
8
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
196 static INT64 first_frame; |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
197 |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
198 if (emulate_frame_rate) { |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
199 if (!first_frame) { |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
200 first_frame = av_gettime(); |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
201 } else { |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
202 INT64 pts; |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
203 INT64 nowus; |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
204 |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
205 nowus = av_gettime() - first_frame; |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
206 |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
207 pts = ((INT64)s->img_number * FRAME_RATE_BASE * 1000000) / (s1->streams[0]->codec.frame_rate); |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
208 |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
209 if (pts > nowus) |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
210 usleep(pts - nowus); |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
211 } |
995bb04e02f1
* Add code to allow the img reader to read files at the nominal frame rate.
philipjsg
parents:
0
diff
changeset
|
212 } |
0 | 213 |
214 /* | |
215 This if-statement destroys pipes - I do not see why it is necessary | |
216 if (get_frame_filename(filename, sizeof(filename), | |
217 s->path, s->img_number) < 0) | |
218 return -EIO; | |
219 */ | |
220 get_frame_filename(filename, sizeof(filename), | |
221 s->path, s->img_number); | |
222 if (!s->is_pipe) { | |
223 f = &f1; | |
224 if (url_fopen(f, filename, URL_RDONLY) < 0) | |
225 return -EIO; | |
226 } else { | |
227 f = &s1->pb; | |
228 if (url_feof(f)) | |
229 return -EIO; | |
230 } | |
231 | |
232 av_new_packet(pkt, s->img_size); | |
233 pkt->stream_index = 0; | |
234 | |
235 switch(s->img_fmt) { | |
236 case IMGFMT_PGMYUV: | |
237 ret = pgm_read(s, f, pkt->data, pkt->size, 1); | |
238 break; | |
239 case IMGFMT_PGM: | |
240 ret = pgm_read(s, f, pkt->data, pkt->size, 0); | |
241 break; | |
242 case IMGFMT_YUV: | |
243 ret = yuv_read(s, filename, pkt->data, pkt->size); | |
244 break; | |
245 case IMGFMT_PPM: | |
246 ret = ppm_read(s, f, pkt->data, pkt->size); | |
247 break; | |
248 default: | |
249 return -EIO; | |
250 } | |
251 | |
252 if (!s->is_pipe) { | |
253 url_fclose(f); | |
254 } | |
255 | |
256 if (ret < 0) { | |
257 av_free_packet(pkt); | |
258 return -EIO; /* signal EOF */ | |
259 } else { | |
260 pkt->pts = ((INT64)s->img_number * s1->pts_den * FRAME_RATE_BASE) / (s1->streams[0]->codec.frame_rate * s1->pts_num); | |
261 s->img_number++; | |
262 return 0; | |
263 } | |
264 } | |
265 | |
266 static int sizes[][2] = { | |
267 { 640, 480 }, | |
268 { 720, 480 }, | |
269 { 720, 576 }, | |
270 { 352, 288 }, | |
271 { 352, 240 }, | |
272 { 160, 128 }, | |
273 { 512, 384 }, | |
274 { 640, 352 }, | |
275 { 640, 240 }, | |
276 }; | |
277 | |
278 static int infer_size(int *width_ptr, int *height_ptr, int size) | |
279 { | |
280 int i; | |
281 | |
282 for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) { | |
283 if ((sizes[i][0] * sizes[i][1]) == size) { | |
284 *width_ptr = sizes[i][0]; | |
285 *height_ptr = sizes[i][1]; | |
286 return 0; | |
287 } | |
288 } | |
289 return -1; | |
290 } | |
291 | |
292 static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) | |
293 { | |
294 VideoData *s = s1->priv_data; | |
295 int i, h; | |
296 char buf[1024]; | |
297 char buf1[32]; | |
298 ByteIOContext pb1, *f = &pb1; | |
299 AVStream *st; | |
300 | |
301 st = av_new_stream(s1, 0); | |
302 if (!st) { | |
303 av_free(s); | |
304 return -ENOMEM; | |
305 } | |
306 | |
307 strcpy(s->path, s1->filename); | |
308 s->img_number = 0; | |
309 | |
310 /* find format */ | |
311 if (s1->iformat->flags & AVFMT_NOFILE) | |
312 s->is_pipe = 0; | |
313 else | |
314 s->is_pipe = 1; | |
315 | |
316 if (s1->iformat == &pgmyuvpipe_iformat || | |
317 s1->iformat == &pgmyuv_iformat) | |
318 s->img_fmt = IMGFMT_PGMYUV; | |
319 else if (s1->iformat == &pgmpipe_iformat || | |
320 s1->iformat == &pgm_iformat) | |
321 s->img_fmt = IMGFMT_PGM; | |
322 else if (s1->iformat == &imgyuv_iformat) | |
323 s->img_fmt = IMGFMT_YUV; | |
324 else if (s1->iformat == &ppmpipe_iformat || | |
325 s1->iformat == &ppm_iformat) | |
326 s->img_fmt = IMGFMT_PPM; | |
327 else | |
328 goto fail; | |
329 | |
330 if (!s->is_pipe) { | |
331 /* try to find the first image */ | |
332 for(i=0;i<5;i++) { | |
333 if (get_frame_filename(buf, sizeof(buf), s->path, s->img_number) < 0) | |
334 goto fail; | |
335 if (url_fopen(f, buf, URL_RDONLY) >= 0) | |
336 break; | |
337 s->img_number++; | |
338 } | |
339 if (i == 5) | |
340 goto fail; | |
341 } else { | |
342 f = &s1->pb; | |
343 } | |
344 | |
345 /* find the image size */ | |
346 /* XXX: use generic file format guessing, as mpeg */ | |
347 switch(s->img_fmt) { | |
348 case IMGFMT_PGM: | |
349 case IMGFMT_PGMYUV: | |
350 case IMGFMT_PPM: | |
351 pnm_get(f, buf1, sizeof(buf1)); | |
352 pnm_get(f, buf1, sizeof(buf1)); | |
353 s->width = atoi(buf1); | |
354 pnm_get(f, buf1, sizeof(buf1)); | |
355 h = atoi(buf1); | |
356 if (s->img_fmt == IMGFMT_PGMYUV) | |
357 h = (h * 2) / 3; | |
358 s->height = h; | |
359 if (s->width <= 0 || | |
360 s->height <= 0 || | |
361 (s->width % 2) != 0 || | |
362 (s->height % 2) != 0) { | |
363 goto fail1; | |
364 } | |
365 break; | |
366 case IMGFMT_YUV: | |
367 /* infer size by using the file size. */ | |
368 { | |
369 int img_size; | |
370 URLContext *h; | |
371 | |
372 /* XXX: hack hack */ | |
373 h = url_fileno(f); | |
374 img_size = url_seek(h, 0, SEEK_END); | |
375 if (infer_size(&s->width, &s->height, img_size) < 0) { | |
376 goto fail1; | |
377 } | |
378 } | |
379 break; | |
380 } | |
381 | |
382 | |
383 if (!s->is_pipe) { | |
384 url_fclose(f); | |
385 } else { | |
386 url_fseek(f, 0, SEEK_SET); | |
387 } | |
388 | |
389 | |
390 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
391 st->codec.codec_id = CODEC_ID_RAWVIDEO; | |
392 st->codec.width = s->width; | |
393 st->codec.height = s->height; | |
394 if (s->img_fmt == IMGFMT_PPM) { | |
395 st->codec.pix_fmt = PIX_FMT_RGB24; | |
396 s->img_size = (s->width * s->height * 3); | |
397 } else { | |
398 st->codec.pix_fmt = PIX_FMT_YUV420P; | |
399 s->img_size = (s->width * s->height * 3) / 2; | |
400 } | |
401 if (!ap || !ap->frame_rate) | |
402 st->codec.frame_rate = 25 * FRAME_RATE_BASE; | |
403 else | |
404 st->codec.frame_rate = ap->frame_rate; | |
405 | |
406 return 0; | |
407 fail1: | |
408 if (!s->is_pipe) | |
409 url_fclose(f); | |
410 fail: | |
411 av_free(s); | |
412 return -EIO; | |
413 } | |
414 | |
415 static int img_read_close(AVFormatContext *s1) | |
416 { | |
417 return 0; | |
418 } | |
419 | |
420 /******************************************************/ | |
421 /* image output */ | |
422 | |
423 static int pgm_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int is_yuv) | |
424 { | |
425 int i, h; | |
426 char buf[100]; | |
427 UINT8 *ptr, *ptr1, *ptr2; | |
428 | |
429 h = height; | |
430 if (is_yuv) | |
431 h = (height * 3) / 2; | |
432 snprintf(buf, sizeof(buf), | |
433 "P5\n%d %d\n%d\n", | |
434 width, h, 255); | |
435 put_buffer(pb, buf, strlen(buf)); | |
436 | |
437 ptr = picture->data[0]; | |
438 for(i=0;i<height;i++) { | |
439 put_buffer(pb, ptr, width); | |
440 ptr += picture->linesize[0]; | |
441 } | |
442 | |
443 if (is_yuv) { | |
444 height >>= 1; | |
445 width >>= 1; | |
446 ptr1 = picture->data[1]; | |
447 ptr2 = picture->data[2]; | |
448 for(i=0;i<height;i++) { | |
449 put_buffer(pb, ptr1, width); | |
450 put_buffer(pb, ptr2, width); | |
451 ptr1 += picture->linesize[1]; | |
452 ptr2 += picture->linesize[2]; | |
453 } | |
454 } | |
455 put_flush_packet(pb); | |
456 return 0; | |
457 } | |
458 | |
459 static int ppm_save(AVPicture *picture, int width, int height, ByteIOContext *pb) | |
460 { | |
461 int i; | |
462 char buf[100]; | |
463 UINT8 *ptr; | |
464 | |
465 snprintf(buf, sizeof(buf), | |
466 "P6\n%d %d\n%d\n", | |
467 width, height, 255); | |
468 put_buffer(pb, buf, strlen(buf)); | |
469 | |
470 ptr = picture->data[0]; | |
471 for(i=0;i<height;i++) { | |
472 put_buffer(pb, ptr, width * 3); | |
473 ptr += picture->linesize[0]; | |
474 } | |
475 | |
476 put_flush_packet(pb); | |
477 return 0; | |
478 } | |
479 | |
480 static int yuv_save(AVPicture *picture, int width, int height, const char *filename) | |
481 { | |
482 ByteIOContext pb1, *pb = &pb1; | |
483 char fname[1024], *p; | |
484 int i, j; | |
485 UINT8 *ptr; | |
486 static char *ext = "YUV"; | |
487 | |
488 strcpy(fname, filename); | |
489 p = strrchr(fname, '.'); | |
490 if (!p || p[1] != 'Y') | |
491 return -EIO; | |
492 | |
493 for(i=0;i<3;i++) { | |
494 if (i == 1) { | |
495 width >>= 1; | |
496 height >>= 1; | |
497 } | |
498 | |
499 p[1] = ext[i]; | |
500 if (url_fopen(pb, fname, URL_WRONLY) < 0) | |
501 return -EIO; | |
502 | |
503 ptr = picture->data[i]; | |
504 for(j=0;j<height;j++) { | |
505 put_buffer(pb, ptr, width); | |
506 ptr += picture->linesize[i]; | |
507 } | |
508 put_flush_packet(pb); | |
509 url_fclose(pb); | |
510 } | |
511 return 0; | |
512 } | |
513 | |
514 static int yuv4mpeg_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int need_stream_header, | |
515 int is_yuv, int raten, int rated, int aspectn, int aspectd) | |
516 { | |
517 int i, n, m; | |
518 char buf[Y4M_LINE_MAX+1], buf1[20]; | |
519 UINT8 *ptr, *ptr1, *ptr2; | |
520 | |
521 /* construct stream header, if this is the first frame */ | |
522 if(need_stream_header) { | |
523 n = snprintf(buf, sizeof(buf), "%s W%d H%d F%d:%d I%s A%d:%d\n", | |
524 Y4M_MAGIC, | |
525 width, | |
526 height, | |
527 raten, rated, | |
528 "p", /* ffmpeg seems to only output progressive video */ | |
529 aspectn, aspectd); | |
530 if (n < 0) { | |
531 fprintf(stderr, "Error. YUV4MPEG stream header write failed.\n"); | |
532 } else { | |
533 fprintf(stderr, "YUV4MPEG stream header written. FPS is %d\n", raten); | |
534 put_buffer(pb, buf, strlen(buf)); | |
535 } | |
536 } | |
537 | |
538 /* construct frame header */ | |
539 m = snprintf(buf1, sizeof(buf1), "%s \n", Y4M_FRAME_MAGIC); | |
540 if (m < 0) { | |
541 fprintf(stderr, "Error. YUV4MPEG frame header write failed.\n"); | |
542 } else { | |
543 /* fprintf(stderr, "YUV4MPEG frame header written.\n"); */ | |
544 put_buffer(pb, buf1, strlen(buf1)); | |
545 } | |
546 | |
547 ptr = picture->data[0]; | |
548 for(i=0;i<height;i++) { | |
549 put_buffer(pb, ptr, width); | |
550 ptr += picture->linesize[0]; | |
551 } | |
552 | |
553 if (is_yuv) { | |
554 height >>= 1; | |
555 width >>= 1; | |
556 ptr1 = picture->data[1]; | |
557 ptr2 = picture->data[2]; | |
558 for(i=0;i<height;i++) { /* Cb */ | |
559 put_buffer(pb, ptr1, width); | |
560 ptr1 += picture->linesize[1]; | |
561 } | |
562 for(i=0;i<height;i++) { /* Cr */ | |
563 put_buffer(pb, ptr2, width); | |
564 ptr2 += picture->linesize[2]; | |
565 } | |
566 } | |
567 put_flush_packet(pb); | |
568 return 0; | |
569 } | |
570 | |
571 static int img_write_header(AVFormatContext *s) | |
572 { | |
573 VideoData *img = s->priv_data; | |
574 | |
575 img->img_number = 1; | |
576 strcpy(img->path, s->filename); | |
577 | |
578 /* find format */ | |
579 if (s->oformat->flags & AVFMT_NOFILE) | |
580 img->is_pipe = 0; | |
581 else | |
582 img->is_pipe = 1; | |
583 | |
584 if (s->oformat == &pgmyuvpipe_oformat || | |
585 s->oformat == &pgmyuv_oformat) { | |
586 img->img_fmt = IMGFMT_PGMYUV; | |
587 } else if (s->oformat == &pgmpipe_oformat || | |
588 s->oformat == &pgm_oformat) { | |
589 img->img_fmt = IMGFMT_PGM; | |
590 } else if (s->oformat == &imgyuv_oformat) { | |
591 img->img_fmt = IMGFMT_YUV; | |
592 } else if (s->oformat == &ppmpipe_oformat || | |
593 s->oformat == &ppm_oformat) { | |
594 img->img_fmt = IMGFMT_PPM; | |
595 } else if (s->oformat == &yuv4mpegpipe_oformat) { | |
596 img->img_fmt = IMGFMT_YUV4MPEG; | |
597 img->header_written = 0; | |
598 } else { | |
599 goto fail; | |
600 } | |
601 return 0; | |
602 fail: | |
603 av_free(img); | |
604 return -EIO; | |
605 } | |
606 | |
607 static int img_write_packet(AVFormatContext *s, int stream_index, | |
608 UINT8 *buf, int size, int force_pts) | |
609 { | |
610 VideoData *img = s->priv_data; | |
611 AVStream *st = s->streams[stream_index]; | |
612 ByteIOContext pb1, *pb; | |
613 AVPicture picture; | |
614 int width, height, need_stream_header, ret, size1, raten, rated, aspectn, aspectd, fps, fps1; | |
615 char filename[1024]; | |
616 | |
617 width = st->codec.width; | |
618 height = st->codec.height; | |
619 | |
620 if (img->img_number == 1) { | |
621 need_stream_header = 1; | |
622 } else { | |
623 need_stream_header = 0; | |
624 } | |
625 | |
626 fps = st->codec.frame_rate; | |
627 fps1 = (((float)fps / FRAME_RATE_BASE) * 1000); | |
628 | |
629 /* Sorry about this messy code, but mpeg2enc is very picky about | |
630 * the framerates it accepts. */ | |
631 switch(fps1) { | |
632 case 23976: | |
633 raten = 24000; /* turn the framerate into a ratio */ | |
634 rated = 1001; | |
635 break; | |
636 case 29970: | |
637 raten = 30000; | |
638 rated = 1001; | |
639 break; | |
640 case 25000: | |
641 raten = 25; | |
642 rated = 1; | |
643 break; | |
644 case 30000: | |
645 raten = 30; | |
646 rated = 1; | |
647 break; | |
648 case 24000: | |
649 raten = 24; | |
650 rated = 1; | |
651 break; | |
652 case 50000: | |
653 raten = 50; | |
654 rated = 1; | |
655 break; | |
656 case 59940: | |
657 raten = 60000; | |
658 rated = 1001; | |
659 break; | |
660 case 60000: | |
661 raten = 60; | |
662 rated = 1; | |
663 break; | |
664 default: | |
665 raten = fps1; /* this setting should work, but often doesn't */ | |
666 rated = 1000; | |
667 break; | |
668 } | |
669 | |
670 aspectn = 1; | |
671 aspectd = 1; /* ffmpeg always uses a 1:1 aspect ratio */ | |
672 | |
673 switch(st->codec.pix_fmt) { | |
674 case PIX_FMT_YUV420P: | |
675 size1 = (width * height * 3) / 2; | |
676 if (size != size1) | |
677 return -EIO; | |
678 | |
679 picture.data[0] = buf; | |
680 picture.data[1] = picture.data[0] + width * height; | |
681 picture.data[2] = picture.data[1] + (width * height) / 4; | |
682 picture.linesize[0] = width; | |
683 picture.linesize[1] = width >> 1; | |
684 picture.linesize[2] = width >> 1; | |
685 break; | |
686 case PIX_FMT_RGB24: | |
687 size1 = (width * height * 3); | |
688 if (size != size1) | |
689 return -EIO; | |
690 picture.data[0] = buf; | |
691 picture.linesize[0] = width * 3; | |
692 break; | |
693 default: | |
694 return -EIO; | |
695 } | |
696 | |
697 /* | |
698 This if-statement destroys pipes - I do not see why it is necessary | |
699 if (get_frame_filename(filename, sizeof(filename), | |
700 img->path, img->img_number) < 0) | |
701 return -EIO; | |
702 */ | |
703 get_frame_filename(filename, sizeof(filename), | |
704 img->path, img->img_number); | |
705 if (!img->is_pipe) { | |
706 pb = &pb1; | |
707 if (url_fopen(pb, filename, URL_WRONLY) < 0) | |
708 return -EIO; | |
709 } else { | |
710 pb = &s->pb; | |
711 } | |
712 switch(img->img_fmt) { | |
713 case IMGFMT_PGMYUV: | |
714 ret = pgm_save(&picture, width, height, pb, 1); | |
715 break; | |
716 case IMGFMT_PGM: | |
717 ret = pgm_save(&picture, width, height, pb, 0); | |
718 break; | |
719 case IMGFMT_YUV: | |
720 ret = yuv_save(&picture, width, height, filename); | |
721 break; | |
722 case IMGFMT_PPM: | |
723 ret = ppm_save(&picture, width, height, pb); | |
724 break; | |
725 case IMGFMT_YUV4MPEG: | |
726 ret = yuv4mpeg_save(&picture, width, height, pb, | |
727 need_stream_header, 1, raten, rated, aspectn, aspectd); | |
728 break; | |
729 } | |
730 if (!img->is_pipe) { | |
731 url_fclose(pb); | |
732 } | |
733 | |
734 img->img_number++; | |
735 return 0; | |
736 } | |
737 | |
738 static int img_write_trailer(AVFormatContext *s) | |
739 { | |
740 return 0; | |
741 } | |
742 | |
743 static AVInputFormat pgm_iformat = { | |
744 "pgm", | |
745 "pgm image format", | |
746 sizeof(VideoData), | |
747 NULL, | |
748 img_read_header, | |
749 img_read_packet, | |
750 img_read_close, | |
751 NULL, | |
752 AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |
753 .extensions = "pgm", | |
754 }; | |
755 | |
756 static AVOutputFormat pgm_oformat = { | |
757 "pgm", | |
758 "pgm image format", | |
759 "", | |
760 "pgm", | |
761 sizeof(VideoData), | |
762 CODEC_ID_NONE, | |
763 CODEC_ID_RAWVIDEO, | |
764 img_write_header, | |
765 img_write_packet, | |
766 img_write_trailer, | |
767 AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |
768 }; | |
769 | |
770 static AVInputFormat pgmyuv_iformat = { | |
771 "pgmyuv", | |
772 "pgm with YUV content image format", | |
773 sizeof(VideoData), | |
774 NULL, /* no probe */ | |
775 img_read_header, | |
776 img_read_packet, | |
777 img_read_close, | |
778 NULL, | |
779 AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |
780 }; | |
781 | |
782 static AVOutputFormat pgmyuv_oformat = { | |
783 "pgmyuv", | |
784 "pgm with YUV content image format", | |
785 "", | |
786 "pgm", | |
787 sizeof(VideoData), | |
788 CODEC_ID_NONE, | |
789 CODEC_ID_RAWVIDEO, | |
790 img_write_header, | |
791 img_write_packet, | |
792 img_write_trailer, | |
793 AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |
794 }; | |
795 | |
796 static AVInputFormat ppm_iformat = { | |
797 "ppm", | |
798 "ppm image format", | |
799 sizeof(VideoData), | |
800 NULL, | |
801 img_read_header, | |
802 img_read_packet, | |
803 img_read_close, | |
804 NULL, | |
805 AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RGB24, | |
806 .extensions = "ppm", | |
807 }; | |
808 | |
809 static AVOutputFormat ppm_oformat = { | |
810 "ppm", | |
811 "ppm image format", | |
812 "", | |
813 "ppm", | |
814 sizeof(VideoData), | |
815 CODEC_ID_NONE, | |
816 CODEC_ID_RAWVIDEO, | |
817 img_write_header, | |
818 img_write_packet, | |
819 img_write_trailer, | |
820 AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RGB24, | |
821 }; | |
822 | |
823 static AVInputFormat imgyuv_iformat = { | |
824 ".Y.U.V", | |
825 ".Y.U.V format", | |
826 sizeof(VideoData), | |
827 NULL, | |
828 img_read_header, | |
829 img_read_packet, | |
830 img_read_close, | |
831 NULL, | |
832 AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |
833 .extensions = "Y", | |
834 }; | |
835 | |
836 static AVOutputFormat imgyuv_oformat = { | |
837 ".Y.U.V", | |
838 ".Y.U.V format", | |
839 "", | |
840 "Y", | |
841 sizeof(VideoData), | |
842 CODEC_ID_NONE, | |
843 CODEC_ID_RAWVIDEO, | |
844 img_write_header, | |
845 img_write_packet, | |
846 img_write_trailer, | |
847 AVFMT_NOFILE | AVFMT_NEEDNUMBER, | |
848 }; | |
849 | |
850 static AVInputFormat pgmpipe_iformat = { | |
851 "pgmpipe", | |
852 "PGM pipe format", | |
853 sizeof(VideoData), | |
854 NULL, /* no probe */ | |
855 img_read_header, | |
856 img_read_packet, | |
857 img_read_close, | |
858 NULL, | |
859 }; | |
860 | |
861 static AVOutputFormat pgmpipe_oformat = { | |
862 "pgmpipe", | |
863 "PGM pipe format", | |
864 "", | |
865 "pgm", | |
866 sizeof(VideoData), | |
867 CODEC_ID_NONE, | |
868 CODEC_ID_RAWVIDEO, | |
869 img_write_header, | |
870 img_write_packet, | |
871 img_write_trailer, | |
872 }; | |
873 | |
874 static AVInputFormat pgmyuvpipe_iformat = { | |
875 "pgmyuvpipe", | |
876 "PGM YUV pipe format", | |
877 sizeof(VideoData), | |
878 NULL, /* no probe */ | |
879 img_read_header, | |
880 img_read_packet, | |
881 img_read_close, | |
882 NULL, | |
883 }; | |
884 | |
885 static AVOutputFormat pgmyuvpipe_oformat = { | |
886 "pgmyuvpipe", | |
887 "PGM YUV pipe format", | |
888 "", | |
889 "pgm", | |
890 sizeof(VideoData), | |
891 CODEC_ID_NONE, | |
892 CODEC_ID_RAWVIDEO, | |
893 img_write_header, | |
894 img_write_packet, | |
895 img_write_trailer, | |
896 }; | |
897 | |
898 static AVInputFormat ppmpipe_iformat = { | |
899 "ppmpipe", | |
900 "PPM pipe format", | |
901 sizeof(VideoData), | |
902 NULL, /* no probe */ | |
903 img_read_header, | |
904 img_read_packet, | |
905 img_read_close, | |
906 NULL, | |
907 .flags = AVFMT_RGB24, | |
908 }; | |
909 | |
910 static AVOutputFormat ppmpipe_oformat = { | |
911 "ppmpipe", | |
912 "PPM pipe format", | |
913 "", | |
914 "ppm", | |
915 sizeof(VideoData), | |
916 CODEC_ID_NONE, | |
917 CODEC_ID_RAWVIDEO, | |
918 img_write_header, | |
919 img_write_packet, | |
920 img_write_trailer, | |
921 .flags = AVFMT_RGB24, | |
922 }; | |
923 | |
924 | |
925 static AVOutputFormat yuv4mpegpipe_oformat = { | |
926 "yuv4mpegpipe", | |
927 "YUV4MPEG pipe format", | |
928 "", | |
929 "yuv4mpeg", | |
930 sizeof(VideoData), | |
931 CODEC_ID_NONE, | |
932 CODEC_ID_RAWVIDEO, | |
933 img_write_header, | |
934 img_write_packet, | |
935 img_write_trailer, | |
936 }; | |
937 | |
938 | |
939 int img_init(void) | |
940 { | |
941 av_register_input_format(&pgm_iformat); | |
942 av_register_output_format(&pgm_oformat); | |
943 | |
944 av_register_input_format(&pgmyuv_iformat); | |
945 av_register_output_format(&pgmyuv_oformat); | |
946 | |
947 av_register_input_format(&ppm_iformat); | |
948 av_register_output_format(&ppm_oformat); | |
949 | |
950 av_register_input_format(&imgyuv_iformat); | |
951 av_register_output_format(&imgyuv_oformat); | |
952 | |
953 av_register_input_format(&pgmpipe_iformat); | |
954 av_register_output_format(&pgmpipe_oformat); | |
955 | |
956 av_register_input_format(&pgmyuvpipe_iformat); | |
957 av_register_output_format(&pgmyuvpipe_oformat); | |
958 | |
959 av_register_input_format(&ppmpipe_iformat); | |
960 av_register_output_format(&ppmpipe_oformat); | |
961 | |
962 av_register_output_format(&yuv4mpegpipe_oformat); | |
963 | |
964 return 0; | |
965 } |