merge
[libav.git] / libav / img.c
1 /*
2 * Image format
3 * Copyright (c) 2000, 2001 Gerard Lantau.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <math.h>
26
27 #include "avformat.h"
28
29 #define IMGFMT_YUV 1
30 #define IMGFMT_PGMYUV 2
31 #define IMGFMT_PGM 3
32
33 typedef struct {
34 int width;
35 int height;
36 int img_number;
37 int img_size;
38 int img_fmt;
39 int is_pipe;
40 char path[1024];
41 } VideoData;
42
43 static inline int pnm_space(int c)
44 {
45 return (c==' ' || c=='\n' || c=='\r' || c=='\t');
46 }
47
48 static void pnm_get(ByteIOContext *f, char *str, int buf_size)
49 {
50 char *s;
51 int c;
52
53 do {
54 c=get_byte(f);
55 if (c=='#') {
56 do {
57 c=get_byte(f);
58 } while (c!='\n');
59 c=get_byte(f);
60 }
61 } while (pnm_space(c));
62
63 s=str;
64 do {
65 if (url_feof(f))
66 break;
67 if ((s - str) < buf_size - 1)
68 *s++=c;
69 c=get_byte(f);
70 } while (!pnm_space(c));
71 *s = '\0';
72 }
73
74 static int pgm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size, int is_yuv)
75 {
76 int width, height, i;
77 char buf1[32];
78 UINT8 *picture[3];
79
80 width = s->width;
81 height = s->height;
82
83 pnm_get(f, buf1, sizeof(buf1));
84 if (strcmp(buf1, "P5")) {
85 return -EIO;
86 }
87 pnm_get(f, buf1, sizeof(buf1));
88 pnm_get(f, buf1, sizeof(buf1));
89 pnm_get(f, buf1, sizeof(buf1));
90
91 picture[0] = buf;
92 picture[1] = buf + width * height;
93 picture[2] = buf + width * height + (width * height / 4);
94 get_buffer(f, picture[0], width * height);
95
96 height>>=1;
97 width>>=1;
98 if (is_yuv) {
99 for(i=0;i<height;i++) {
100 get_buffer(f, picture[1] + i * width, width);
101 get_buffer(f, picture[2] + i * width, width);
102 }
103 } else {
104 for(i=0;i<height;i++) {
105 memset(picture[1] + i * width, 128, width);
106 memset(picture[2] + i * width, 128, width);
107 }
108 }
109 return 0;
110 }
111
112 static int yuv_read(VideoData *s, const char *filename, UINT8 *buf, int size1)
113 {
114 ByteIOContext pb1, *pb = &pb1;
115 char fname[1024], *p;
116 int size;
117
118 size = s->width * s->height;
119
120 strcpy(fname, filename);
121 p = strrchr(fname, '.');
122 if (!p || p[1] != 'Y')
123 return -EIO;
124
125 if (url_fopen(pb, fname, URL_RDONLY) < 0)
126 return -EIO;
127
128 get_buffer(pb, buf, size);
129 url_fclose(pb);
130
131 p[1] = 'U';
132 if (url_fopen(pb, fname, URL_RDONLY) < 0)
133 return -EIO;
134
135 get_buffer(pb, buf + size, size / 4);
136 url_fclose(pb);
137
138 p[1] = 'V';
139 if (url_fopen(pb, fname, URL_RDONLY) < 0)
140 return -EIO;
141
142 get_buffer(pb, buf + size + (size / 4), size / 4);
143 url_fclose(pb);
144 return 0;
145 }
146
147 int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
148 {
149 VideoData *s = s1->priv_data;
150 char filename[1024];
151 int ret;
152 ByteIOContext f1, *f;
153
154 snprintf(filename, sizeof(filename), s->path, s->img_number);
155
156 if (!s->is_pipe) {
157 f = &f1;
158 if (url_fopen(f, filename, URL_RDONLY) < 0)
159 return -EIO;
160 } else {
161 f = &s1->pb;
162 if (url_feof(f))
163 return -EIO;
164 }
165
166 av_new_packet(pkt, s->img_size);
167 pkt->stream_index = 0;
168
169 switch(s->img_fmt) {
170 case IMGFMT_PGMYUV:
171 ret = pgm_read(s, f, pkt->data, pkt->size, 1);
172 break;
173 case IMGFMT_PGM:
174 ret = pgm_read(s, f, pkt->data, pkt->size, 0);
175 break;
176 case IMGFMT_YUV:
177 ret = yuv_read(s, filename, pkt->data, pkt->size);
178 break;
179 default:
180 return -EIO;
181 }
182
183 if (!s->is_pipe) {
184 url_fclose(f);
185 }
186
187 if (ret < 0) {
188 av_free_packet(pkt);
189 return -EIO; /* signal EOF */
190 } else {
191 s->img_number++;
192 return 0;
193 }
194 }
195
196 static int sizes[][2] = {
197 { 640, 480 },
198 { 720, 480 },
199 { 720, 576 },
200 { 352, 288 },
201 { 352, 240 },
202 { 160, 128 },
203 { 512, 384 },
204 { 640, 352 },
205 };
206
207 static int infer_size(int *width_ptr, int *height_ptr, int size)
208 {
209 int i;
210
211 for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
212 if ((sizes[i][0] * sizes[i][1]) == size) {
213 *width_ptr = sizes[i][0];
214 *height_ptr = sizes[i][1];
215 return 0;
216 }
217 }
218 return -1;
219 }
220
221 static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap)
222 {
223 VideoData *s;
224 int i, h;
225 char buf[1024];
226 char buf1[32];
227 ByteIOContext pb1, *f = &pb1;
228 AVStream *st;
229
230 s = malloc(sizeof(VideoData));
231 if (!s)
232 return -ENOMEM;
233
234 s1->priv_data = s;
235
236 s1->nb_streams = 1;
237 st = av_mallocz(sizeof(AVStream));
238 if (!st) {
239 free(s);
240 return -ENOMEM;
241 }
242 s1->streams[0] = st;
243
244 strcpy(s->path, s1->filename);
245 s->img_number = 0;
246
247 /* find format */
248 if (s1->format->flags & AVFMT_NOFILE)
249 s->is_pipe = 0;
250 else
251 s->is_pipe = 1;
252
253 if (s1->format == &pgmpipe_format ||
254 s1->format == &pgmyuv_format)
255 s->img_fmt = IMGFMT_PGMYUV;
256 else if (s1->format == &pgm_format)
257 s->img_fmt = IMGFMT_PGM;
258 else if (s1->format == &imgyuv_format)
259 s->img_fmt = IMGFMT_YUV;
260 else
261 goto fail;
262
263 if (!s->is_pipe) {
264 /* try to find the first image */
265 for(i=0;i<5;i++) {
266 snprintf(buf, sizeof(buf), s->path, s->img_number);
267 if (url_fopen(f, buf, URL_RDONLY) >= 0)
268 break;
269 s->img_number++;
270 }
271 if (i == 5)
272 goto fail;
273 } else {
274 f = &s1->pb;
275 }
276
277 /* find the image size */
278 /* XXX: use generic file format guessing, as mpeg */
279 switch(s->img_fmt) {
280 case IMGFMT_PGM:
281 case IMGFMT_PGMYUV:
282 pnm_get(f, buf1, sizeof(buf1));
283 pnm_get(f, buf1, sizeof(buf1));
284 s->width = atoi(buf1);
285 pnm_get(f, buf1, sizeof(buf1));
286 h = atoi(buf1);
287 if (s->img_fmt == IMGFMT_PGMYUV)
288 h = (h * 2) / 3;
289 s->height = h;
290 if (s->width <= 0 ||
291 s->height <= 0 ||
292 (s->width % 2) != 0 ||
293 (s->height % 2) != 0) {
294 goto fail1;
295 }
296 break;
297 case IMGFMT_YUV:
298 /* infer size by using the file size. */
299 {
300 int img_size;
301 URLContext *h;
302
303 /* XXX: hack hack */
304 h = url_fileno(f);
305 img_size = lseek((int)h->priv_data, 0, SEEK_END);
306 if (infer_size(&s->width, &s->height, img_size) < 0) {
307 goto fail1;
308 }
309 }
310 break;
311 }
312
313 if (!s->is_pipe) {
314 url_fclose(f);
315 } else {
316 url_fseek(f, 0, SEEK_SET);
317 }
318
319 s->img_size = (s->width * s->height * 3) / 2;
320
321 st->codec.codec_type = CODEC_TYPE_VIDEO;
322 st->codec.codec_id = CODEC_ID_RAWVIDEO;
323 st->codec.width = s->width;
324 st->codec.height = s->height;
325 st->codec.pix_fmt = PIX_FMT_YUV420P;
326 if (!ap || !ap->frame_rate)
327 st->codec.frame_rate = 25 * FRAME_RATE_BASE;
328 else
329 st->codec.frame_rate = ap->frame_rate;
330
331 return 0;
332 fail1:
333 if (!s->is_pipe)
334 url_fclose(f);
335 fail:
336 free(s);
337 return -EIO;
338 }
339
340 static int img_read_close(AVFormatContext *s1)
341 {
342 VideoData *s = s1->priv_data;
343 free(s);
344 return 0;
345 }
346
347 /******************************************************/
348 /* image output */
349
350 int pgm_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int is_yuv)
351 {
352 int i, h;
353 char buf[100];
354 UINT8 *ptr, *ptr1, *ptr2;
355
356 h = height;
357 if (is_yuv)
358 h = (height * 3) / 2;
359 snprintf(buf, sizeof(buf),
360 "P5\n%d %d\n%d\n",
361 width, h, 255);
362 put_buffer(pb, buf, strlen(buf));
363
364 ptr = picture->data[0];
365 for(i=0;i<height;i++) {
366 put_buffer(pb, ptr, width);
367 ptr += picture->linesize[0];
368 }
369
370 if (is_yuv) {
371 height >>= 1;
372 width >>= 1;
373 ptr1 = picture->data[1];
374 ptr2 = picture->data[2];
375 for(i=0;i<height;i++) {
376 put_buffer(pb, ptr1, width);
377 put_buffer(pb, ptr2, width);
378 ptr1 += picture->linesize[1];
379 ptr2 += picture->linesize[2];
380 }
381 }
382 put_flush_packet(pb);
383 return 0;
384 }
385
386 static int yuv_save(AVPicture *picture, int width, int height, const char *filename)
387 {
388 ByteIOContext pb1, *pb = &pb1;
389 char fname[1024], *p;
390 int i, j;
391 UINT8 *ptr;
392 static char *ext = "YUV";
393
394 strcpy(fname, filename);
395 p = strrchr(fname, '.');
396 if (!p || p[1] != 'Y')
397 return -EIO;
398
399 for(i=0;i<3;i++) {
400 if (i == 1) {
401 width >>= 1;
402 height >>= 1;
403 }
404
405 p[1] = ext[i];
406 if (url_fopen(pb, fname, URL_WRONLY) < 0)
407 return -EIO;
408
409 ptr = picture->data[i];
410 for(j=0;j<height;j++) {
411 put_buffer(pb, ptr, width);
412 ptr += picture->linesize[i];
413 }
414 put_flush_packet(pb);
415 url_fclose(pb);
416 }
417 return 0;
418 }
419
420 static int img_write_header(AVFormatContext *s)
421 {
422 VideoData *img;
423
424 img = av_mallocz(sizeof(VideoData));
425 if (!img)
426 return -1;
427 s->priv_data = img;
428 img->img_number = 1;
429 strcpy(img->path, s->filename);
430
431 /* find format */
432 if (s->format->flags & AVFMT_NOFILE)
433 img->is_pipe = 0;
434 else
435 img->is_pipe = 1;
436
437 if (s->format == &pgmpipe_format ||
438 s->format == &pgmyuv_format)
439 img->img_fmt = IMGFMT_PGMYUV;
440 else if (s->format == &pgm_format)
441 img->img_fmt = IMGFMT_PGM;
442 else if (s->format == &imgyuv_format)
443 img->img_fmt = IMGFMT_YUV;
444 else
445 goto fail;
446 return 0;
447 fail:
448 free(img);
449 return -EIO;
450 }
451
452 static int img_write_packet(AVFormatContext *s, int stream_index,
453 UINT8 *buf, int size)
454 {
455 VideoData *img = s->priv_data;
456 AVStream *st = s->streams[stream_index];
457 ByteIOContext pb1, *pb;
458 AVPicture picture;
459 int width, height, ret, size1;
460 char filename[1024];
461
462 width = st->codec.width;
463 height = st->codec.height;
464 size1 = (width * height * 3) / 2;
465 if (size != size1)
466 return -EIO;
467
468 picture.data[0] = buf;
469 picture.data[1] = picture.data[0] + width * height;
470 picture.data[2] = picture.data[1] + (width * height) / 4;
471 picture.linesize[0] = width;
472 picture.linesize[1] = width >> 1;
473 picture.linesize[2] = width >> 1;
474 snprintf(filename, sizeof(filename), img->path, img->img_number);
475
476 if (!img->is_pipe) {
477 pb = &pb1;
478 if (url_fopen(pb, filename, URL_WRONLY) < 0)
479 return -EIO;
480 } else {
481 pb = &s->pb;
482 }
483 switch(img->img_fmt) {
484 case IMGFMT_PGMYUV:
485 ret = pgm_save(&picture, width, height, pb, 1);
486 break;
487 case IMGFMT_PGM:
488 ret = pgm_save(&picture, width, height, pb, 0);
489 break;
490 case IMGFMT_YUV:
491 ret = yuv_save(&picture, width, height, filename);
492 break;
493 }
494 if (!img->is_pipe) {
495 url_fclose(pb);
496 }
497
498 img->img_number++;
499 return 0;
500 }
501
502 static int img_write_trailer(AVFormatContext *s)
503 {
504 VideoData *img = s->priv_data;
505 free(img);
506 return 0;
507 }
508
509 AVFormat pgm_format = {
510 "pgm",
511 "pgm image format",
512 "",
513 "pgm",
514 CODEC_ID_NONE,
515 CODEC_ID_RAWVIDEO,
516 img_write_header,
517 img_write_packet,
518 img_write_trailer,
519
520 img_read_header,
521 img_read_packet,
522 img_read_close,
523 NULL,
524 AVFMT_NOFILE,
525 };
526
527 AVFormat pgmyuv_format = {
528 "pgmyuv",
529 "pgm with YUV content image format",
530 "",
531 "pgm",
532 CODEC_ID_NONE,
533 CODEC_ID_RAWVIDEO,
534 img_write_header,
535 img_write_packet,
536 img_write_trailer,
537
538 img_read_header,
539 img_read_packet,
540 img_read_close,
541 NULL,
542 AVFMT_NOFILE,
543 };
544
545 AVFormat imgyuv_format = {
546 ".Y.U.V",
547 ".Y.U.V format",
548 "",
549 "Y",
550 CODEC_ID_NONE,
551 CODEC_ID_RAWVIDEO,
552 img_write_header,
553 img_write_packet,
554 img_write_trailer,
555
556 img_read_header,
557 img_read_packet,
558 img_read_close,
559 NULL,
560 AVFMT_NOFILE,
561 };
562
563 AVFormat pgmpipe_format = {
564 "pgmpipe",
565 "PGM pipe format",
566 "",
567 "pgm",
568 CODEC_ID_NONE,
569 CODEC_ID_RAWVIDEO,
570 img_write_header,
571 img_write_packet,
572 img_write_trailer,
573
574 img_read_header,
575 img_read_packet,
576 img_read_close,
577 NULL,
578 };