split mux/demux related structures - added file probing support - improve media file...
authorFabrice Bellard <fabrice@bellard.org>
Mon, 20 May 2002 16:28:47 +0000 (16:28 +0000)
committerFabrice Bellard <fabrice@bellard.org>
Mon, 20 May 2002 16:28:47 +0000 (16:28 +0000)
Originally committed as revision 545 to svn://svn.ffmpeg.org/ffmpeg/trunk

libav/avformat.h
libav/utils.c

index fd3052d..8ab1dab 100644 (file)
@@ -24,10 +24,18 @@ int av_new_packet(AVPacket *pkt, int size);
 void av_free_packet(AVPacket *pkt);
 
 /*************************************************/
-/* output formats */
+/* input/output formats */
 
 struct AVFormatContext;
-struct AVFormatInputContext;
+
+/* this structure contains the data a format has to probe a file */
+typedef struct AVProbeData {
+    char *filename;
+    unsigned char *buf;
+    int buf_size;
+} AVProbeData;
+
+#define AVPROBE_SCORE_MAX 100
 
 typedef struct AVFormatParameters {
     int frame_rate;
@@ -38,12 +46,21 @@ typedef struct AVFormatParameters {
     enum PixelFormat pix_fmt;
 } AVFormatParameters;
 
-typedef struct AVFormat {
+#define AVFMT_NOFILE        0x0001 /* no file should be opened */
+#define AVFMT_NEEDNUMBER    0x0002 /* needs '%d' in filename */ 
+#define AVFMT_NOHEADER      0x0004 /* signal that no header is present
+                                      (streams are added dynamically) */
+#define AVFMT_SHOW_IDS      0x0008 /* show format stream IDs numbers */
+#define AVFMT_RGB24         0x0010 /* force RGB24 output for ppm (hack
+                                      - need better api) */
+
+typedef struct AVOutputFormat {
     const char *name;
     const char *long_name;
     const char *mime_type;
     const char *extensions; /* comma separated extensions */
-
+    /* size of private data so that it can be allocated in the wrapper */
+    int priv_data_size;
     /* output support */
     enum CodecID audio_codec; /* default audio codec */
     enum CodecID video_codec; /* default video codec */
@@ -52,14 +69,28 @@ typedef struct AVFormat {
                         int stream_index,
                         unsigned char *buf, int size, int force_pts);
     int (*write_trailer)(struct AVFormatContext *);
+    /* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */
+    int flags;
+    /* private fields */
+    struct AVOutputFormat *next;
+} AVOutputFormat;
 
-    /* optional input support */
-    /* read the format header and initialize the AVFormatInputContext
+typedef struct AVInputFormat {
+    const char *name;
+    const char *long_name;
+    /* size of private data so that it can be allocated in the wrapper */
+    int priv_data_size;
+    /* tell if a given file has a chance of being parsing by this format */
+    int (*read_probe)(AVProbeData *);
+    /* read the format header and initialize the AVFormatContext
        structure. Return 0 if OK. 'ap' if non NULL contains
-       additionnal paramters. Only used in raw format right now */
+       additionnal paramters. Only used in raw format right
+       now. 'av_new_stream' should be called to create new streams.  */
     int (*read_header)(struct AVFormatContext *,
                        AVFormatParameters *ap);
-    /* read one packet and put it in 'pkt'. pts and flags are also set */
+    /* read one packet and put it in 'pkt'. pts and flags are also
+       set. 'av_new_stream' can be called only if the flag
+       AVFMT_NOHEADER is used. */
     int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
     /* close the stream. The AVFormatContext and AVStreams are not
        freed by this function */
@@ -67,24 +98,37 @@ typedef struct AVFormat {
     /* seek at or before a given pts (given in microsecond). The pts
        origin is defined by the stream */
     int (*read_seek)(struct AVFormatContext *, INT64 pts);
+    /* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_NOHEADER */
     int flags;
-#define AVFMT_NOFILE        0x0001 /* no file should be opened */
-#define AVFMT_NEEDNUMBER    0x0002 /* needs '%d' in filename */ 
-    struct AVFormat *next;
-} AVFormat;
+    /* if extensions are defined, then no probe is done. You should
+       usually not use extension format guessing because it is not
+       reliable enough */
+    const char *extensions;
+    /* general purpose read only value that the format can use */
+    int value;
+    /* private fields */
+    struct AVInputFormat *next;
+} AVInputFormat;
 
 typedef struct AVStream {
-    int id;       /* internal stream id */
+    int index;    /* stream index in AVFormatContext */
+    int id;       /* format specific stream id */
     AVCodecContext codec; /* codec context */
     int r_frame_rate;     /* real frame rate of the stream */
     void *priv_data;
+    /* internal data used in av_find_stream_info() */
+    int codec_info_state;     
+    int codec_info_nb_repeat_frames;
+    int codec_info_nb_real_frames;
 } AVStream;
 
 #define MAX_STREAMS 20
 
 /* format I/O context */
 typedef struct AVFormatContext {
-    struct AVFormat *format;
+    /* can only be iformat or oformat, not both at the same time */
+    struct AVInputFormat *iformat;
+    struct AVOutputFormat *oformat;
     void *priv_data;
     ByteIOContext pb;
     int nb_streams;
@@ -107,86 +151,76 @@ typedef struct AVPacketList {
     struct AVPacketList *next;
 } AVPacketList;
 
-extern AVFormat *first_format;
+extern AVInputFormat *first_iformat;
+extern AVOutputFormat *first_oformat;
 
-/* rv10enc.c */
-extern AVFormat rm_format;
+/* XXX: use automatic init with either ELF sections or C file parser */
+/* modules */
 
-/* mpegmux.c */
+/* mpeg.c */
 #define AVF_FLAG_VCD   0x00000001   /* VCD compatible MPEG-PS */
-extern AVFormat mpeg_mux_format;
+int mpegps_init(void);
+
+/* mpegts.c */
+extern AVInputFormat mpegts_demux;
+int mpegts_init(void);
 
-/* asfenc.c */
-extern AVFormat asf_format;
+/* rm.c */
+int rm_init(void);
+
+/* crc.c */
+int crc_init(void);
+
+/* img.c */
+int img_init(void);
+
+/* asf.c */
+int asf_init(void);
 
 /* avienc.c */
-extern AVFormat avi_format;
+int avienc_init(void);
 
-/* mov.c */
-extern AVFormat mov_format;
-extern AVFormat mp4_format;
+/* avidec.c */
+int avidec_init(void);
 
-/* jpegenc.c */
-extern AVFormat mpjpeg_format;
-extern AVFormat jpeg_format;
-extern AVFormat single_jpeg_format;
+/* swf.c */
+int swf_init(void);
+
+/* mov.c */
+int mov_init(void);
 
-/* swfenc.c */
-extern AVFormat swf_format;
+/* jpeg.c */
+int jpeg_init(void);
 
 /* gif.c */
-extern AVFormat gif_format;
+int gif_init(void);
+
 /* au.c */
-extern AVFormat au_format;
+int au_init(void);
 
 /* wav.c */
-extern AVFormat wav_format;
-
-/* crc.c */
-extern AVFormat crc_format;
-
-/* img.c */
-extern AVFormat pgm_format;
-extern AVFormat ppm_format;
-extern AVFormat pgmyuv_format;
-extern AVFormat imgyuv_format;
-
-extern AVFormat pgmpipe_format;
-extern AVFormat pgmyuvpipe_format;
-extern AVFormat ppmpipe_format;
+int wav_init(void);
 
 /* raw.c */
-extern AVFormat mp2_format;
-extern AVFormat ac3_format;
-extern AVFormat h263_format;
-extern AVFormat mpeg1video_format;
-extern AVFormat mjpeg_format;
-extern AVFormat pcm_s16le_format;
-extern AVFormat pcm_s16be_format;
-extern AVFormat pcm_u16le_format;
-extern AVFormat pcm_u16be_format;
-extern AVFormat pcm_s8_format;
-extern AVFormat pcm_u8_format;
-extern AVFormat pcm_mulaw_format;
-extern AVFormat pcm_alaw_format;
-extern AVFormat rawvideo_format;
+int raw_init(void);
 
 /* ffm.c */
-extern AVFormat ffm_format;
-
-/* formats.c */
+int ffm_init(void);
 
+/* utils.c */
 #define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
 #define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
 
-void register_avformat(AVFormat *format);
-AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type);
+void av_register_input_format(AVInputFormat *format);
+void av_register_output_format(AVOutputFormat *format);
+AVOutputFormat *guess_format(const char *short_name, 
+                             const char *filename, const char *mime_type);
 
 int strstart(const char *str, const char *val, const char **ptr);
