Mercurial > libavformat.hg
annotate img2.c @ 1942:70b741fa63eb libavformat
The NSV demuxer assumes that a video frame's timestamp increases by one on each
frame, but some low-bitrate NSV files omit video frames for some NSV frames,
and expect the timestamp to increase by one every NSV frame. This is noticeable
in 64vp3.nsv where the video runs several times faster than the audio. Fix this
by unconditionally incrementing the video's timestamp with each NSV frame.
patch by David Conrad, umovimus gmail com
author | diego |
---|---|
date | Wed, 21 Mar 2007 11:05:35 +0000 |
parents | eb16c64144ee |
children | b5e15030d788 |
rev | line source |
---|---|
497 | 1 /* |
2 * Image format | |
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. | |
4 * Copyright (c) 2004 Michael Niedermayer | |
5 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1291
diff
changeset
|
6 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1291
diff
changeset
|
7 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1291
diff
changeset
|
8 * FFmpeg is free software; you can redistribute it and/or |
497 | 9 * modify it under the terms of the GNU Lesser General Public |
10 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1291
diff
changeset
|
11 * version 2.1 of the License, or (at your option) any later version. |
497 | 12 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1291
diff
changeset
|
13 * FFmpeg is distributed in the hope that it will be useful, |
497 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1291
diff
changeset
|
19 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
885
diff
changeset
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
497 | 21 */ |
22 #include "avformat.h" | |
23 | |
24 typedef struct { | |
25 int img_first; | |
26 int img_last; | |
27 int img_number; | |
28 int img_count; | |
29 int is_pipe; | |
30 char path[1024]; | |
31 } VideoData; | |
32 | |
33 typedef struct { | |
34 enum CodecID id; | |
35 const char *str; | |
36 } IdStrMap; | |
37 | |
38 static const IdStrMap img_tags[] = { | |
39 { CODEC_ID_MJPEG , "jpeg"}, | |
40 { CODEC_ID_MJPEG , "jpg"}, | |
41 { CODEC_ID_LJPEG , "ljpg"}, | |
581 | 42 { CODEC_ID_PNG , "png"}, |
583 | 43 { CODEC_ID_PPM , "ppm"}, |
44 { CODEC_ID_PGM , "pgm"}, | |
45 { CODEC_ID_PGMYUV , "pgmyuv"}, | |
46 { CODEC_ID_PBM , "pbm"}, | |
47 { CODEC_ID_PAM , "pam"}, | |
497 | 48 { CODEC_ID_MPEG1VIDEO, "mpg1-img"}, |
49 { CODEC_ID_MPEG2VIDEO, "mpg2-img"}, | |
50 { CODEC_ID_MPEG4 , "mpg4-img"}, | |
51 { CODEC_ID_FFV1 , "ffv1-img"}, | |
635 | 52 { CODEC_ID_RAWVIDEO , "y"}, |
875 | 53 { CODEC_ID_BMP , "bmp"}, |
1409 | 54 { CODEC_ID_GIF , "gif"}, |
1416 | 55 { CODEC_ID_TARGA , "tga"}, |
56 { CODEC_ID_TIFF , "tiff"}, | |
497 | 57 {0, NULL} |
58 }; | |
59 | |
635 | 60 static int sizes[][2] = { |
61 { 640, 480 }, | |
62 { 720, 480 }, | |
63 { 720, 576 }, | |
64 { 352, 288 }, | |
65 { 352, 240 }, | |
66 { 160, 128 }, | |
67 { 512, 384 }, | |
68 { 640, 352 }, | |
69 { 640, 240 }, | |
70 }; | |
71 | |
72 static int infer_size(int *width_ptr, int *height_ptr, int size) | |
73 { | |
74 int i; | |
75 | |
76 for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) { | |
77 if ((sizes[i][0] * sizes[i][1]) == size) { | |
78 *width_ptr = sizes[i][0]; | |
79 *height_ptr = sizes[i][1]; | |
80 return 0; | |
81 } | |
82 } | |
83 return -1; | |
84 } | |
497 | 85 static enum CodecID av_str2id(const IdStrMap *tags, const char *str) |
86 { | |
530 | 87 str= strrchr(str, '.'); |
88 if(!str) return CODEC_ID_NONE; | |
89 str++; | |
497 | 90 |
91 while (tags->id) { | |
92 int i; | |
93 for(i=0; toupper(tags->str[i]) == toupper(str[i]); i++){ | |
94 if(tags->str[i]==0 && str[i]==0) | |
95 return tags->id; | |
96 } | |
97 | |
98 tags++; | |
99 } | |
100 return CODEC_ID_NONE; | |
101 } | |
102 | |
103 /* return -1 if no image found */ | |
885 | 104 static int find_image_range(int *pfirst_index, int *plast_index, |
497 | 105 const char *path) |
106 { | |
107 char buf[1024]; | |
108 int range, last_index, range1, first_index; | |
109 | |
110 /* find the first image */ | |
111 for(first_index = 0; first_index < 5; first_index++) { | |
1291
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
112 if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){ |
885 | 113 *pfirst_index = |
498 | 114 *plast_index = 1; |
115 return 0; | |
116 } | |
497 | 117 if (url_exist(buf)) |
118 break; | |
119 } | |
120 if (first_index == 5) | |
121 goto fail; | |
885 | 122 |
497 | 123 /* find the last image */ |
124 last_index = first_index; | |
125 for(;;) { | |
126 range = 0; | |
127 for(;;) { | |
128 if (!range) | |
129 range1 = 1; | |
130 else | |
131 range1 = 2 * range; | |
1291
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
132 if (av_get_frame_filename(buf, sizeof(buf), path, |
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
133 last_index + range1) < 0) |
497 | 134 goto fail; |
135 if (!url_exist(buf)) | |
136 break; | |
137 range = range1; | |
138 /* just in case... */ | |
139 if (range >= (1 << 30)) | |
140 goto fail; | |
141 } | |
142 /* we are sure than image last_index + range exists */ | |
143 if (!range) | |
144 break; | |
145 last_index += range; | |
146 } | |
147 *pfirst_index = first_index; | |
148 *plast_index = last_index; | |
149 return 0; | |
150 fail: | |
151 return -1; | |
152 } | |
153 | |
154 | |
155 static int image_probe(AVProbeData *p) | |
156 { | |
1594
ffb64cb62cc9
Fix a crash when probing img2 format with a NULL filename.
aurel
parents:
1551
diff
changeset
|
157 if (p->filename && av_str2id(img_tags, p->filename)) { |
1551
ee4ef413497e
probe with some success image files not containing number pattern but having recognized image extension
bcoudurier
parents:
1416
diff
changeset
|
158 if (av_filename_number_test(p->filename)) |
ee4ef413497e
probe with some success image files not containing number pattern but having recognized image extension
bcoudurier
parents:
1416
diff
changeset
|
159 return AVPROBE_SCORE_MAX; |
ee4ef413497e
probe with some success image files not containing number pattern but having recognized image extension
bcoudurier
parents:
1416
diff
changeset
|
160 else |
ee4ef413497e
probe with some success image files not containing number pattern but having recognized image extension
bcoudurier
parents:
1416
diff
changeset
|
161 return AVPROBE_SCORE_MAX/2; |
ee4ef413497e
probe with some success image files not containing number pattern but having recognized image extension
bcoudurier
parents:
1416
diff
changeset
|
162 } |
ee4ef413497e
probe with some success image files not containing number pattern but having recognized image extension
bcoudurier
parents:
1416
diff
changeset
|
163 return 0; |
497 | 164 } |
165 | |
583 | 166 enum CodecID av_guess_image2_codec(const char *filename){ |
167 return av_str2id(img_tags, filename); | |
168 } | |
169 | |
497 | 170 static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) |
171 { | |
172 VideoData *s = s1->priv_data; | |
173 int first_index, last_index; | |
174 AVStream *st; | |
175 | |
176 s1->ctx_flags |= AVFMTCTX_NOHEADER; | |
177 | |
178 st = av_new_stream(s1, 0); | |
179 if (!st) { | |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1594
diff
changeset
|
180 return AVERROR(ENOMEM); |
497 | 181 } |
182 | |
639 | 183 pstrcpy(s->path, sizeof(s->path), s1->filename); |
497 | 184 s->img_number = 0; |
185 s->img_count = 0; | |
885 | 186 |
497 | 187 /* find format */ |
188 if (s1->iformat->flags & AVFMT_NOFILE) | |
189 s->is_pipe = 0; | |
574 | 190 else{ |
497 | 191 s->is_pipe = 1; |
574 | 192 st->need_parsing= 1; |
193 } | |
885 | 194 |
1003 | 195 if (!ap->time_base.num) { |
743 | 196 av_set_pts_info(st, 60, 1, 25); |
497 | 197 } else { |
743 | 198 av_set_pts_info(st, 60, ap->time_base.num, ap->time_base.den); |
497 | 199 } |
885 | 200 |
1003 | 201 if(ap->width && ap->height){ |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
202 st->codec->width = ap->width; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
203 st->codec->height= ap->height; |
635 | 204 } |
885 | 205 |
497 | 206 if (!s->is_pipe) { |
207 if (find_image_range(&first_index, &last_index, s->path) < 0) | |
622 | 208 return AVERROR_IO; |
497 | 209 s->img_first = first_index; |
210 s->img_last = last_index; | |
211 s->img_number = first_index; | |
212 /* compute duration */ | |
213 st->start_time = 0; | |
743 | 214 st->duration = last_index - first_index + 1; |
497 | 215 } |
885 | 216 |
583 | 217 if(ap->video_codec_id){ |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
218 st->codec->codec_type = CODEC_TYPE_VIDEO; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
219 st->codec->codec_id = ap->video_codec_id; |
583 | 220 }else if(ap->audio_codec_id){ |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
221 st->codec->codec_type = CODEC_TYPE_AUDIO; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
222 st->codec->codec_id = ap->audio_codec_id; |
583 | 223 }else{ |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
224 st->codec->codec_type = CODEC_TYPE_VIDEO; |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
225 st->codec->codec_id = av_str2id(img_tags, s->path); |
583 | 226 } |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
227 if(st->codec->codec_type == CODEC_TYPE_VIDEO && ap->pix_fmt != PIX_FMT_NONE) |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
228 st->codec->pix_fmt = ap->pix_fmt; |
497 | 229 |
230 return 0; | |
231 } | |
232 | |
233 static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) | |
234 { | |
235 VideoData *s = s1->priv_data; | |
236 char filename[1024]; | |
635 | 237 int i; |
238 int size[3]={0}, ret[3]={0}; | |
239 ByteIOContext f1[3], *f[3]= {&f1[0], &f1[1], &f1[2]}; | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
240 AVCodecContext *codec= s1->streams[0]->codec; |
497 | 241 |
242 if (!s->is_pipe) { | |
243 /* loop over input */ | |
1175
8b53c0f3e7ad
add loop_input to AVFormatContext, getting rid of old hack
mru
parents:
1169
diff
changeset
|
244 if (s1->loop_input && s->img_number > s->img_last) { |
497 | 245 s->img_number = s->img_first; |
590 | 246 } |
1291
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
247 if (av_get_frame_filename(filename, sizeof(filename), |
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
248 s->path, s->img_number)<0 && s->img_number > 1) |
497 | 249 return AVERROR_IO; |
635 | 250 for(i=0; i<3; i++){ |
251 if (url_fopen(f[i], filename, URL_RDONLY) < 0) | |
252 return AVERROR_IO; | |
764
cdb845a57ae4
drop most url_fileno() calls (allows to use ByteIOContext directly in caller apps instead of URLProtocol)
aurel
parents:
743
diff
changeset
|
253 size[i]= url_fsize(f[i]); |
885 | 254 |
635 | 255 if(codec->codec_id != CODEC_ID_RAWVIDEO) |
256 break; | |
257 filename[ strlen(filename) - 1 ]= 'U' + i; | |
258 } | |
885 | 259 |
635 | 260 if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width) |
261 infer_size(&codec->width, &codec->height, size[0]); | |
497 | 262 } else { |
635 | 263 f[0] = &s1->pb; |
264 if (url_feof(f[0])) | |
497 | 265 return AVERROR_IO; |
635 | 266 size[0]= 4096; |
497 | 267 } |
268 | |
635 | 269 av_new_packet(pkt, size[0] + size[1] + size[2]); |
497 | 270 pkt->stream_index = 0; |
271 pkt->flags |= PKT_FLAG_KEY; | |
272 | |
635 | 273 pkt->size= 0; |
274 for(i=0; i<3; i++){ | |
275 if(size[i]){ | |
276 ret[i]= get_buffer(f[i], pkt->data + pkt->size, size[i]); | |
277 if (!s->is_pipe) | |
278 url_fclose(f[i]); | |
279 if(ret[i]>0) | |
280 pkt->size += ret[i]; | |
281 } | |
497 | 282 } |
283 | |
635 | 284 if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) { |
497 | 285 av_free_packet(pkt); |
286 return AVERROR_IO; /* signal EOF */ | |
287 } else { | |
288 s->img_count++; | |
289 s->img_number++; | |
290 return 0; | |
291 } | |
292 } | |
293 | |
294 static int img_read_close(AVFormatContext *s1) | |
295 { | |
296 return 0; | |
297 } | |
298 | |
903
68bc3ca12e79
Put muxer-specific code parts in #ifdef CONFIG_MUXERS.
diego
parents:
896
diff
changeset
|
299 #ifdef CONFIG_MUXERS |
497 | 300 /******************************************************/ |
301 /* image output */ | |
302 | |
303 static int img_write_header(AVFormatContext *s) | |
304 { | |
305 VideoData *img = s->priv_data; | |
306 | |
307 img->img_number = 1; | |
639 | 308 pstrcpy(img->path, sizeof(img->path), s->filename); |
497 | 309 |
310 /* find format */ | |
311 if (s->oformat->flags & AVFMT_NOFILE) | |
312 img->is_pipe = 0; | |
313 else | |
314 img->is_pipe = 1; | |
885 | 315 |
497 | 316 return 0; |
317 } | |
318 | |
319 static int img_write_packet(AVFormatContext *s, AVPacket *pkt) | |
320 { | |
321 VideoData *img = s->priv_data; | |
635 | 322 ByteIOContext pb1[3], *pb[3]= {&pb1[0], &pb1[1], &pb1[2]}; |
497 | 323 char filename[1024]; |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
764
diff
changeset
|
324 AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec; |
635 | 325 int i; |
497 | 326 |
327 if (!img->is_pipe) { | |
1291
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
328 if (av_get_frame_filename(filename, sizeof(filename), |
185190bdc185
Clarified API for numbered sequences, patch by Michel Bardiaux % mbardiaux A mediaxim P be %
gpoirier
parents:
1175
diff
changeset
|
329 img->path, img->img_number) < 0 && img->img_number>1) |
497 | 330 return AVERROR_IO; |
635 | 331 for(i=0; i<3; i++){ |
332 if (url_fopen(pb[i], filename, URL_WRONLY) < 0) | |
333 return AVERROR_IO; | |
885 | 334 |
635 | 335 if(codec->codec_id != CODEC_ID_RAWVIDEO) |
336 break; | |
337 filename[ strlen(filename) - 1 ]= 'U' + i; | |
338 } | |
497 | 339 } else { |
635 | 340 pb[0] = &s->pb; |
497 | 341 } |
885 | 342 |
635 | 343 if(codec->codec_id == CODEC_ID_RAWVIDEO){ |
731 | 344 int ysize = codec->width * codec->height; |
345 put_buffer(pb[0], pkt->data , ysize); | |
346 put_buffer(pb[1], pkt->data + ysize, (pkt->size - ysize)/2); | |
347 put_buffer(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2); | |
635 | 348 put_flush_packet(pb[1]); |
349 put_flush_packet(pb[2]); | |
350 url_fclose(pb[1]); | |
351 url_fclose(pb[2]); | |
352 }else{ | |
353 put_buffer(pb[0], pkt->data, pkt->size); | |
354 } | |
355 put_flush_packet(pb[0]); | |
497 | 356 if (!img->is_pipe) { |
635 | 357 url_fclose(pb[0]); |
497 | 358 } |
359 | |
360 img->img_number++; | |
361 return 0; | |
362 } | |
363 | |
364 static int img_write_trailer(AVFormatContext *s) | |
365 { | |
366 return 0; | |
367 } | |
368 | |
903
68bc3ca12e79
Put muxer-specific code parts in #ifdef CONFIG_MUXERS.
diego
parents:
896
diff
changeset
|
369 #endif /* CONFIG_MUXERS */ |
68bc3ca12e79
Put muxer-specific code parts in #ifdef CONFIG_MUXERS.
diego
parents:
896
diff
changeset
|
370 |
497 | 371 /* input */ |
1169 | 372 #ifdef CONFIG_IMAGE2_DEMUXER |
373 AVInputFormat image2_demuxer = { | |
497 | 374 "image2", |
375 "image2 sequence", | |
376 sizeof(VideoData), | |
377 image_probe, | |
378 img_read_header, | |
379 img_read_packet, | |
380 img_read_close, | |
381 NULL, | |
382 NULL, | |
498 | 383 AVFMT_NOFILE, |
497 | 384 }; |
1169 | 385 #endif |
386 #ifdef CONFIG_IMAGE2PIPE_DEMUXER | |
387 AVInputFormat image2pipe_demuxer = { | |
497 | 388 "image2pipe", |
389 "piped image2 sequence", | |
390 sizeof(VideoData), | |
391 NULL, /* no probe */ | |
392 img_read_header, | |
393 img_read_packet, | |
394 img_read_close, | |
395 NULL, | |
396 }; | |
1169 | 397 #endif |
497 | 398 |
399 /* output */ | |
1169 | 400 #ifdef CONFIG_IMAGE2_MUXER |
401 AVOutputFormat image2_muxer = { | |
497 | 402 "image2", |
403 "image2 sequence", | |
404 "", | |
405 "", | |
406 sizeof(VideoData), | |
407 CODEC_ID_NONE, | |
408 CODEC_ID_MJPEG, | |
409 img_write_header, | |
410 img_write_packet, | |
411 img_write_trailer, | |
498 | 412 AVFMT_NOFILE, |
497 | 413 }; |
1169 | 414 #endif |
415 #ifdef CONFIG_IMAGE2PIPE_MUXER | |
416 AVOutputFormat image2pipe_muxer = { | |
497 | 417 "image2pipe", |
418 "piped image2 sequence", | |
419 "", | |
420 "", | |
421 sizeof(VideoData), | |
422 CODEC_ID_NONE, | |
423 CODEC_ID_MJPEG, | |
424 img_write_header, | |
425 img_write_packet, | |
426 img_write_trailer, | |
427 }; | |
903
68bc3ca12e79
Put muxer-specific code parts in #ifdef CONFIG_MUXERS.
diego
parents:
896
diff
changeset
|
428 #endif |