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