-void nstrcpy(char *buf, int buf_size, const char *str);
-/* This does what strncpy ought to do. */
-void strlcpy(char *dst, const char *src, int dst_size);
+void pstrcpy(char *buf, int buf_size, const char *str);
+
 int match_ext(const char *filename, const char *extensions);
+void av_hex_dump(UINT8 *buf, int size);
 
 void register_all(void);
 
@@ -203,14 +237,29 @@ int fifo_size(FifoBuffer *f, UINT8 *rptr);
 int fifo_read(FifoBuffer *f, UINT8 *buf, int buf_size, UINT8 **rptr_ptr);
 void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr);
 
-AVFormatContext *av_open_input_file(const char *filename, 
-                                    const char *format_name,
-                                    int buf_size,
-                                    AVFormatParameters *ap);
+/* media file input */
+AVInputFormat *av_find_input_format(const char *short_name);
+int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, 
+                       AVInputFormat *fmt,
+                       int buf_size,
+                       AVFormatParameters *ap);
+
+#define AVERROR_UNKNOWN     (-1)  /* unknown error */
+#define AVERROR_IO          (-2)  /* i/o error */
+#define AVERROR_NUMEXPECTED (-3)  /* number syntax expected in filename */
+#define AVERROR_INVALIDDATA (-4)  /* invalid data found */
+#define AVERROR_NOMEM       (-5)  /* not enough memory */
+#define AVERROR_NOFMT       (-6)  /* unknown format */
+
+int av_find_stream_info(AVFormatContext *ic);
 int av_read_packet(AVFormatContext *s, AVPacket *pkt);
 void av_close_input_file(AVFormatContext *s);
