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