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 23#include "libavutil/intreadwrite.h" 24#include "libavutil/avstring.h" 25#include "avformat.h" 26#include <strings.h> 27 28typedef struct { 29 int img_first; 30 int img_last; 31 int img_number; 32 int img_count; 33 int is_pipe; 34 char path[1024]; 35} VideoData; 36 37typedef struct { 38 enum CodecID id; 39 const char *str; 40} IdStrMap; 41 42static const IdStrMap img_tags[] = { 43 { CODEC_ID_MJPEG , "jpeg"}, 44 { CODEC_ID_MJPEG , "jpg"}, 45 { CODEC_ID_LJPEG , "ljpg"}, 46 { CODEC_ID_PNG , "png"}, 47 { CODEC_ID_PNG , "mng"}, 48 { CODEC_ID_PPM , "ppm"}, 49 { CODEC_ID_PPM , "pnm"}, 50 { CODEC_ID_PGM , "pgm"}, 51 { CODEC_ID_PGMYUV , "pgmyuv"}, 52 { CODEC_ID_PBM , "pbm"}, 53 { CODEC_ID_PAM , "pam"}, 54 { CODEC_ID_MPEG1VIDEO, "mpg1-img"}, 55 { CODEC_ID_MPEG2VIDEO, "mpg2-img"}, 56 { CODEC_ID_MPEG4 , "mpg4-img"}, 57 { CODEC_ID_FFV1 , "ffv1-img"}, 58 { CODEC_ID_RAWVIDEO , "y"}, 59 { CODEC_ID_BMP , "bmp"}, 60 { CODEC_ID_GIF , "gif"}, 61 { CODEC_ID_TARGA , "tga"}, 62 { CODEC_ID_TIFF , "tiff"}, 63 { CODEC_ID_TIFF , "tif"}, 64 { CODEC_ID_SGI , "sgi"}, 65 { CODEC_ID_PTX , "ptx"}, 66 { CODEC_ID_PCX , "pcx"}, 67 { CODEC_ID_SUNRAST , "sun"}, 68 { CODEC_ID_SUNRAST , "ras"}, 69 { CODEC_ID_SUNRAST , "rs"}, 70 { CODEC_ID_SUNRAST , "im1"}, 71 { CODEC_ID_SUNRAST , "im8"}, 72 { CODEC_ID_SUNRAST , "im24"}, 73 { CODEC_ID_SUNRAST , "sunras"}, 74 { CODEC_ID_JPEG2000 , "jp2"}, 75 { CODEC_ID_NONE , NULL} 76}; 77 78static const int sizes[][2] = { 79 { 640, 480 }, 80 { 720, 480 }, 81 { 720, 576 }, 82 { 352, 288 }, 83 { 352, 240 }, 84 { 160, 128 }, 85 { 512, 384 }, 86 { 640, 352 }, 87 { 640, 240 }, 88}; 89 90static int infer_size(int *width_ptr, int *height_ptr, int size) 91{ 92 int i; 93 94 for(i=0;i<FF_ARRAY_ELEMS(sizes);i++) { 95 if ((sizes[i][0] * sizes[i][1]) == size) { 96 *width_ptr = sizes[i][0]; 97 *height_ptr = sizes[i][1]; 98 return 0; 99 } 100 } 101 return -1; 102} 103static enum CodecID av_str2id(const IdStrMap *tags, const char *str) 104{ 105 str= strrchr(str, '.'); 106 if(!str) return CODEC_ID_NONE; 107 str++; 108 109 while (tags->id) { 110 if (!strcasecmp(str, tags->str)) 111 return tags->id; 112 113 tags++; 114 } 115 return CODEC_ID_NONE; 116} 117 118/* return -1 if no image found */ 119static int find_image_range(int *pfirst_index, int *plast_index, 120 const char *path) 121{ 122 char buf[1024]; 123 int range, last_index, range1, first_index; 124 125 /* find the first image */ 126 for(first_index = 0; first_index < 5; first_index++) { 127 if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){ 128 *pfirst_index = 129 *plast_index = 1; 130 return 0; 131 } 132 if (url_exist(buf)) 133 break; 134 } 135 if (first_index == 5) 136 goto fail; 137 138 /* find the last image */ 139 last_index = first_index; 140 for(;;) { 141 range = 0; 142 for(;;) { 143 if (!range) 144 range1 = 1; 145 else 146 range1 = 2 * range; 147 if (av_get_frame_filename(buf, sizeof(buf), path, 148 last_index + range1) < 0) 149 goto fail; 150 if (!url_exist(buf)) 151 break; 152 range = range1; 153 /* just in case... */ 154 if (range >= (1 << 30)) 155 goto fail; 156 } 157 /* we are sure than image last_index + range exists */ 158 if (!range) 159 break; 160 last_index += range; 161 } 162 *pfirst_index = first_index; 163 *plast_index = last_index; 164 return 0; 165 fail: 166 return -1; 167} 168 169 170static int image_probe(AVProbeData *p) 171{ 172 if (p->filename && av_str2id(img_tags, p->filename)) { 173 if (av_filename_number_test(p->filename)) 174 return AVPROBE_SCORE_MAX; 175 else 176 return AVPROBE_SCORE_MAX/2; 177 } 178 return 0; 179} 180 181enum CodecID av_guess_image2_codec(const char *filename){ 182 return av_str2id(img_tags, filename); 183} 184 185static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) 186{ 187 VideoData *s = s1->priv_data; 188 int first_index, last_index; 189 AVStream *st; 190 191 s1->ctx_flags |= AVFMTCTX_NOHEADER; 192 193 st = av_new_stream(s1, 0); 194 if (!st) { 195 return AVERROR(ENOMEM); 196 } 197 198 av_strlcpy(s->path, s1->filename, sizeof(s->path)); 199 s->img_number = 0; 200 s->img_count = 0; 201 202 /* find format */ 203 if (s1->iformat->flags & AVFMT_NOFILE) 204 s->is_pipe = 0; 205 else{ 206 s->is_pipe = 1; 207 st->need_parsing = AVSTREAM_PARSE_FULL; 208 } 209 210 if (!ap->time_base.num) { 211 av_set_pts_info(st, 60, 1, 25); 212 } else { 213 av_set_pts_info(st, 60, ap->time_base.num, ap->time_base.den); 214 } 215 216 if(ap->width && ap->height){ 217 st->codec->width = ap->width; 218 st->codec->height= ap->height; 219 } 220 221 if (!s->is_pipe) { 222 if (find_image_range(&first_index, &last_index, s->path) < 0) 223 return AVERROR(EIO); 224 s->img_first = first_index; 225 s->img_last = last_index; 226 s->img_number = first_index; 227 /* compute duration */ 228 st->start_time = 0; 229 st->duration = last_index - first_index + 1; 230 } 231 232 if(ap->video_codec_id){ 233 st->codec->codec_type = CODEC_TYPE_VIDEO; 234 st->codec->codec_id = ap->video_codec_id; 235 }else if(ap->audio_codec_id){ 236 st->codec->codec_type = CODEC_TYPE_AUDIO; 237 st->codec->codec_id = ap->audio_codec_id; 238 }else{ 239 st->codec->codec_type = CODEC_TYPE_VIDEO; 240 st->codec->codec_id = av_str2id(img_tags, s->path); 241 } 242 if(st->codec->codec_type == CODEC_TYPE_VIDEO && ap->pix_fmt != PIX_FMT_NONE) 243 st->codec->pix_fmt = ap->pix_fmt; 244 245 return 0; 246} 247 248static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) 249{ 250 VideoData *s = s1->priv_data; 251 char filename[1024]; 252 int i; 253 int size[3]={0}, ret[3]={0}; 254 ByteIOContext *f[3]; 255 AVCodecContext *codec= s1->streams[0]->codec; 256 257 if (!s->is_pipe) { 258 /* loop over input */ 259 if (s1->loop_input && s->img_number > s->img_last) { 260 s->img_number = s->img_first; 261 } 262 if (av_get_frame_filename(filename, sizeof(filename), 263 s->path, s->img_number)<0 && s->img_number > 1) 264 return AVERROR(EIO); 265 for(i=0; i<3; i++){ 266 if (url_fopen(&f[i], filename, URL_RDONLY) < 0) 267 return AVERROR(EIO); 268 size[i]= url_fsize(f[i]); 269 270 if(codec->codec_id != CODEC_ID_RAWVIDEO) 271 break; 272 filename[ strlen(filename) - 1 ]= 'U' + i; 273 } 274 275 if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width) 276 infer_size(&codec->width, &codec->height, size[0]); 277 } else { 278 f[0] = s1->pb; 279 if (url_feof(f[0])) 280 return AVERROR(EIO); 281 size[0]= 4096; 282 } 283 284 av_new_packet(pkt, size[0] + size[1] + size[2]); 285 pkt->stream_index = 0; 286 pkt->flags |= PKT_FLAG_KEY; 287 288 pkt->size= 0; 289 for(i=0; i<3; i++){ 290 if(size[i]){ 291 ret[i]= get_buffer(f[i], pkt->data + pkt->size, size[i]); 292 if (!s->is_pipe) 293 url_fclose(f[i]); 294 if(ret[i]>0) 295 pkt->size += ret[i]; 296 } 297 } 298 299 if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) { 300 av_free_packet(pkt); 301 return AVERROR(EIO); /* signal EOF */ 302 } else { 303 s->img_count++; 304 s->img_number++; 305 return 0; 306 } 307} 308 309#if CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER 310/******************************************************/ 311/* image output */ 312 313static int img_write_header(AVFormatContext *s) 314{ 315 VideoData *img = s->priv_data; 316 317 img->img_number = 1; 318 av_strlcpy(img->path, s->filename, sizeof(img->path)); 319 320 /* find format */ 321 if (s->oformat->flags & AVFMT_NOFILE) 322 img->is_pipe = 0; 323 else 324 img->is_pipe = 1; 325 326 return 0; 327} 328 329static int img_write_packet(AVFormatContext *s, AVPacket *pkt) 330{ 331 VideoData *img = s->priv_data; 332 ByteIOContext *pb[3]; 333 char filename[1024]; 334 AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec; 335 int i; 336 337 if (!img->is_pipe) { 338 if (av_get_frame_filename(filename, sizeof(filename), 339 img->path, img->img_number) < 0 && img->img_number>1) 340 return AVERROR(EIO); 341 for(i=0; i<3; i++){ 342 if (url_fopen(&pb[i], filename, URL_WRONLY) < 0) 343 return AVERROR(EIO); 344 345 if(codec->codec_id != CODEC_ID_RAWVIDEO) 346 break; 347 filename[ strlen(filename) - 1 ]= 'U' + i; 348 } 349 } else { 350 pb[0] = s->pb; 351 } 352 353 if(codec->codec_id == CODEC_ID_RAWVIDEO){ 354 int ysize = codec->width * codec->height; 355 put_buffer(pb[0], pkt->data , ysize); 356 put_buffer(pb[1], pkt->data + ysize, (pkt->size - ysize)/2); 357 put_buffer(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2); 358 put_flush_packet(pb[1]); 359 put_flush_packet(pb[2]); 360 url_fclose(pb[1]); 361 url_fclose(pb[2]); 362 }else{ 363 if(av_str2id(img_tags, s->filename) == CODEC_ID_JPEG2000){ 364 AVStream *st = s->streams[0]; 365 if(st->codec->extradata_size > 8 && 366 AV_RL32(st->codec->extradata+4) == MKTAG('j','p','2','h')){ 367 if(pkt->size < 8 || AV_RL32(pkt->data+4) != MKTAG('j','p','2','c')) 368 goto error; 369 put_be32(pb[0], 12); 370 put_tag (pb[0], "jP "); 371 put_be32(pb[0], 0x0D0A870A); // signature 372 put_be32(pb[0], 20); 373 put_tag (pb[0], "ftyp"); 374 put_tag (pb[0], "jp2 "); 375 put_be32(pb[0], 0); 376 put_tag (pb[0], "jp2 "); 377 put_buffer(pb[0], st->codec->extradata, st->codec->extradata_size); 378 }else if(pkt->size < 8 || 379 (!st->codec->extradata_size && 380 AV_RL32(pkt->data+4) != MKTAG('j','P',' ',' '))){ // signature 381 error: 382 av_log(s, AV_LOG_ERROR, "malformated jpeg2000 codestream\n"); 383 return -1; 384 } 385 } 386 put_buffer(pb[0], pkt->data, pkt->size); 387 } 388 put_flush_packet(pb[0]); 389 if (!img->is_pipe) { 390 url_fclose(pb[0]); 391 } 392 393 img->img_number++; 394 return 0; 395} 396 397#endif /* CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER */ 398 399/* input */ 400#if CONFIG_IMAGE2_DEMUXER 401AVInputFormat image2_demuxer = { 402 "image2", 403 NULL_IF_CONFIG_SMALL("image2 sequence"), 404 sizeof(VideoData), 405 image_probe, 406 img_read_header, 407 img_read_packet, 408 NULL, 409 NULL, 410 NULL, 411 AVFMT_NOFILE, 412}; 413#endif 414#if CONFIG_IMAGE2PIPE_DEMUXER 415AVInputFormat image2pipe_demuxer = { 416 "image2pipe", 417 NULL_IF_CONFIG_SMALL("piped image2 sequence"), 418 sizeof(VideoData), 419 NULL, /* no probe */ 420 img_read_header, 421 img_read_packet, 422}; 423#endif 424 425/* output */ 426#if CONFIG_IMAGE2_MUXER 427AVOutputFormat image2_muxer = { 428 "image2", 429 NULL_IF_CONFIG_SMALL("image2 sequence"), 430 "", 431 "bmp,jpeg,jpg,ljpg,pam,pbm,pgm,pgmyuv,png,ppm,sgi,tif,tiff,jp2", 432 sizeof(VideoData), 433 CODEC_ID_NONE, 434 CODEC_ID_MJPEG, 435 img_write_header, 436 img_write_packet, 437 NULL, 438 .flags= AVFMT_NOTIMESTAMPS | AVFMT_NOFILE 439}; 440#endif 441#if CONFIG_IMAGE2PIPE_MUXER 442AVOutputFormat image2pipe_muxer = { 443 "image2pipe", 444 NULL_IF_CONFIG_SMALL("piped image2 sequence"), 445 "", 446 "", 447 sizeof(VideoData), 448 CODEC_ID_NONE, 449 CODEC_ID_MJPEG, 450 img_write_header, 451 img_write_packet, 452 .flags= AVFMT_NOTIMESTAMPS 453}; 454#endif 455