+AVStream *av_new_stream(AVFormatContext *s, int id);
 
+/* media file output */
+int av_write_header(AVFormatContext *s);
 int av_write_packet(AVFormatContext *s, AVPacket *pkt, int force_pts);
+int av_write_trailer(AVFormatContext *s);
 
 void dump_format(AVFormatContext *ic,
                  int index, 
@@ -230,10 +279,11 @@ int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info);
 
 int get_frame_filename(char *buf, int buf_size,
                        const char *path, int number);
+int filename_number_test(const char *filename);
 
-/* grab/output specific */
-extern AVFormat video_grab_device_format;
-extern AVFormat audio_device_format;
+/* grab specific */
+int video_grab_init(void);
+int audio_init(void);
 
 extern const char *v4l_device;
 extern const char *audio_device;
index 78258f9..ef5a3c7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Various utilities for ffmpeg system
- * Copyright (c) 2000,2001 Gerard Lantau
+ * Copyright (c) 2000, 2001, 2002 Gerard Lantau
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <sys/timeb.h>
 #endif
 
-AVFormat *first_format;
+AVInputFormat *first_iformat;
+AVOutputFormat *first_oformat;
 
-void register_avformat(AVFormat *format)
+void av_register_input_format(AVInputFormat *format)
 {
-    AVFormat **p;
-    p = &first_format;
+    AVInputFormat **p;
+    p = &first_iformat;
+    while (*p != NULL) p = &(*p)->next;
+    *p = format;
+    format->next = NULL;
+}
+
+void av_register_output_format(AVOutputFormat *format)
+{
+    AVOutputFormat **p;
+    p = &first_oformat;
     while (*p != NULL) p = &(*p)->next;
     *p = format;
     format->next = NULL;
@@ -64,15 +74,16 @@ int match_ext(const char *filename, const char *extensions)
     return 0;
 }
 
