From da24c5e330ab90b5249f4fb94044b78919f64d4f Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Wed, 29 Oct 2003 14:20:56 +0000 Subject: [PATCH] make AVFMT_NOHEADER flag dynamic - added av_open_input_stream() Originally committed as revision 2447 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/avformat.h | 23 ++++-- libavformat/mpeg.c | 3 +- libavformat/utils.c | 165 +++++++++++++++++++++++------------------ 3 files changed, 112 insertions(+), 79 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 7de9c8ee3c..f3a89fdf4b 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -5,7 +5,7 @@ extern "C" { #endif -#define LIBAVFORMAT_BUILD 4608 +#define LIBAVFORMAT_BUILD 4609 #define LIBAVFORMAT_VERSION_INT FFMPEG_VERSION_INT #define LIBAVFORMAT_VERSION FFMPEG_VERSION @@ -42,6 +42,7 @@ typedef struct AVPacket { } AVPacket; #define PKT_FLAG_KEY 0x0001 +/* initialize optional fields of a packet */ static inline void av_init_packet(AVPacket *pkt) { pkt->pts = AV_NOPTS_VALUE; @@ -102,12 +103,14 @@ typedef struct AVFormatParameters { int channel; /* used to select dv channel */ const char *device; /* video4linux, audio or DV device */ const char *standard; /* tv standard, NTSC, PAL, SECAM */ + int mpeg2ts_raw:1; /* force raw MPEG2 transport stream output, if possible */ + int mpeg2ts_compute_pcr:1; /* compute exact PCR for each transport + stream packet (only meaningful if + mpeg2ts_raw is TRUE */ } AVFormatParameters; #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_RAWPICTURE 0x0020 /* format wants AVPicture structure for raw picture data */ @@ -150,7 +153,7 @@ typedef struct AVInputFormat { AVFormatParameters *ap); /* 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. */ + AVFMTCTX_NOHEADER is used. */ int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); /* close the stream. The AVFormatContext and AVStreams are not freed by this function */ @@ -158,7 +161,7 @@ typedef struct AVInputFormat { /* seek at or before a given pts (given in microsecond). The pts origin is defined by the stream */ int (*read_seek)(struct AVFormatContext *, int64_t pts); - /* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_NOHEADER */ + /* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */ int flags; /* if extensions are defined, then no probe is done. You should usually not use extension format guessing because it is not @@ -181,7 +184,7 @@ typedef struct AVStream { int codec_info_state; int codec_info_nb_repeat_frames; int codec_info_nb_real_frames; - /* PTS generation when outputing stream */ + /* encoding: PTS generation when outputing stream */ AVFrac pts; /* ffmpeg.c private use */ int stream_copy; /* if TRUE, just copy stream */ @@ -196,6 +199,9 @@ typedef struct AVStream { int64_t duration; } AVStream; +#define AVFMTCTX_NOHEADER 0x0001 /* signal that no header is present + (streams are added dynamically) */ + #define MAX_STREAMS 20 /* format I/O context */ @@ -218,7 +224,7 @@ typedef struct AVFormatContext { int track; /* track number, 0 if none */ char genre[32]; /* ID3 genre */ - int flags; /* format specific flags */ + int ctx_flags; /* format specific flags, see AVFMTCTX_xx */ /* private data for pts handling (do not modify directly) */ int pts_wrap_bits; /* number of bits in pts (used for wrapping control) */ int pts_num, pts_den; /* value to convert to seconds */ @@ -448,6 +454,9 @@ void fifo_write(FifoBuffer *f, uint8_t *buf, int size, uint8_t **wptr_ptr); /* media file input */ AVInputFormat *av_find_input_format(const char *short_name); AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); +int av_open_input_stream(AVFormatContext **ic_ptr, + ByteIOContext *pb, const char *filename, + AVInputFormat *fmt, AVFormatParameters *ap); int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 45ffdf6841..9c138556f1 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -479,6 +479,8 @@ static int mpegps_read_header(AVFormatContext *s, { MpegDemuxContext *m = s->priv_data; m->header_state = 0xff; + s->ctx_flags |= AVFMTCTX_NOHEADER; + /* no need to do more */ return 0; } @@ -705,7 +707,6 @@ AVInputFormat mpegps_demux = { mpegps_read_header, mpegps_read_packet, mpegps_read_close, - .flags = AVFMT_NOHEADER, }; int mpegps_init(void) diff --git a/libavformat/utils.c b/libavformat/utils.c index 70c9e6e192..ddd26f1b7d 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -274,6 +274,56 @@ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened) /************************************************************/ /* input media file */ +/** + * open a media file from an IO stream. 'fmt' must be specified. + */ +int av_open_input_stream(AVFormatContext **ic_ptr, + ByteIOContext *pb, const char *filename, + AVInputFormat *fmt, AVFormatParameters *ap) +{ + int err; + AVFormatContext *ic; + + ic = av_mallocz(sizeof(AVFormatContext)); + if (!ic) { + err = AVERROR_NOMEM; + goto fail; + } + ic->iformat = fmt; + if (pb) + ic->pb = *pb; + ic->duration = AV_NOPTS_VALUE; + ic->start_time = AV_NOPTS_VALUE; + pstrcpy(ic->filename, sizeof(ic->filename), filename); + + /* allocate private data */ + if (fmt->priv_data_size > 0) { + ic->priv_data = av_mallocz(fmt->priv_data_size); + if (!ic->priv_data) { + err = AVERROR_NOMEM; + goto fail; + } + } else { + ic->priv_data = NULL; + } + + /* default pts settings is MPEG like */ + av_set_pts_info(ic, 33, 1, 90000); + + err = ic->iformat->read_header(ic, ap); + if (err < 0) + goto fail; + *ic_ptr = ic; + return 0; + fail: + if (ic) { + av_freep(&ic->priv_data); + } + av_free(ic); + *ic_ptr = NULL; + return err; +} + #define PROBE_BUF_SIZE 2048 /** @@ -292,20 +342,15 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, int buf_size, AVFormatParameters *ap) { - AVFormatContext *ic = NULL; - int err, must_open_file; - unsigned char buf[PROBE_BUF_SIZE]; + int err, must_open_file, file_opened; + uint8_t buf[PROBE_BUF_SIZE]; AVProbeData probe_data, *pd = &probe_data; - - ic = av_mallocz(sizeof(AVFormatContext)); - if (!ic) { - err = AVERROR_NOMEM; - goto fail; - } - ic->duration = AV_NOPTS_VALUE; - ic->start_time = AV_NOPTS_VALUE; - pstrcpy(ic->filename, sizeof(ic->filename), filename); - pd->filename = ic->filename; + ByteIOContext pb1, *pb = &pb1; + + file_opened = 0; + pd->filename = ""; + if (filename) + pd->filename = filename; pd->buf = buf; pd->buf_size = 0; @@ -317,27 +362,24 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, /* do not open file if the format does not need it. XXX: specific hack needed to handle RTSP/TCP */ must_open_file = 1; - if ((fmt && (fmt->flags & AVFMT_NOFILE)) -#ifdef CONFIG_NETWORK - || (fmt == &rtp_demux && !strcmp(filename, "null")) -#endif - ) { + if (fmt && (fmt->flags & AVFMT_NOFILE)) { must_open_file = 0; } if (!fmt || must_open_file) { /* if no file needed do not try to open one */ - if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0) { + if (url_fopen(pb, filename, URL_RDONLY) < 0) { err = AVERROR_IO; goto fail; } + file_opened = 1; if (buf_size > 0) { - url_setbufsize(&ic->pb, buf_size); + url_setbufsize(pb, buf_size); } if (!fmt) { /* read probe data */ - pd->buf_size = get_buffer(&ic->pb, buf, PROBE_BUF_SIZE); - url_fseek(&ic->pb, 0, SEEK_SET); + pd->buf_size = get_buffer(pb, buf, PROBE_BUF_SIZE); + url_fseek(pb, 0, SEEK_SET); } } @@ -349,65 +391,46 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, /* if still no format found, error */ if (!fmt) { err = AVERROR_NOFMT; - goto fail1; + goto fail; } /* XXX: suppress this hack for redirectors */ #ifdef CONFIG_NETWORK if (fmt == &redir_demux) { - err = redir_open(ic_ptr, &ic->pb); - url_fclose(&ic->pb); - av_free(ic); + err = redir_open(ic_ptr, pb); + url_fclose(pb); return err; } #endif - ic->iformat = fmt; - /* check filename in case of an image number is expected */ - if (ic->iformat->flags & AVFMT_NEEDNUMBER) { - if (filename_number_test(ic->filename) < 0) { + if (fmt->flags & AVFMT_NEEDNUMBER) { + if (filename_number_test(filename) < 0) { err = AVERROR_NUMEXPECTED; - goto fail1; + goto fail; } } - - /* allocate private data */ - if (fmt->priv_data_size > 0) { - ic->priv_data = av_mallocz(fmt->priv_data_size); - if (!ic->priv_data) { - err = AVERROR_NOMEM; - goto fail1; - } - } else - ic->priv_data = NULL; - - /* default pts settings is MPEG like */ - av_set_pts_info(ic, 33, 1, 90000); - - err = ic->iformat->read_header(ic, ap); - if (err < 0) - goto fail1; - *ic_ptr = ic; + err = av_open_input_stream(ic_ptr, pb, filename, fmt, ap); + if (err) + goto fail; return 0; - fail1: - if (!fmt || must_open_file) { - url_fclose(&ic->pb); - } fail: - if (ic) { - av_freep(&ic->priv_data); - } - av_free(ic); + if (file_opened) + url_fclose(pb); *ic_ptr = NULL; return err; + } +/*******************************************************/ + /** - * Read a packet from a media file + * Read a packet from a media file. Use it only for low level file + * reading. It is almost always better to use av_read_frame(). + * * @param s media file handle * @param pkt is filled - * @return 0 if OK. AVERROR_xxx if error. + * @return 0 if OK. AVERROR_xxx if error. */ int av_read_packet(AVFormatContext *s, AVPacket *pkt) { @@ -425,6 +448,7 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) } } +/*******************************************************/ /* return TRUE if the stream has accurate timings for at least one component */ static int av_has_timings(AVFormatContext *ic) @@ -796,7 +820,7 @@ int av_find_stream_info(AVFormatContext *ic) /* 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) || + if (!(ic->ctx_flags & AVFMTCTX_NOHEADER) || read_size >= min_read_size) { /* if we found the info for all the codecs, we can stop */ ret = count; @@ -821,12 +845,12 @@ int av_find_stream_info(AVFormatContext *ic) ppktl = &pktl->next; /* NOTE: a new stream can be added there if no header in file - (AVFMT_NOHEADER) */ + (AVFMTCTX_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) && + if ((ic->ctx_flags & AVFMTCTX_NOHEADER) && i == ic->nb_streams) ret = 0; break; @@ -950,11 +974,14 @@ int av_find_stream_info(AVFormatContext *ic) void av_close_input_file(AVFormatContext *s) { int i, must_open_file; + AVStream *st; if (s->iformat->read_close) s->iformat->read_close(s); for(i=0;inb_streams;i++) { - av_free(s->streams[i]); + /* free all data in a stream component */ + st = s->streams[i]; + av_free(st); } if (s->packet_buffer) { AVPacketList *p, *p1; @@ -968,11 +995,7 @@ void av_close_input_file(AVFormatContext *s) s->packet_buffer = NULL; } must_open_file = 1; - if ((s->iformat->flags & AVFMT_NOFILE) -#ifdef CONFIG_NETWORK - || (s->iformat == &rtp_demux && !strcmp(s->filename, "null")) -#endif - ) { + if (s->iformat->flags & AVFMT_NOFILE) { must_open_file = 0; } if (must_open_file) { @@ -984,12 +1007,12 @@ void av_close_input_file(AVFormatContext *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. + * read_header function. If the flag AVFMTCTX_NOHEADER is in the + * format context, then new streams can be added in read_packet too. * * * @param s media file handle - * @param id file format dependent stream id + * @param id file format dependent stream id */ AVStream *av_new_stream(AVFormatContext *s, int id) {