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