-AVFormat *guess_format(const char *short_name, const char *filename, const char *mime_type)
+AVOutputFormat *guess_format(const char *short_name, const char *filename, 
+                             const char *mime_type)
 {
-    AVFormat *fmt, *fmt_found;
+    AVOutputFormat *fmt, *fmt_found;
     int score_max, score;
 
     /* find the proper file type */
     fmt_found = NULL;
     score_max = 0;
-    fmt = first_format;
+    fmt = first_oformat;
     while (fmt != NULL) {
         score = 0;
         if (fmt->name && short_name && !strcmp(fmt->name, short_name))
@@ -92,8 +103,26 @@ AVFormat *guess_format(const char *short_name, const char *filename, const char
     return fmt_found;
 }   
 
-/* return TRUE if val is a prefix of str. If it returns TRUE, ptr is
-   set to the next character in 'str' after the prefix */
+AVInputFormat *av_find_input_format(const char *short_name)
+{
+    AVInputFormat *fmt;
+    for(fmt = first_iformat; fmt != NULL; fmt = fmt->next) {
+        if (!strcmp(fmt->name, short_name))
+            return fmt;
+    }
+    return NULL;
+}
+
+
+/**
+ * Return TRUE if val is a prefix of str. If it returns TRUE, ptr is
+ * set to the next character in 'str' after the prefix.
+ *
+ * @param str input string
+ * @param val prefix to test
+ * @param ptr updated after the prefix in str in there is a match
+ * @return TRUE if there is a match
+ */
 int strstart(const char *str, const char *val, const char **ptr)
 {
     const char *p, *q;
@@ -110,7 +139,17 @@ int strstart(const char *str, const char *val, const char **ptr)
     return 1;
 }
 
-void nstrcpy(char *buf, int buf_size, const char *str)
+/**
+ * Copy the string str to buf. If str length is bigger than buf_size -
+ * 1 then it is clamped to buf_size - 1.
+ * NOTE: this function does what strncpy should have done to be
+ * useful. NEVER use strncpy.
+ * 
+ * @param buf destination buffer
+ * @param buf_size size of destination buffer
+ * @param str source string
+ */
+void pstrcpy(char *buf, int buf_size, const char *str)
 {
     int c;
     char *q = buf;
@@ -124,67 +163,34 @@ void nstrcpy(char *buf, int buf_size, const char *str)
     *q = '\0';
 }
 
-void strlcpy(char *dst, const char *src, int len)
-{
-    int slen = strlen(src) + 1;
-
-    if (slen <= len) {
-        memcpy(dst, src, slen);
-    } else {
-        memcpy(dst, src, len - 1);
-        dst[len - 1] = 0;
-    }
-}
-
 void register_all(void)
 {
     avcodec_init();
     avcodec_register_all();
 
-    register_avformat(&mp2_format);
-    register_avformat(&ac3_format);
-    register_avformat(&mpeg_mux_format);
-    register_avformat(&mpeg1video_format);
-    register_avformat(&mjpeg_format);
-    register_avformat(&h263_format);
-    register_avformat(&rm_format);
-    register_avformat(&asf_format);
-    register_avformat(&avi_format);
-    register_avformat(&mov_format);
-    register_avformat(&mp4_format);
-    register_avformat(&mpjpeg_format);
-    register_avformat(&jpeg_format);
-    register_avformat(&single_jpeg_format);
-    register_avformat(&swf_format);
-    register_avformat(&gif_format);
-    register_avformat(&au_format);
-    register_avformat(&wav_format);
-    register_avformat(&crc_format);
-
-    register_avformat(&pcm_s16le_format);
-    register_avformat(&pcm_s16be_format);
-    register_avformat(&pcm_u16le_format);
-    register_avformat(&pcm_u16be_format);
-    register_avformat(&pcm_s8_format);
-    register_avformat(&pcm_u8_format);
-    register_avformat(&pcm_mulaw_format);
-    register_avformat(&pcm_alaw_format);
-    register_avformat(&rawvideo_format);
+    mpegps_init();
+    mpegts_init();
+    crc_init();
+    img_init();
+    raw_init();
+    rm_init();
+    asf_init();
+    avienc_init();
+    avidec_init();
+    wav_init();
+    swf_init();
+    au_init();
+    gif_init();
+    mov_init();
+    jpeg_init();
+
 #ifndef CONFIG_WIN32
-    register_avformat(&ffm_format);
+    ffm_init();
 #endif
-    register_avformat(&pgm_format);
-    register_avformat(&ppm_format);
-    register_avformat(&pgmyuv_format);
-    register_avformat(&imgyuv_format);
-    register_avformat(&pgmpipe_format);
-    register_avformat(&pgmyuvpipe_format);
-    register_avformat(&ppmpipe_format);
 #ifdef CONFIG_GRAB
-    register_avformat(&video_grab_device_format);
-    register_avformat(&audio_device_format);
+    video_grab_init();    
+    audio_init();
 #endif
-
     /* file protocols */
     register_protocol(&file_protocol);
     register_protocol(&pipe_protocol);
@@ -196,11 +202,18 @@ void register_all(void)
 
 /* memory handling */
 
+/**
+ * Allocate the payload of a packet and intialized its fields to default values.
+ *
+ * @param pkt packet
+ * @param size wanted payload size
+ * @return 0 if OK. AVERROR_xxx otherwise.
+ */
 int av_new_packet(AVPacket *pkt, int size)
 {
     pkt->data = av_malloc(size);
     if (!pkt->data)
-        return -ENOMEM;
+        return AVERROR_NOMEM;
     pkt->size = size;
     /* sane state */
     pkt->pts = 0;
@@ -209,6 +222,11 @@ int av_new_packet(AVPacket *pkt, int size)
     return 0;
 }
 
+/**
+ * Free a packet
+ *
+ * @param pkt packet to free
+ */
 void av_free_packet(AVPacket *pkt)
 {
     av_freep(&pkt->data);
@@ -293,61 +311,146 @@ void fifo_write(FifoBuffer *f, UINT8 *buf, int size, UINT8 **wptr_ptr)
     *wptr_ptr = wptr;
 }
 
-/* media file handling. 
-   'filename' is the filename to open.
-   'format_name' is used to force the file format (NULL if auto guess).
-   'buf_size' is the optional buffer size (zero if default is OK).
-   'ap' are additionnal parameters needed when opening the file (NULL if default).
-*/
+int filename_number_test(const char *filename)
+{
+    char buf[1024];
+    return get_frame_filename(buf, sizeof(buf), filename, 1);
+}
+
+/* guess file format */
+static AVInputFormat *probe_input_format(AVProbeData *pd, int is_opened)
+{
+    AVInputFormat *fmt1, *fmt;
+    int score, score_max;
+
+    fmt = NULL;
+    score_max = 0;
+    for(fmt1 = first_iformat; fmt1 != NULL; fmt1 = fmt1->next) {
+        if (!is_opened && !(fmt1->flags & AVFMT_NOFILE))
+            continue;
+        score = 0;
+        if (fmt1->extensions) {
+            if (match_ext(pd->filename, fmt1->extensions)) {
+                score = 50;
+            }
+        } else if (fmt1->read_probe) {
+            score = fmt1->read_probe(pd);
+        }
+        if (score > score_max) {
+            score_max = score;
+            fmt = fmt1;
+        }
+    }
+    return fmt;
+}
+
+/************************************************************/
+/* input media file */
 
-AVFormatContext *av_open_input_file(const char *filename, 
-                                    const char *format_name,
-                                    int buf_size,
-                                    AVFormatParameters *ap)
+#define PROBE_BUF_SIZE 2048
+
+/**
+ * Open a media file as input. The codec are not opened. Only the file
+ * header (if present) is read.
+ *
+ * @param ic_ptr the opened media file handle is put here
+ * @param filename filename to open.
+ * @param fmt if non NULL, force the file format to use
+ * @param buf_size optional buffer size (zero if default is OK)
+ * @param ap additionnal parameters needed when opening the file (NULL if default)
+ * @return 0 if OK. AVERROR_xxx otherwise.
+ */
+int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, 
+                       AVInputFormat *fmt,
+                       int buf_size,
+                       AVFormatParameters *ap)
 {
-    AVFormat *fmt;
     AVFormatContext *ic = NULL;
     int err;
+    char buf[PROBE_BUF_SIZE];
+    AVProbeData probe_data, *pd = &probe_data;
 
     ic = av_mallocz(sizeof(AVFormatContext));
-    if (!ic)
+    if (!ic) {
+        err = AVERROR_NOMEM;
         goto fail;
-
-    /* find format */
-    if (format_name != NULL) {
-        fmt = guess_format(format_name, NULL, NULL);
-    } else {
-        fmt = guess_format(NULL, filename, NULL);
     }
-    if (!fmt || !fmt->read_header) {
-        return NULL;
+    pstrcpy(ic->filename, sizeof(ic->filename), filename);
+    pd->filename = ic->filename;
+    pd->buf = buf;
+    pd->buf_size = 0;
+
+    if (!fmt) {
+        /* guess format if no file can be opened  */
+        fmt = probe_input_format(pd, 0);
     }
-    ic->format = fmt;
 
     /* if no file needed do not try to open one */
-    if (!(fmt->flags & AVFMT_NOFILE)) {
-        if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0)
+    if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
+        if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0) {
+            err = AVERROR_IO;
             goto fail;
+        }
         if (buf_size > 0) {
             url_setbufsize(&ic->pb, buf_size);
         }
+        /* read probe data */
+        pd->buf_size = get_buffer(&ic->pb, buf, PROBE_BUF_SIZE);
+        url_fseek(&ic->pb, 0, SEEK_SET);
     }
     
-    err = ic->format->read_header(ic, ap);
-    if (err < 0) {
-        if (!(fmt->flags & AVFMT_NOFILE)) {
-            url_fclose(&ic->pb);
-        }
+    /* guess file format */
+    if (!fmt) {
+        fmt = probe_input_format(pd, 1);
+    }
+
+    /* if still no format found, error */
+    if (!fmt) {
+        err = AVERROR_NOFMT;
         goto fail;
     }
-    
-    return ic;
+        
+    ic->iformat = fmt;
 
+    /* allocate private data */
+    ic->priv_data = av_mallocz(fmt->priv_data_size);
+    if (!ic->priv_data) {
+        err = AVERROR_NOMEM;
+        goto fail;
+    }
+
+    /* check filename in case of an image number is expected */
+    if (ic->iformat->flags & AVFMT_NEEDNUMBER) {
+        if (filename_number_test(ic->filename) < 0) { 
+            err = AVERROR_NUMEXPECTED;
+            goto fail1;
+        }
+    }
+    
+    err = ic->iformat->read_header(ic, ap);
+    if (err < 0)
+        goto fail1;
+    *ic_ptr = ic;
+    return 0;
+ fail1:
+    if (!(fmt->flags & AVFMT_NOFILE)) {
+        url_fclose(&ic->pb);
+    }
  fail:
+    if (ic) {
+        av_free(ic->priv_data);
+    }
     av_free(ic);
-    return NULL;
+    *ic_ptr = NULL;
+    return err;
 }
 
+/**
+ * Read a packet from a media file
+ * @param s media file handle
+ * @param pkt is filled 
+ * @return 0 if OK. AVERROR_xxx if error.
+ */
 int av_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     AVPacketList *pktl;
@@ -360,16 +463,240 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt)
         av_free(pktl);
         return 0;
     } else {
-        return s->format->read_packet(s, pkt);
+        return s->iformat->read_packet(s, pkt);
+    }
+}
+
+/* state for codec information */
+#define CSTATE_NOTFOUND    0
+#define CSTATE_DECODING    1
+#define CSTATE_FOUND       2
+
+static int has_codec_parameters(AVCodecContext *enc)
+{
+    int val;
+    switch(enc->codec_type) {
+    case CODEC_TYPE_AUDIO:
+        val = enc->sample_rate;
+        break;
+    case CODEC_TYPE_VIDEO:
+        val = enc->width;
+        break;
+    default:
+        val = 1;
+        break;
+    }
+    return (val != 0);
+}
+
+/**
+ * Read the beginning of a media file to get stream information. This
+ * is useful for file formats with no headers such as MPEG. This
+ * function also compute the real frame rate in case of mpeg2 repeat
+ * frame mode.
+ *
+ * @param ic media file handle
+ * @return >=0 if OK. AVERROR_xxx if error.  
+ */
+int av_find_stream_info(AVFormatContext *ic)
+{
+    int i, count, ret, got_picture, size, read_size;
+    AVCodec *codec;
+    AVStream *st;
+    AVPacket *pkt;
+    AVPicture picture;
+    AVPacketList *pktl=NULL, **ppktl;
+    short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2];
+    UINT8 *ptr;
+    int min_read_size, max_read_size;
+
+    /* typical mpeg ts rate is 40 Mbits. DVD rate is about 10
+       Mbits. We read at most 0.1 second of file to find all streams */
+
+    /* XXX: base it on stream bitrate when possible */
+    if (ic->iformat == &mpegts_demux) {
+        /* maximum number of bytes we accept to read to find all the streams
+           in a file */
+        min_read_size = 3000000;
+    } else {
+        min_read_size = 125000;
+    }
+    /* max read size is 2 seconds of video max */
+    max_read_size = min_read_size * 20;
+
+    /* set initial codec state */
+    for(i=0;i<ic->nb_streams;i++) {
+        st = ic->streams[i];
+        if (has_codec_parameters(&st->codec))
+            st->codec_info_state = CSTATE_FOUND;
+        else
+            st->codec_info_state = CSTATE_NOTFOUND;
+        st->codec_info_nb_repeat_frames = 0;
+        st->codec_info_nb_real_frames = 0;
+    }
+
+    count = 0;
+    read_size = 0;
+    ppktl = &ic->packet_buffer;
+    for(;;) {
+        /* check if one codec still needs to be handled */
+        for(i=0;i<ic->nb_streams;i++) {
+            st = ic->streams[i];
+            if (st->codec_info_state != CSTATE_FOUND)
+                break;
+        }
+        if (i == ic->nb_streams) {
+            /* NOTE: if the format has no header, then we need to read
+               some packets to get most of the streams, so we cannot
+               stop here */
+            if (!(ic->iformat->flags & AVFMT_NOHEADER) ||
+                read_size >= min_read_size) {
+                /* if we found the info for all the codecs, we can stop */
+                ret = count;
+                break;
+            }
+        } else {
+            /* we did not get all the codec info, but we read too much data */
+            if (read_size >= max_read_size) {
+                ret = count;
+                break;
+            }
+        }
+
+        pktl = av_mallocz(sizeof(AVPacketList));
+        if (!pktl) {
+            ret = AVERROR_NOMEM;
+            break;
+        }
+
+        /* add the packet in the buffered packet list */
+        *ppktl = pktl;
+        ppktl = &pktl->next;
+
+        /* NOTE: a new stream can be added there if no header in file
+           (AVFMT_NOHEADER) */
+        pkt = &pktl->pkt;
+        if (ic->iformat->read_packet(ic, pkt) < 0) {
+            /* EOF or error */
+            ret = -1; /* we could not have all the codec parameters before EOF */
+            if ((ic->iformat->flags & AVFMT_NOHEADER) &&
+                i == ic->nb_streams)
+                ret = 0;
+            break;
+        }
+        read_size += pkt->size;
+
+        /* open new codecs */
+        for(i=0;i<ic->nb_streams;i++) {
+            st = ic->streams[i];
+            if (st->codec_info_state == CSTATE_NOTFOUND) {
+                /* set to found in case of error */
+                st->codec_info_state = CSTATE_FOUND; 
+                codec = avcodec_find_decoder(st->codec.codec_id);
+                if (codec) {
+                    ret = avcodec_open(&st->codec, codec);
+                    if (ret >= 0)
+                        st->codec_info_state = CSTATE_DECODING;
+                }
+            }
+        }
+
+        st = ic->streams[pkt->stream_index];
+        if (st->codec_info_state == CSTATE_DECODING) {
+            /* decode the data and update codec parameters */
+            ptr = pkt->data;
+            size = pkt->size;
+            while (size > 0) {
+                switch(st->codec.codec_type) {
+                case CODEC_TYPE_VIDEO:
+                    ret = avcodec_decode_video(&st->codec, &picture, 
+                                               &got_picture, ptr, size);
+                    break;
+                case CODEC_TYPE_AUDIO:
+                    ret = avcodec_decode_audio(&st->codec, samples, 
+                                               &got_picture, ptr, size);
+                    break;
+                default:
+                    ret = -1;
+                    break;
+                }
+                if (ret < 0) {
+                    /* if error, simply ignore because another packet
+                       may be OK */
+                    break;
+                }
+                if (got_picture) {
+                    /* we got the parameters - now we can stop
+                       examining this stream */
+                    /* XXX: add a codec info so that we can decide if
+                       the codec can repeat frames */
+                    if (st->codec.codec_id == CODEC_ID_MPEG1VIDEO && 
+                        ic->iformat != &mpegts_demux &&
+                        st->codec.sub_id == 2) {
+                        /* for mpeg2 video, we want to know the real
+                           frame rate, so we decode 40 frames. In mpeg
+                           TS case we do not do it because it would be
+                           too long */
+                        st->codec_info_nb_real_frames++;
+                        st->codec_info_nb_repeat_frames += st->codec.repeat_pict;
+#if 0
+                        /* XXX: testing */
+                        if ((st->codec_info_nb_real_frames % 24) == 23) {
+                            st->codec_info_nb_repeat_frames += 2;
+                        }
+#endif
+                        /* stop after 40 frames */
+                        if (st->codec_info_nb_real_frames >= 40) {
+                            st->r_frame_rate = (st->codec.frame_rate * 
+                                                st->codec_info_nb_real_frames) /
+                                (st->codec_info_nb_real_frames + 
+                                 (st->codec_info_nb_repeat_frames >> 1));
+                            goto close_codec;
+                        }
+                    } else {
+                    close_codec:
+                        st->codec_info_state = CSTATE_FOUND;
+                        avcodec_close(&st->codec);
+                    }
+                    break;
+                }
+                ptr += ret;
+                size -= ret;
+            }
+        }
+        count++;
+    }
+
+    /* close each codec if there are opened */
+    for(i=0;i<ic->nb_streams;i++) {
+        st = ic->streams[i];
+        if (st->codec_info_state == CSTATE_DECODING)
+            avcodec_close(&st->codec);
+    }
+
+    /* set real frame rate info */
+    for(i=0;i<ic->nb_streams;i++) {
+        st = ic->streams[i];
+        if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
+            if (!st->r_frame_rate)
+                st->r_frame_rate = st->codec.frame_rate;
+        }
     }
