]> git.sesse.net Git - ffmpeg/blob - libav/img.c
new codec: Sorenson v1
[ffmpeg] / libav / img.c
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  */
19 #include "avformat.h"
20
21 extern AVInputFormat pgm_iformat;
22 extern AVOutputFormat pgm_oformat;
23 extern AVInputFormat pgmyuv_iformat;
24 extern AVOutputFormat pgmyuv_oformat;
25 extern AVInputFormat ppm_iformat;
26 extern AVOutputFormat ppm_oformat;
27 extern AVInputFormat imgyuv_iformat;
28 extern AVOutputFormat imgyuv_oformat;
29 extern AVInputFormat pgmpipe_iformat;
30 extern AVOutputFormat pgmpipe_oformat;
31 extern AVInputFormat pgmyuvpipe_iformat;
32 extern AVOutputFormat pgmyuvpipe_oformat;
33 extern AVInputFormat ppmpipe_iformat;
34 extern AVOutputFormat ppmpipe_oformat;
35
36 #define IMGFMT_YUV     1
37 #define IMGFMT_PGMYUV  2
38 #define IMGFMT_PGM     3
39 #define IMGFMT_PPM     4
40
41 typedef struct {
42     int width;
43     int height;
44     int img_number;
45     int img_size;
46     int img_fmt;
47     int is_pipe;
48     char path[1024];
49 } VideoData;
50
51 static inline int pnm_space(int c)  
52 {
53     return (c==' ' || c=='\n' || c=='\r' || c=='\t');
54 }
55
56 static void pnm_get(ByteIOContext *f, char *str, int buf_size) 
57 {
58     char *s;
59     int c;
60     
61     do  {
62         c=get_byte(f);
63         if (c=='#')  {
64             do  {
65                 c=get_byte(f);
66             } while (c!='\n');
67             c=get_byte(f);
68         }
69     } while (pnm_space(c));
70     
71     s=str;
72     do  {
73         if (url_feof(f))
74             break;
75         if ((s - str)  < buf_size - 1)
76             *s++=c;
77         c=get_byte(f);
78     } while (!pnm_space(c));
79     *s = '\0';
80 }
81
82 static int pgm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size, int is_yuv)
83 {
84     int width, height, i;
85     char buf1[32];
86     UINT8 *picture[3];
87
88     width = s->width;
89     height = s->height;
90
91     pnm_get(f, buf1, sizeof(buf1));
92     if (strcmp(buf1, "P5")) {
93         return -EIO;
94     }
95     pnm_get(f, buf1, sizeof(buf1));
96     pnm_get(f, buf1, sizeof(buf1));
97     pnm_get(f, buf1, sizeof(buf1));
98     
99     picture[0] = buf;
100     picture[1] = buf + width * height;
101     picture[2] = buf + width * height + (width * height / 4);
102     get_buffer(f, picture[0], width * height);
103     
104     height>>=1;
105     width>>=1;
106     if (is_yuv) {
107         for(i=0;i<height;i++) {
108             get_buffer(f, picture[1] + i * width, width);
109             get_buffer(f, picture[2] + i * width, width);
110         }
111     } else {
112         for(i=0;i<height;i++) {
113             memset(picture[1] + i * width, 128, width);
114             memset(picture[2] + i * width, 128, width);
115         }
116     }
117     return 0;
118 }
119
120 static int ppm_read(VideoData *s, ByteIOContext *f, UINT8 *buf, int size)
121 {
122     int width, height;
123     char buf1[32];
124     UINT8 *picture[3];
125
126     width = s->width;
127     height = s->height;
128
129     pnm_get(f, buf1, sizeof(buf1));
130     if (strcmp(buf1, "P6")) {
131         return -EIO;
132     }
133     
134     pnm_get(f, buf1, sizeof(buf1));
135     pnm_get(f, buf1, sizeof(buf1));
136     pnm_get(f, buf1, sizeof(buf1));
137     
138     picture[0] = buf;
139     get_buffer(f, picture[0], width * height*3);
140     
141     return 0;
142
143 }
144
145 static int yuv_read(VideoData *s, const char *filename, UINT8 *buf, int size1)
146 {
147     ByteIOContext pb1, *pb = &pb1;
148     char fname[1024], *p;
149     int size;
150
151     size = s->width * s->height;
152     
153     strcpy(fname, filename);
154     p = strrchr(fname, '.');
155     if (!p || p[1] != 'Y')
156         return -EIO;
157
158     if (url_fopen(pb, fname, URL_RDONLY) < 0)
159         return -EIO;
160     
161     get_buffer(pb, buf, size);
162     url_fclose(pb);
163     
164     p[1] = 'U';
165     if (url_fopen(pb, fname, URL_RDONLY) < 0)
166         return -EIO;
167
168     get_buffer(pb, buf + size, size / 4);
169     url_fclose(pb);
170     
171     p[1] = 'V';
172     if (url_fopen(pb, fname, URL_RDONLY) < 0)
173         return -EIO;
174
175     get_buffer(pb, buf + size + (size / 4), size / 4);
176     url_fclose(pb);
177     return 0;
178 }
179
180 static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
181 {
182     VideoData *s = s1->priv_data;
183     char filename[1024];
184     int ret;
185     ByteIOContext f1, *f;
186
187 /*
188     This if-statement destroys pipes - I do not see why it is necessary
189     if (get_frame_filename(filename, sizeof(filename),
190                            s->path, s->img_number) < 0)
191         return -EIO;
192 */
193     get_frame_filename(filename, sizeof(filename),
194                        s->path, s->img_number);
195     if (!s->is_pipe) {
196         f = &f1;
197         if (url_fopen(f, filename, URL_RDONLY) < 0)
198             return -EIO;
199     } else {
200         f = &s1->pb;
201         if (url_feof(f))
202             return -EIO;
203     }
204
205     av_new_packet(pkt, s->img_size);
206     pkt->stream_index = 0;
207
208     switch(s->img_fmt) {
209     case IMGFMT_PGMYUV:
210         ret = pgm_read(s, f, pkt->data, pkt->size, 1);
211         break;
212     case IMGFMT_PGM:
213         ret = pgm_read(s, f, pkt->data, pkt->size, 0);
214         break;
215     case IMGFMT_YUV:
216         ret = yuv_read(s, filename, pkt->data, pkt->size);
217         break;
218     case IMGFMT_PPM:
219         ret = ppm_read(s, f, pkt->data, pkt->size);
220         break;
221     default:
222         return -EIO;
223     }
224     
225     if (!s->is_pipe) {
226         url_fclose(f);
227     }
228
229     if (ret < 0) {
230         av_free_packet(pkt);
231         return -EIO; /* signal EOF */
232     } else {
233         s->img_number++;
234         return 0;
235     }
236 }
237
238 static int sizes[][2] = {
239     { 640, 480 },
240     { 720, 480 },
241     { 720, 576 },
242     { 352, 288 },
243     { 352, 240 },
244     { 160, 128 },
245     { 512, 384 },
246     { 640, 352 },
247     { 640, 240 },
248 };
249
250 static int infer_size(int *width_ptr, int *height_ptr, int size)
251 {
252     int i;
253
254     for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
255         if ((sizes[i][0] * sizes[i][1]) == size) {
256             *width_ptr = sizes[i][0];
257             *height_ptr = sizes[i][1];
258             return 0;
259         }
260     }
261     return -1;
262 }
263
264 static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap)
265 {
266     VideoData *s = s1->priv_data;
267     int i, h;
268     char buf[1024];
269     char buf1[32];
270     ByteIOContext pb1, *f = &pb1;
271     AVStream *st;
272
273     st = av_new_stream(s1, 0);
274     if (!st) {
275         av_free(s);
276         return -ENOMEM;
277     }
278
279     strcpy(s->path, s1->filename);
280     s->img_number = 0;
281
282     /* find format */
283     if (s1->iformat->flags & AVFMT_NOFILE)
284         s->is_pipe = 0;
285     else
286         s->is_pipe = 1;
287         
288     if (s1->iformat == &pgmyuvpipe_iformat ||
289         s1->iformat == &pgmyuv_iformat)
290         s->img_fmt = IMGFMT_PGMYUV;
291     else if (s1->iformat == &pgmpipe_iformat ||
292              s1->iformat == &pgm_iformat)
293         s->img_fmt = IMGFMT_PGM;
294     else if (s1->iformat == &imgyuv_iformat)
295         s->img_fmt = IMGFMT_YUV;
296     else if (s1->iformat == &ppmpipe_iformat ||
297              s1->iformat == &ppm_iformat)
298         s->img_fmt = IMGFMT_PPM;
299     else
300         goto fail;
301
302     if (!s->is_pipe) {
303         /* try to find the first image */
304         for(i=0;i<5;i++) {
305             if (get_frame_filename(buf, sizeof(buf), s->path, s->img_number) < 0)
306                 goto fail;
307             if (url_fopen(f, buf, URL_RDONLY) >= 0)
308                 break;
309             s->img_number++;
310         }
311         if (i == 5)
312             goto fail;
313     } else {
314         f = &s1->pb;
315     }
316     
317     /* find the image size */
318     /* XXX: use generic file format guessing, as mpeg */
319     switch(s->img_fmt) {
320     case IMGFMT_PGM:
321     case IMGFMT_PGMYUV:
322     case IMGFMT_PPM:
323         pnm_get(f, buf1, sizeof(buf1));
324         pnm_get(f, buf1, sizeof(buf1));
325         s->width = atoi(buf1);
326         pnm_get(f, buf1, sizeof(buf1));
327         h = atoi(buf1);
328         if (s->img_fmt == IMGFMT_PGMYUV)
329             h = (h * 2) / 3;
330         s->height = h;
331         if (s->width <= 0 ||
332             s->height <= 0 ||
333             (s->width % 2) != 0 ||
334             (s->height % 2) != 0) {
335             goto fail1;
336         }
337         break;
338     case IMGFMT_YUV:
339         /* infer size by using the file size. */
340         {
341             int img_size;
342             URLContext *h;
343
344             /* XXX: hack hack */
345             h = url_fileno(f);
346             img_size = url_seek(h, 0, SEEK_END);
347             if (infer_size(&s->width, &s->height, img_size) < 0) {
348                 goto fail1;
349             }
350         }
351         break;
352     }
353
354     if (!s->is_pipe) {
355         url_fclose(f);
356     } else {
357         url_fseek(f, 0, SEEK_SET);
358     }
359     
360
361     st->codec.codec_type = CODEC_TYPE_VIDEO;
362     st->codec.codec_id = CODEC_ID_RAWVIDEO;
363     st->codec.width = s->width;
364     st->codec.height = s->height;
365     if (s->img_fmt == IMGFMT_PPM) {
366         st->codec.pix_fmt = PIX_FMT_RGB24;
367         s->img_size = (s->width * s->height * 3);
368     } else {
369         st->codec.pix_fmt = PIX_FMT_YUV420P;
370         s->img_size = (s->width * s->height * 3) / 2;
371     }
372     if (!ap || !ap->frame_rate)
373         st->codec.frame_rate = 25 * FRAME_RATE_BASE;
374     else
375         st->codec.frame_rate = ap->frame_rate;
376     
377     return 0;
378  fail1:
379     if (!s->is_pipe)
380         url_fclose(f);
381  fail:
382     av_free(s);
383     return -EIO;
384 }
385
386 static int img_read_close(AVFormatContext *s1)
387 {
388     return 0;
389 }
390
391 /******************************************************/
392 /* image output */
393
394 static int pgm_save(AVPicture *picture, int width, int height, ByteIOContext *pb, int is_yuv) 
395 {
396     int i, h;
397     char buf[100];
398     UINT8 *ptr, *ptr1, *ptr2;
399
400     h = height;
401     if (is_yuv)
402         h = (height * 3) / 2;
403     snprintf(buf, sizeof(buf), 
404              "P5\n%d %d\n%d\n",
405              width, h, 255);
406     put_buffer(pb, buf, strlen(buf));
407     
408     ptr = picture->data[0];
409     for(i=0;i<height;i++) {
410         put_buffer(pb, ptr, width);
411         ptr += picture->linesize[0];
412     }
413
414     if (is_yuv) {
415         height >>= 1;
416         width >>= 1;
417         ptr1 = picture->data[1];
418         ptr2 = picture->data[2];
419         for(i=0;i<height;i++) {
420             put_buffer(pb, ptr1, width);
421             put_buffer(pb, ptr2, width);
422             ptr1 += picture->linesize[1];
423             ptr2 += picture->linesize[2];
424         }
425     }
426     put_flush_packet(pb);
427     return 0;
428 }
429
430 static int ppm_save(AVPicture *picture, int width, int height, ByteIOContext *pb) 
431 {
432     int i;
433     char buf[100];
434     UINT8 *ptr;
435
436     snprintf(buf, sizeof(buf), 
437              "P6\n%d %d\n%d\n",
438              width, height, 255);
439     put_buffer(pb, buf, strlen(buf));
440     
441     ptr = picture->data[0];
442     for(i=0;i<height;i++) {
443         put_buffer(pb, ptr, width * 3);
444         ptr += picture->linesize[0];
445     }
446
447     put_flush_packet(pb);
448     return 0;
449 }
450
451 static int yuv_save(AVPicture *picture, int width, int height, const char *filename)
452 {
453     ByteIOContext pb1, *pb = &pb1;
454     char fname[1024], *p;
455     int i, j;
456     UINT8 *ptr;
457     static char *ext = "YUV";
458
459     strcpy(fname, filename);
460     p = strrchr(fname, '.');
461     if (!p || p[1] != 'Y')
462         return -EIO;
463
464     for(i=0;i<3;i++) {
465         if (i == 1) {
466             width >>= 1;
467             height >>= 1;
468         }
469
470         p[1] = ext[i];
471         if (url_fopen(pb, fname, URL_WRONLY) < 0)
472             return -EIO;
473     
474         ptr = picture->data[i];
475         for(j=0;j<height;j++) {
476             put_buffer(pb, ptr, width);
477             ptr += picture->linesize[i];
478         }
479         put_flush_packet(pb);
480         url_fclose(pb);
481     }
482     return 0;
483 }
484
485 static int img_write_header(AVFormatContext *s)
486 {
487     VideoData *img = s->priv_data;
488
489     img->img_number = 1;
490     strcpy(img->path, s->filename);
491
492     /* find format */
493     if (s->oformat->flags & AVFMT_NOFILE)
494         img->is_pipe = 0;
495     else
496         img->is_pipe = 1;
497         
498     if (s->oformat == &pgmyuvpipe_oformat ||
499         s->oformat == &pgmyuv_oformat) {
500         img->img_fmt = IMGFMT_PGMYUV;
501     } else if (s->oformat == &pgmpipe_oformat ||
502                s->oformat == &pgm_oformat) {
503         img->img_fmt = IMGFMT_PGM;
504     } else if (s->oformat == &imgyuv_oformat) {
505         img->img_fmt = IMGFMT_YUV;
506     } else if (s->oformat == &ppmpipe_oformat ||
507                s->oformat == &ppm_oformat) {
508         img->img_fmt = IMGFMT_PPM;
509     } else {
510         goto fail;
511     }
512     return 0;
513  fail:
514     av_free(img);
515     return -EIO;
516 }
517
518 static int img_write_packet(AVFormatContext *s, int stream_index,
519                             UINT8 *buf, int size, int force_pts)
520 {
521     VideoData *img = s->priv_data;
522     AVStream *st = s->streams[stream_index];
523     ByteIOContext pb1, *pb;
524     AVPicture picture;
525     int width, height, ret, size1;
526     char filename[1024];
527
528     width = st->codec.width;
529     height = st->codec.height;
530
531     switch(st->codec.pix_fmt) {
532     case PIX_FMT_YUV420P:
533         size1 = (width * height * 3) / 2;
534         if (size != size1)
535             return -EIO;
536         
537         picture.data[0] = buf;
538         picture.data[1] = picture.data[0] + width * height;
539         picture.data[2] = picture.data[1] + (width * height) / 4;
540         picture.linesize[0] = width;
541         picture.linesize[1] = width >> 1; 
542         picture.linesize[2] = width >> 1;
543         break;
544     case PIX_FMT_RGB24:
545         size1 = (width * height * 3);
546         if (size != size1)
547             return -EIO;
548         picture.data[0] = buf;
549         picture.linesize[0] = width * 3;
550         break;
551     default:
552         return -EIO;
553     }
554     
555 /*
556     This if-statement destroys pipes - I do not see why it is necessary
557     if (get_frame_filename(filename, sizeof(filename), 
558                            img->path, img->img_number) < 0)
559         return -EIO;
560 */
561     get_frame_filename(filename, sizeof(filename), 
562                        img->path, img->img_number);
563     if (!img->is_pipe) {
564         pb = &pb1;
565         if (url_fopen(pb, filename, URL_WRONLY) < 0)
566             return -EIO;
567     } else {
568         pb = &s->pb;
569     }
570     switch(img->img_fmt) {
571     case IMGFMT_PGMYUV:
572         ret = pgm_save(&picture, width, height, pb, 1);
573         break;
574     case IMGFMT_PGM:
575         ret = pgm_save(&picture, width, height, pb, 0);
576         break;
577     case IMGFMT_YUV:
578         ret = yuv_save(&picture, width, height, filename);
579         break;
580     case IMGFMT_PPM:
581         ret = ppm_save(&picture, width, height, pb);
582         break;
583     }
584     if (!img->is_pipe) {
585         url_fclose(pb);
586     }
587
588     img->img_number++;
589     return 0;
590 }
591
592 static int img_write_trailer(AVFormatContext *s)
593 {
594     return 0;
595 }
596
597 AVInputFormat pgm_iformat = {
598     "pgm",
599     "pgm image format",
600     sizeof(VideoData),
601     NULL,
602     img_read_header,
603     img_read_packet,
604     img_read_close,
605     NULL,
606     AVFMT_NOFILE | AVFMT_NEEDNUMBER,
607     extensions: "pgm",
608 };
609
610 AVOutputFormat pgm_oformat = {
611     "pgm",
612     "pgm image format",
613     "",
614     "pgm",
615     sizeof(VideoData),
616     CODEC_ID_NONE,
617     CODEC_ID_RAWVIDEO,
618     img_write_header,
619     img_write_packet,
620     img_write_trailer,
621     AVFMT_NOFILE | AVFMT_NEEDNUMBER,
622 };
623
624 AVInputFormat pgmyuv_iformat = {
625     "pgmyuv",
626     "pgm with YUV content image format",
627     sizeof(VideoData),
628     NULL, /* no probe */
629     img_read_header,
630     img_read_packet,
631     img_read_close,
632     NULL,
633     AVFMT_NOFILE | AVFMT_NEEDNUMBER,
634 };
635
636 AVOutputFormat pgmyuv_oformat = {
637     "pgmyuv",
638     "pgm with YUV content image format",
639     "",
640     "pgm",
641     sizeof(VideoData),
642     CODEC_ID_NONE,
643     CODEC_ID_RAWVIDEO,
644     img_write_header,
645     img_write_packet,
646     img_write_trailer,
647     AVFMT_NOFILE | AVFMT_NEEDNUMBER,
648 };
649
650 AVInputFormat ppm_iformat = {
651     "ppm",
652     "ppm image format",
653     sizeof(VideoData),
654     NULL,
655     img_read_header,
656     img_read_packet,
657     img_read_close,
658     NULL,
659     AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RGB24,
660     extensions: "ppm",
661 };
662
663 AVOutputFormat ppm_oformat = {
664     "ppm",
665     "ppm image format",
666     "",
667     "ppm",
668     sizeof(VideoData),
669     CODEC_ID_NONE,
670     CODEC_ID_RAWVIDEO,
671     img_write_header,
672     img_write_packet,
673     img_write_trailer,
674     AVFMT_NOFILE | AVFMT_NEEDNUMBER | AVFMT_RGB24,
675 };
676
677 AVInputFormat imgyuv_iformat = {
678     ".Y.U.V",
679     ".Y.U.V format",
680     sizeof(VideoData),
681     NULL,
682     img_read_header,
683     img_read_packet,
684     img_read_close,
685     NULL,
686     AVFMT_NOFILE | AVFMT_NEEDNUMBER,
687     extensions: "Y",
688 };
689
690 AVOutputFormat imgyuv_oformat = {
691     ".Y.U.V",
692     ".Y.U.V format",
693     "",
694     "Y",
695     sizeof(VideoData),
696     CODEC_ID_NONE,
697     CODEC_ID_RAWVIDEO,
698     img_write_header,
699     img_write_packet,
700     img_write_trailer,
701     AVFMT_NOFILE | AVFMT_NEEDNUMBER,
702 };
703
704 AVInputFormat pgmpipe_iformat = {
705     "pgmpipe",
706     "PGM pipe format",
707     sizeof(VideoData),
708     NULL, /* no probe */
709     img_read_header,
710     img_read_packet,
711     img_read_close,
712     NULL,
713 };
714
715 AVOutputFormat pgmpipe_oformat = {
716     "pgmpipe",
717     "PGM pipe format",
718     "",
719     "pgm",
720     sizeof(VideoData),
721     CODEC_ID_NONE,
722     CODEC_ID_RAWVIDEO,
723     img_write_header,
724     img_write_packet,
725     img_write_trailer,
726 };
727
728 AVInputFormat pgmyuvpipe_iformat = {
729     "pgmyuvpipe",
730     "PGM YUV pipe format",
731     sizeof(VideoData),
732     NULL, /* no probe */
733     img_read_header,
734     img_read_packet,
735     img_read_close,
736     NULL,
737 };
738
739 AVOutputFormat pgmyuvpipe_oformat = {
740     "pgmyuvpipe",
741     "PGM YUV pipe format",
742     "",
743     "pgm",
744     sizeof(VideoData),
745     CODEC_ID_NONE,
746     CODEC_ID_RAWVIDEO,
747     img_write_header,
748     img_write_packet,
749     img_write_trailer,
750 };
751
752 AVInputFormat ppmpipe_iformat = {
753     "ppmpipe",
754     "PPM pipe format",
755     sizeof(VideoData),
756     NULL, /* no probe */
757     img_read_header,
758     img_read_packet,
759     img_read_close,
760     NULL,
761     flags: AVFMT_RGB24,
762 };
763
764 AVOutputFormat ppmpipe_oformat = {
765     "ppmpipe",
766     "PPM pipe format",
767     "",
768     "ppm",
769     sizeof(VideoData),
770     CODEC_ID_NONE,
771     CODEC_ID_RAWVIDEO,
772     img_write_header,
773     img_write_packet,
774     img_write_trailer,
775     flags: AVFMT_RGB24,
776 };
777
778
779 int img_init(void)
780 {
781     av_register_input_format(&pgm_iformat);
782     av_register_output_format(&pgm_oformat);
783
784     av_register_input_format(&pgmyuv_iformat);
785     av_register_output_format(&pgmyuv_oformat);
786
787     av_register_input_format(&ppm_iformat);
788     av_register_output_format(&ppm_oformat);
789
790     av_register_input_format(&imgyuv_iformat);
791     av_register_output_format(&imgyuv_oformat);
792     
793     av_register_input_format(&pgmpipe_iformat);
794     av_register_output_format(&pgmpipe_oformat);
795
796     av_register_input_format(&pgmyuvpipe_iformat);
797     av_register_output_format(&pgmyuvpipe_oformat);
798
799     av_register_input_format(&ppmpipe_iformat);
800     av_register_output_format(&ppmpipe_oformat);
801     return 0;
802 }