Libav 0.7.1
libavformat/img2.c
Go to the documentation of this file.
00001 /*
00002  * Image format
00003  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
00004  * Copyright (c) 2004 Michael Niedermayer
00005  *
00006  * This file is part of Libav.
00007  *
00008  * Libav is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * Libav is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with Libav; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 #include "libavutil/intreadwrite.h"
00024 #include "libavutil/avstring.h"
00025 #include "libavutil/log.h"
00026 #include "libavutil/opt.h"
00027 #include "libavutil/pixdesc.h"
00028 #include "libavutil/parseutils.h"
00029 #include "avformat.h"
00030 #include "avio_internal.h"
00031 #include "internal.h"
00032 #include <strings.h>
00033 
00034 typedef struct {
00035     const AVClass *class;  
00036     int img_first;
00037     int img_last;
00038     int img_number;
00039     int img_count;
00040     int is_pipe;
00041     char path[1024];
00042     char *pixel_format;     
00043     char *video_size;       
00044     char *framerate;        
00045 } VideoData;
00046 
00047 typedef struct {
00048     enum CodecID id;
00049     const char *str;
00050 } IdStrMap;
00051 
00052 static const IdStrMap img_tags[] = {
00053     { CODEC_ID_MJPEG     , "jpeg"},
00054     { CODEC_ID_MJPEG     , "jpg"},
00055     { CODEC_ID_LJPEG     , "ljpg"},
00056     { CODEC_ID_PNG       , "png"},
00057     { CODEC_ID_PNG       , "mng"},
00058     { CODEC_ID_PPM       , "ppm"},
00059     { CODEC_ID_PPM       , "pnm"},
00060     { CODEC_ID_PGM       , "pgm"},
00061     { CODEC_ID_PGMYUV    , "pgmyuv"},
00062     { CODEC_ID_PBM       , "pbm"},
00063     { CODEC_ID_PAM       , "pam"},
00064     { CODEC_ID_MPEG1VIDEO, "mpg1-img"},
00065     { CODEC_ID_MPEG2VIDEO, "mpg2-img"},
00066     { CODEC_ID_MPEG4     , "mpg4-img"},
00067     { CODEC_ID_FFV1      , "ffv1-img"},
00068     { CODEC_ID_RAWVIDEO  , "y"},
00069     { CODEC_ID_BMP       , "bmp"},
00070     { CODEC_ID_GIF       , "gif"},
00071     { CODEC_ID_TARGA     , "tga"},
00072     { CODEC_ID_TIFF      , "tiff"},
00073     { CODEC_ID_TIFF      , "tif"},
00074     { CODEC_ID_SGI       , "sgi"},
00075     { CODEC_ID_PTX       , "ptx"},
00076     { CODEC_ID_PCX       , "pcx"},
00077     { CODEC_ID_SUNRAST   , "sun"},
00078     { CODEC_ID_SUNRAST   , "ras"},
00079     { CODEC_ID_SUNRAST   , "rs"},
00080     { CODEC_ID_SUNRAST   , "im1"},
00081     { CODEC_ID_SUNRAST   , "im8"},
00082     { CODEC_ID_SUNRAST   , "im24"},
00083     { CODEC_ID_SUNRAST   , "sunras"},
00084     { CODEC_ID_JPEG2000  , "jp2"},
00085     { CODEC_ID_JPEG2000  , "jpc"},
00086     { CODEC_ID_DPX       , "dpx"},
00087     { CODEC_ID_PICTOR    , "pic"},
00088     { CODEC_ID_NONE      , NULL}
00089 };
00090 
00091 static const int sizes[][2] = {
00092     { 640, 480 },
00093     { 720, 480 },
00094     { 720, 576 },
00095     { 352, 288 },
00096     { 352, 240 },
00097     { 160, 128 },
00098     { 512, 384 },
00099     { 640, 352 },
00100     { 640, 240 },
00101 };
00102 
00103 static int infer_size(int *width_ptr, int *height_ptr, int size)
00104 {
00105     int i;
00106 
00107     for(i=0;i<FF_ARRAY_ELEMS(sizes);i++) {
00108         if ((sizes[i][0] * sizes[i][1]) == size) {
00109             *width_ptr = sizes[i][0];
00110             *height_ptr = sizes[i][1];
00111             return 0;
00112         }
00113     }
00114     return -1;
00115 }
00116 static enum CodecID av_str2id(const IdStrMap *tags, const char *str)
00117 {
00118     str= strrchr(str, '.');
00119     if(!str) return CODEC_ID_NONE;
00120     str++;
00121 
00122     while (tags->id) {
00123         if (!strcasecmp(str, tags->str))
00124             return tags->id;
00125 
00126         tags++;
00127     }
00128     return CODEC_ID_NONE;
00129 }
00130 
00131 /* return -1 if no image found */
00132 static int find_image_range(int *pfirst_index, int *plast_index,
00133                             const char *path)
00134 {
00135     char buf[1024];
00136     int range, last_index, range1, first_index;
00137 
00138     /* find the first image */
00139     for(first_index = 0; first_index < 5; first_index++) {
00140         if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0){
00141             *pfirst_index =
00142             *plast_index = 1;
00143             if (avio_check(buf, AVIO_FLAG_READ) > 0)
00144                 return 0;
00145             return -1;
00146         }
00147         if (avio_check(buf, AVIO_FLAG_READ) > 0)
00148             break;
00149     }
00150     if (first_index == 5)
00151         goto fail;
00152 
00153     /* find the last image */
00154     last_index = first_index;
00155     for(;;) {
00156         range = 0;
00157         for(;;) {
00158             if (!range)
00159                 range1 = 1;
00160             else
00161                 range1 = 2 * range;
00162             if (av_get_frame_filename(buf, sizeof(buf), path,
00163                                       last_index + range1) < 0)
00164                 goto fail;
00165             if (avio_check(buf, AVIO_FLAG_READ) <= 0)
00166                 break;
00167             range = range1;
00168             /* just in case... */
00169             if (range >= (1 << 30))
00170                 goto fail;
00171         }
00172         /* we are sure than image last_index + range exists */
00173         if (!range)
00174             break;
00175         last_index += range;
00176     }
00177     *pfirst_index = first_index;
00178     *plast_index = last_index;
00179     return 0;
00180  fail:
00181     return -1;
00182 }
00183 
00184 
00185 static int read_probe(AVProbeData *p)
00186 {
00187     if (p->filename && av_str2id(img_tags, p->filename)) {
00188         if (av_filename_number_test(p->filename))
00189             return AVPROBE_SCORE_MAX;
00190         else
00191             return AVPROBE_SCORE_MAX/2;
00192     }
00193     return 0;
00194 }
00195 
00196 enum CodecID ff_guess_image2_codec(const char *filename)
00197 {
00198     return av_str2id(img_tags, filename);
00199 }
00200 
00201 #if FF_API_GUESS_IMG2_CODEC
00202 enum CodecID av_guess_image2_codec(const char *filename){
00203     return av_str2id(img_tags, filename);
00204 }
00205 #endif
00206 
00207 static int read_header(AVFormatContext *s1, AVFormatParameters *ap)
00208 {
00209     VideoData *s = s1->priv_data;
00210     int first_index, last_index, ret = 0;
00211     int width = 0, height = 0;
00212     AVStream *st;
00213     enum PixelFormat pix_fmt = PIX_FMT_NONE;
00214     AVRational framerate;
00215 
00216     s1->ctx_flags |= AVFMTCTX_NOHEADER;
00217 
00218     st = av_new_stream(s1, 0);
00219     if (!st) {
00220         return AVERROR(ENOMEM);
00221     }
00222 
00223     if (s->pixel_format && (pix_fmt = av_get_pix_fmt(s->pixel_format)) == PIX_FMT_NONE) {
00224         av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n", s->pixel_format);
00225         return AVERROR(EINVAL);
00226     }
00227     if (s->video_size && (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
00228         av_log(s, AV_LOG_ERROR, "Could not parse video size: %s.\n", s->video_size);
00229         return ret;
00230     }
00231     if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
00232         av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s->framerate);
00233         return ret;
00234     }
00235 #if FF_API_FORMAT_PARAMETERS
00236     if (ap->pix_fmt != PIX_FMT_NONE)
00237         pix_fmt = ap->pix_fmt;
00238     if (ap->width > 0)
00239         width = ap->width;
00240     if (ap->height > 0)
00241         height = ap->height;
00242     if (ap->time_base.num)
00243         framerate = (AVRational){ap->time_base.den, ap->time_base.num};
00244 #endif
00245 
00246     av_strlcpy(s->path, s1->filename, sizeof(s->path));
00247     s->img_number = 0;
00248     s->img_count = 0;
00249 
00250     /* find format */
00251     if (s1->iformat->flags & AVFMT_NOFILE)
00252         s->is_pipe = 0;
00253     else{
00254         s->is_pipe = 1;
00255         st->need_parsing = AVSTREAM_PARSE_FULL;
00256     }
00257 
00258     av_set_pts_info(st, 60, framerate.den, framerate.num);
00259 
00260     if (width && height) {
00261         st->codec->width  = width;
00262         st->codec->height = height;
00263     }
00264 
00265     if (!s->is_pipe) {
00266         if (find_image_range(&first_index, &last_index, s->path) < 0)
00267             return AVERROR(ENOENT);
00268         s->img_first = first_index;
00269         s->img_last = last_index;
00270         s->img_number = first_index;
00271         /* compute duration */
00272         st->start_time = 0;
00273         st->duration = last_index - first_index + 1;
00274     }
00275 
00276     if(s1->video_codec_id){
00277         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00278         st->codec->codec_id = s1->video_codec_id;
00279     }else if(s1->audio_codec_id){
00280         st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00281         st->codec->codec_id = s1->audio_codec_id;
00282     }else{
00283         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00284         st->codec->codec_id = av_str2id(img_tags, s->path);
00285     }
00286     if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pix_fmt != PIX_FMT_NONE)
00287         st->codec->pix_fmt = pix_fmt;
00288 
00289     return 0;
00290 }
00291 
00292 static int read_packet(AVFormatContext *s1, AVPacket *pkt)
00293 {
00294     VideoData *s = s1->priv_data;
00295     char filename[1024];
00296     int i;
00297     int size[3]={0}, ret[3]={0};
00298     AVIOContext *f[3];
00299     AVCodecContext *codec= s1->streams[0]->codec;
00300 
00301     if (!s->is_pipe) {
00302         /* loop over input */
00303         if (s1->loop_input && s->img_number > s->img_last) {
00304             s->img_number = s->img_first;
00305         }
00306         if (s->img_number > s->img_last)
00307             return AVERROR_EOF;
00308         if (av_get_frame_filename(filename, sizeof(filename),
00309                                   s->path, s->img_number)<0 && s->img_number > 1)
00310             return AVERROR(EIO);
00311         for(i=0; i<3; i++){
00312             if (avio_open(&f[i], filename, AVIO_FLAG_READ) < 0) {
00313                 if(i==1)
00314                     break;
00315                 av_log(s1, AV_LOG_ERROR, "Could not open file : %s\n",filename);
00316                 return AVERROR(EIO);
00317             }
00318             size[i]= avio_size(f[i]);
00319 
00320             if(codec->codec_id != CODEC_ID_RAWVIDEO)
00321                 break;
00322             filename[ strlen(filename) - 1 ]= 'U' + i;
00323         }
00324 
00325         if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width)
00326             infer_size(&codec->width, &codec->height, size[0]);
00327     } else {
00328         f[0] = s1->pb;
00329         if (f[0]->eof_reached)
00330             return AVERROR(EIO);
00331         size[0]= 4096;
00332     }
00333 
00334     av_new_packet(pkt, size[0] + size[1] + size[2]);
00335     pkt->stream_index = 0;
00336     pkt->flags |= AV_PKT_FLAG_KEY;
00337 
00338     pkt->size= 0;
00339     for(i=0; i<3; i++){
00340         if(size[i]){
00341             ret[i]= avio_read(f[i], pkt->data + pkt->size, size[i]);
00342             if (!s->is_pipe)
00343                 avio_close(f[i]);
00344             if(ret[i]>0)
00345                 pkt->size += ret[i];
00346         }
00347     }
00348 
00349     if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) {
00350         av_free_packet(pkt);
00351         return AVERROR(EIO); /* signal EOF */
00352     } else {
00353         s->img_count++;
00354         s->img_number++;
00355         return 0;
00356     }
00357 }
00358 
00359 #if CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER
00360 /******************************************************/
00361 /* image output */
00362 
00363 static int write_header(AVFormatContext *s)
00364 {
00365     VideoData *img = s->priv_data;
00366 
00367     img->img_number = 1;
00368     av_strlcpy(img->path, s->filename, sizeof(img->path));
00369 
00370     /* find format */
00371     if (s->oformat->flags & AVFMT_NOFILE)
00372         img->is_pipe = 0;
00373     else
00374         img->is_pipe = 1;
00375 
00376     return 0;
00377 }
00378 
00379 static int write_packet(AVFormatContext *s, AVPacket *pkt)
00380 {
00381     VideoData *img = s->priv_data;
00382     AVIOContext *pb[3];
00383     char filename[1024];
00384     AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec;
00385     int i;
00386 
00387     if (!img->is_pipe) {
00388         if (av_get_frame_filename(filename, sizeof(filename),
00389                                   img->path, img->img_number) < 0 && img->img_number>1) {
00390             av_log(s, AV_LOG_ERROR,
00391                    "Could not get frame filename number %d from pattern '%s'\n",
00392                    img->img_number, img->path);
00393             return AVERROR(EIO);
00394         }
00395         for(i=0; i<3; i++){
00396             if (avio_open(&pb[i], filename, AVIO_FLAG_WRITE) < 0) {
00397                 av_log(s, AV_LOG_ERROR, "Could not open file : %s\n",filename);
00398                 return AVERROR(EIO);
00399             }
00400 
00401             if(codec->codec_id != CODEC_ID_RAWVIDEO)
00402                 break;
00403             filename[ strlen(filename) - 1 ]= 'U' + i;
00404         }
00405     } else {
00406         pb[0] = s->pb;
00407     }
00408 
00409     if(codec->codec_id == CODEC_ID_RAWVIDEO){
00410         int ysize = codec->width * codec->height;
00411         avio_write(pb[0], pkt->data        , ysize);
00412         avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize)/2);
00413         avio_write(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2);
00414         avio_flush(pb[1]);
00415         avio_flush(pb[2]);
00416         avio_close(pb[1]);
00417         avio_close(pb[2]);
00418     }else{
00419         if(av_str2id(img_tags, s->filename) == CODEC_ID_JPEG2000){
00420             AVStream *st = s->streams[0];
00421             if(st->codec->extradata_size > 8 &&
00422                AV_RL32(st->codec->extradata+4) == MKTAG('j','p','2','h')){
00423                 if(pkt->size < 8 || AV_RL32(pkt->data+4) != MKTAG('j','p','2','c'))
00424                     goto error;
00425                 avio_wb32(pb[0], 12);
00426                 ffio_wfourcc(pb[0], "jP  ");
00427                 avio_wb32(pb[0], 0x0D0A870A); // signature
00428                 avio_wb32(pb[0], 20);
00429                 ffio_wfourcc(pb[0], "ftyp");
00430                 ffio_wfourcc(pb[0], "jp2 ");
00431                 avio_wb32(pb[0], 0);
00432                 ffio_wfourcc(pb[0], "jp2 ");
00433                 avio_write(pb[0], st->codec->extradata, st->codec->extradata_size);
00434             }else if(pkt->size < 8 ||
00435                      (!st->codec->extradata_size &&
00436                       AV_RL32(pkt->data+4) != MKTAG('j','P',' ',' '))){ // signature
00437             error:
00438                 av_log(s, AV_LOG_ERROR, "malformated jpeg2000 codestream\n");
00439                 return -1;
00440             }
00441         }
00442         avio_write(pb[0], pkt->data, pkt->size);
00443     }
00444     avio_flush(pb[0]);
00445     if (!img->is_pipe) {
00446         avio_close(pb[0]);
00447     }
00448 
00449     img->img_number++;
00450     return 0;
00451 }
00452 
00453 #endif /* CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER */
00454 
00455 #define OFFSET(x) offsetof(VideoData, x)
00456 #define DEC AV_OPT_FLAG_DECODING_PARAM
00457 static const AVOption options[] = {
00458     { "pixel_format", "", OFFSET(pixel_format), FF_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
00459     { "video_size",   "", OFFSET(video_size),   FF_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
00460     { "framerate",    "", OFFSET(framerate),    FF_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
00461     { NULL },
00462 };
00463 
00464 static const AVClass img2_class = {
00465     .class_name = "image2 demuxer",
00466     .item_name  = av_default_item_name,
00467     .option     = options,
00468     .version    = LIBAVUTIL_VERSION_INT,
00469 };
00470 
00471 /* input */
00472 #if CONFIG_IMAGE2_DEMUXER
00473 AVInputFormat ff_image2_demuxer = {
00474     .name           = "image2",
00475     .long_name      = NULL_IF_CONFIG_SMALL("image2 sequence"),
00476     .priv_data_size = sizeof(VideoData),
00477     .read_probe     = read_probe,
00478     .read_header    = read_header,
00479     .read_packet    = read_packet,
00480     .flags          = AVFMT_NOFILE,
00481     .priv_class     = &img2_class,
00482 };
00483 #endif
00484 #if CONFIG_IMAGE2PIPE_DEMUXER
00485 AVInputFormat ff_image2pipe_demuxer = {
00486     .name           = "image2pipe",
00487     .long_name      = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
00488     .priv_data_size = sizeof(VideoData),
00489     .read_header    = read_header,
00490     .read_packet    = read_packet,
00491     .priv_class     = &img2_class,
00492 };
00493 #endif
00494 
00495 /* output */
00496 #if CONFIG_IMAGE2_MUXER
00497 AVOutputFormat ff_image2_muxer = {
00498     .name           = "image2",
00499     .long_name      = NULL_IF_CONFIG_SMALL("image2 sequence"),
00500     .extensions     = "bmp,dpx,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png,"
00501                       "ppm,sgi,tga,tif,tiff,jp2",
00502     .priv_data_size = sizeof(VideoData),
00503     .video_codec    = CODEC_ID_MJPEG,
00504     .write_header   = write_header,
00505     .write_packet   = write_packet,
00506     .flags          = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS | AVFMT_NOFILE
00507 };
00508 #endif
00509 #if CONFIG_IMAGE2PIPE_MUXER
00510 AVOutputFormat ff_image2pipe_muxer = {
00511     .name           = "image2pipe",
00512     .long_name      = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
00513     .priv_data_size = sizeof(VideoData),
00514     .video_codec    = CODEC_ID_MJPEG,
00515     .write_header   = write_header,
00516     .write_packet   = write_packet,
00517     .flags          = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS
00518 };
00519 #endif