+
+    return ret;
 }
 
+/**
+ * Close a media file (but not its codecs)
+ *
+ * @param s media file handle
+ */
 void av_close_input_file(AVFormatContext *s)
 {
     int i;
 
-    if (s->format->read_close)
-        s->format->read_close(s);
+    if (s->iformat->read_close)
+        s->iformat->read_close(s);
     for(i=0;i<s->nb_streams;i++) {
         av_free(s->streams[i]);
     }
@@ -384,17 +711,81 @@ void av_close_input_file(AVFormatContext *s)
         }
         s->packet_buffer = NULL;
     }
-    if (!(s->format->flags & AVFMT_NOFILE)) {
+    if (!(s->iformat->flags & AVFMT_NOFILE)) {
         url_fclose(&s->pb);
     }
+    av_free(s->priv_data);
     av_free(s);
 }
 
+/**
+ * Add a new stream to a media file. Can only be called in the
+ * read_header function. If the flag AVFMT_NOHEADER is in the format
+ * description, then new streams can be added in read_packet too.
+ *
+ *
+ * @param s media file handle
+ * @param id file format dependent stream id
+ */
+AVStream *av_new_stream(AVFormatContext *s, int id)
+{
+    AVStream *st;
+
+    if (s->nb_streams >= MAX_STREAMS)
+        return NULL;
+
+    st = av_mallocz(sizeof(AVStream));
+    if (!st)
+        return NULL;
+    st->index = s->nb_streams;
+    st->id = id;
+    s->streams[s->nb_streams++] = st;
+    return st;
+}
+
+/************************************************************/
+/* output media file */
 
