]> git.sesse.net Git - ffmpeg/blob - libavformat/img2.c
PC Paintbrush PCX image decoder
[ffmpeg] / libavformat / img2.c
1 /*
2  * Image format
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
4  * Copyright (c) 2004 Michael Niedermayer
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 #include "avformat.h"
23 #include "avstring.h"
24
25 typedef struct {
26     int img_first;
27     int img_last;
28     int img_number;
29     int img_count;
30     int is_pipe;
31     char path[1024];
32 } VideoData;
33
34 typedef struct {
35     enum CodecID id;
36     const char *str;
37 } IdStrMap;
38
39 static const IdStrMap img_tags[] = {
40     { CODEC_ID_MJPEG     , "jpeg"},
41     { CODEC_ID_MJPEG     , "jpg"},
42     { CODEC_ID_LJPEG     , "ljpg"},
43     { CODEC_ID_PNG       , "png"},
44     { CODEC_ID_PPM       , "ppm"},
45     { CODEC_ID_PGM       , "pgm"},
46     { CODEC_ID_PGMYUV    , "pgmyuv"},
47     { CODEC_ID_PBM       , "pbm"},
48     { CODEC_ID_PAM       , "pam"},
49     { CODEC_ID_MPEG1VIDEO, "mpg1-img"},
50     { CODEC_ID_MPEG2VIDEO, "mpg2-img"},
51     { CODEC_ID_MPEG4     , "mpg4-img"},
52     { CODEC_ID_FFV1      , "ffv1-img"},
53     { CODEC_ID_RAWVIDEO  , "y"},
54     { CODEC_ID_BMP       , "bmp"},
55     { CODEC_ID_GIF       , "gif"},
56     { CODEC_ID_TARGA     , "tga"},
57     { CODEC_ID_TIFF      , "tiff"},
58     { CODEC_ID_SGI       , "sgi"},
59     { CODEC_ID_PTX       , "ptx"},
60     { CODEC_ID_PCX       , "pcx"},
61     {0, NULL}
62 };
63
64 static int sizes[][2] = {
65     { 640, 480 },
66     { 720, 480 },
67     { 720, 576 },
68     { 352, 288 },
69     { 352, 240 },
70     { 160, 128 },
71     { 512, 384 },
72     { 640, 352 },
73     { 640, 240 },
74 };
75
76 static int infer_size(int *width_ptr, int *height_ptr, int size)
77 {
78     int i;
79
80     for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
81         if ((sizes[i][0] * sizes[i][1]) == size) {
82             *width_ptr = sizes[i][0];
83             *height_ptr = sizes[i][1];
84             return 0;
85         }
86     }
87     return -1;
88 }
89 static enum CodecID av_str2id(const IdStrMap *tags, const char *str)
90 {
91     str= strrchr(str, '.');
92     if(!str) return CODEC_ID_NONE;
93     str++;
94
95     while (tags->id) {
96         int i;
97         for(i=0; toupper(tags->str[i]) == toupper(str[i]); i++){
98             if(tags->str[i]==0 && str[i]==0)
99                 return tags->id;
100         }
101
102         tags++;
103     }
104     return CODEC_ID_NONE;
105 }
106
107 /* return -1 if no image found */
108 static int find_image_range(int *pfirst_index, int *plast_index,
109                             const char *path)
110 {
111     char buf[1024];
112     int range, last_index, range1, first_index;
113
114     /* find the first image */
115     for(first_index = 0; first_index < 5; first_index++) {
116         if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){
117             *pfirst_index =
118             *plast_index = 1;
119             return 0;
120         }
121         if (url_exist(buf))
122             break;
123     }
124     if (first_index == 5)
125         goto fail;
126
127     /* find the last image */
128     last_index = first_index;
129     for(;;) {
130         range = 0;
131         for(;;) {
132             if (!range)
133                 range1 = 1;
134             else
135                 range1 = 2 * range;
136             if (av_get_frame_filename(buf, sizeof(buf), path,
137                                       last_index + range1) < 0)
138                 goto fail;
139             if (!url_exist(buf))
140                 break;
141             range = range1;
142             /* just in case... */
143             if (range >= (1 << 30))
144                 goto fail;
145         }
146         /* we are sure than image last_index + range exists */
147         if (!range)
148             break;
149         last_index += range;
150     }
151     *pfirst_index = first_index;
152     *plast_index = last_index;
153     return 0;
154  fail:
155     return -1;
156 }
157
158
159 static int image_probe(AVProbeData *p)
160 {
161     if (p->filename && av_str2id(img_tags, p->filename)) {
162         if (av_filename_number_test(p->filename))
163             return AVPROBE_SCORE_MAX;
164         else
165             return AVPROBE_SCORE_MAX/2;
166     }
167     return 0;
168 }
169
170 enum CodecID av_guess_image2_codec(const char *filename){
171     return av_str2id(img_tags, filename);
172 }
173
174 static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap)
175 {
176     VideoData *s = s1->priv_data;
177     int first_index, last_index;
178     AVStream *st;
179
180     s1->ctx_flags |= AVFMTCTX_NOHEADER;
181
182     st = av_new_stream(s1, 0);
183     if (!st) {
184         return AVERROR(ENOMEM);
185     }
186
187     av_strlcpy(s->path, s1->filename, sizeof(s->path));
188     s->img_number = 0;
189     s->img_count = 0;
190
191     /* find format */
192     if (s1->iformat->flags & AVFMT_NOFILE)
193         s->is_pipe = 0;
194     else{
195         s->is_pipe = 1;
196         st->need_parsing = AVSTREAM_PARSE_FULL;
197     }
198
199     if (!ap->time_base.num) {
200         av_set_pts_info(st, 60, 1, 25);
201     } else {
202         av_set_pts_info(st, 60, ap->time_base.num, ap->time_base.den);
203     }
204
205     if(ap->width && ap->height){
206         st->codec->width = ap->width;
207         st->codec->height= ap->height;
208     }
209
210     if (!s->is_pipe) {
211         if (find_image_range(&first_index, &last_index, s->path) < 0)
212             return AVERROR(EIO);
213         s->img_first = first_index;
214         s->img_last = last_index;
215         s->img_number = first_index;
216         /* compute duration */
217         st->start_time = 0;
218         st->duration = last_index - first_index + 1;
219     }
220
221     if(ap->video_codec_id){
222         st->codec->codec_type = CODEC_TYPE_VIDEO;
223         st->codec->codec_id = ap->video_codec_id;
224     }else if(ap->audio_codec_id){
225         st->codec->codec_type = CODEC_TYPE_AUDIO;
226         st->codec->codec_id = ap->audio_codec_id;
227     }else{
228         st->codec->codec_type = CODEC_TYPE_VIDEO;
229         st->codec->codec_id = av_str2id(img_tags, s->path);
230     }
231     if(st->codec->codec_type == CODEC_TYPE_VIDEO && ap->pix_fmt != PIX_FMT_NONE)
232         st->codec->pix_fmt = ap->pix_fmt;
233
234     return 0;
235 }
236
237 static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
238 {
239     VideoData *s = s1->priv_data;
240     char filename[1024];
241     int i;
242     int size[3]={0}, ret[3]={0};
243     ByteIOContext *f[3];
244     AVCodecContext *codec= s1->streams[0]->codec;
245
246     if (!s->is_pipe) {
247         /* loop over input */
248         if (s1->loop_input && s->img_number > s->img_last) {
249             s->img_number = s->img_first;
250         }
251         if (av_get_frame_filename(filename, sizeof(filename),
252                                   s->path, s->img_number)<0 && s->img_number > 1)
253             return AVERROR(EIO);
254         for(i=0; i<3; i++){
255             if (url_fopen(&f[i], filename, URL_RDONLY) < 0)
256                 return AVERROR(EIO);
257             size[i]= url_fsize(f[i]);
258
259             if(codec->codec_id != CODEC_ID_RAWVIDEO)
260                 break;
261             filename[ strlen(filename) - 1 ]= 'U' + i;
262         }
263
264         if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width)
265             infer_size(&codec->width, &codec->height, size[0]);
266     } else {
267         f[0] = s1->pb;
268         if (url_feof(f[0]))
269             return AVERROR(EIO);
270         size[0]= 4096;
271     }
272
273     av_new_packet(pkt, size[0] + size[1] + size[2]);
274     pkt->stream_index = 0;
275     pkt->flags |= PKT_FLAG_KEY;
276
277     pkt->size= 0;
278     for(i=0; i<3; i++){
279         if(size[i]){
280             ret[i]= get_buffer(f[i], pkt->data + pkt->size, size[i]);
281             if (!s->is_pipe)
282                 url_fclose(f[i]);
283             if(ret[i]>0)
284                 pkt->size += ret[i];
285         }
286     }
287
288     if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) {
289         av_free_packet(pkt);
290         return AVERROR(EIO); /* signal EOF */
291     } else {
292         s->img_count++;
293         s->img_number++;
294         return 0;
295     }
296 }
297
298 static int img_read_close(AVFormatContext *s1)
299 {
300     return 0;
301 }
302
303 #ifdef CONFIG_MUXERS
304 /******************************************************/
305 /* image output */
306
307 static int img_write_header(AVFormatContext *s)
308 {
309     VideoData *img = s->priv_data;
310
311     img->img_number = 1;
312     av_strlcpy(img->path, s->filename, sizeof(img->path));
313
314     /* find format */
315     if (s->oformat->flags & AVFMT_NOFILE)
316         img->is_pipe = 0;
317     else
318         img->is_pipe = 1;
319
320     return 0;
321 }
322
323 static int img_write_packet(AVFormatContext *s, AVPacket *pkt)
324 {
325     VideoData *img = s->priv_data;
326     ByteIOContext *pb[3];
327     char filename[1024];
328     AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec;
329     int i;
330
331     if (!img->is_pipe) {
332         if (av_get_frame_filename(filename, sizeof(filename),
333                                   img->path, img->img_number) < 0 && img->img_number>1)
334             return AVERROR(EIO);
335         for(i=0; i<3; i++){
336             if (url_fopen(&pb[i], filename, URL_WRONLY) < 0)
337                 return AVERROR(EIO);
338
339             if(codec->codec_id != CODEC_ID_RAWVIDEO)
340                 break;
341             filename[ strlen(filename) - 1 ]= 'U' + i;
342         }
343     } else {
344         pb[0] = s->pb;
345     }
346
347     if(codec->codec_id == CODEC_ID_RAWVIDEO){
348         int ysize = codec->width * codec->height;
349         put_buffer(pb[0], pkt->data        , ysize);
350         put_buffer(pb[1], pkt->data + ysize, (pkt->size - ysize)/2);
351         put_buffer(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2);
352         put_flush_packet(pb[1]);
353         put_flush_packet(pb[2]);
354         url_fclose(pb[1]);
355         url_fclose(pb[2]);
356     }else{
357         put_buffer(pb[0], pkt->data, pkt->size);
358     }
359     put_flush_packet(pb[0]);
360     if (!img->is_pipe) {
361         url_fclose(pb[0]);
362     }
363
364     img->img_number++;
365     return 0;
366 }
367
368 static int img_write_trailer(AVFormatContext *s)
369 {
370     return 0;
371 }
372
373 #endif /* CONFIG_MUXERS */
374
375 /* input */
376 #ifdef CONFIG_IMAGE2_DEMUXER
377 AVInputFormat image2_demuxer = {
378     "image2",
379     "image2 sequence",
380     sizeof(VideoData),
381     image_probe,
382     img_read_header,
383     img_read_packet,
384     img_read_close,
385     NULL,
386     NULL,
387     AVFMT_NOFILE,
388 };
389 #endif
390 #ifdef CONFIG_IMAGE2PIPE_DEMUXER
391 AVInputFormat image2pipe_demuxer = {
392     "image2pipe",
393     "piped image2 sequence",
394     sizeof(VideoData),
395     NULL, /* no probe */
396     img_read_header,
397     img_read_packet,
398     img_read_close,
399     NULL,
400 };
401 #endif
402
403 /* output */
404 #ifdef CONFIG_IMAGE2_MUXER
405 AVOutputFormat image2_muxer = {
406     "image2",
407     "image2 sequence",
408     "",
409     "",
410     sizeof(VideoData),
411     CODEC_ID_NONE,
412     CODEC_ID_MJPEG,
413     img_write_header,
414     img_write_packet,
415     img_write_trailer,
416     AVFMT_NOFILE,
417 };
418 #endif
419 #ifdef CONFIG_IMAGE2PIPE_MUXER
420 AVOutputFormat image2pipe_muxer = {
421     "image2pipe",
422     "piped image2 sequence",
423     "",
424     "",
425     sizeof(VideoData),
426     CODEC_ID_NONE,
427     CODEC_ID_MJPEG,
428     img_write_header,
429     img_write_packet,
430     img_write_trailer,
431 };
432 #endif