+/**
+ * allocate the stream private data and write the stream header to an
+ * output media file
+ *
+ * @param s media file handle
+ * @return 0 if OK. AVERROR_xxx if error.  
+ */
+int av_write_header(AVFormatContext *s)
+{
+    s->priv_data = av_mallocz(s->oformat->priv_data_size);
+    if (!s->priv_data)
+        return AVERROR_NOMEM;
+    return s->oformat->write_header(s);
+}
+
+/**
+ * write a packet to an output media file
+ *
+ * @param s media file handle
+ * @param pkt packet to write
+ * @param force_pts XXX: need to suppress that
+ */
 int av_write_packet(AVFormatContext *s, AVPacket *pkt, int force_pts)
 {
     /* XXX: currently, an emulation because internal API must change */
-    return s->format->write_packet(s, pkt->stream_index, pkt->data, pkt->size, force_pts);
+    return s->oformat->write_packet(s, pkt->stream_index, pkt->data, pkt->size, force_pts);
+}
+
+/**
+ * write the stream trailer to an output media file and and free the
+ * file private data.
+ *
+ * @param s media file handle
+ * @return 0 if OK. AVERROR_xxx if error.  */
+int av_write_trailer(AVFormatContext *s)
+{
+    int ret;
+    ret = s->oformat->write_trailer(s);
+    av_freep(&s->priv_data);
+    return ret;
 }
 
 /* "user interface" functions */
@@ -404,17 +795,28 @@ void dump_format(AVFormatContext *ic,
                  const char *url,
                  int is_output)
 {
-    int i;
+    int i, flags;
     char buf[256];
 
     fprintf(stderr, "%s #%d, %s, %s '%s':\n", 
             is_output ? "Output" : "Input",
-            index, ic->format->name, 
+            index, 
+            is_output ? ic->oformat->name : ic->iformat->name, 
             is_output ? "to" : "from", url);
     for(i=0;i<ic->nb_streams;i++) {
         AVStream *st = ic->streams[i];
         avcodec_string(buf, sizeof(buf), &st->codec, is_output);
-        fprintf(stderr, "  Stream #%d.%d: %s\n", index, i, buf);
+        fprintf(stderr, "  Stream #%d.%d", index, i);
+        /* the pid is an important information, so we display it */
+        /* XXX: add a generic system */
+        if (is_output)
+            flags = ic->oformat->flags;
+        else
+            flags = ic->iformat->flags;
+        if (flags & AVFMT_SHOW_IDS) {
+            fprintf(stderr, "[0x%x]", st->id);
+        }
+        fprintf(stderr, ": %s\n", buf);
     }
 }
 
@@ -661,3 +1063,36 @@ void ticker_init(Ticker *tick, INT64 inrate, INT64 outrate)
     tick->div = tick->outrate / tick->inrate;
     tick->mod = tick->outrate % tick->inrate;
 }
+
+/**
+ *
+ * Print on stdout a nice hexa dump of a buffer
+ * @param buf buffer
+ * @param size buffer size
+ */
+void av_hex_dump(UINT8 *buf, int size)
+{
+    int len, i, j, c;
+
+    for(i=0;i<size;i+=16) {
+        len = size - i;
+        if (len > 16)
+            len = 16;
+        printf("%08x ", i);
+        for(j=0;j<16;j++) {
+            if (j < len)
+                printf(" %02x", buf[i+j]);
+            else
+                printf("   ");
+        }
+        printf(" ");
+        for(j=0;j<len;j++) {
+            c = buf[i+j];
+            if (c < ' ' || c > '~')
+                c = '.';
+            printf("%c", c);
+        }
+        printf("\n");
+    }
+}
+