On Wed, Oct 07, 2015 at 09:50:05PM -0500, Rodger Combs wrote: > This solves the problem discussed in > https://ffmpeg.org/pipermail/ffmpeg-devel/2015-September/179238.html > by allowing AVCodec::write_header to be delayed until after packets have been > run through required bitstream filters in order to generate global extradata. > > It also provides a mechanism by which a muxer can add a bitstream filter to a > stream automatically, rather than prompting the user to do so. > --- > libavformat/avformat.h | 29 +++++++++++++++++++++++++++++ > libavformat/mux.c | 31 ++++++++++++++++++++++++++++--- > 2 files changed, 57 insertions(+), 3 deletions(-) > > diff --git a/libavformat/avformat.h b/libavformat/avformat.h > index 5226b0a..f3c8260 100644 > --- a/libavformat/avformat.h > +++ b/libavformat/avformat.h > @@ -598,6 +598,21 @@ typedef struct AVOutputFormat { > */ > int (*free_device_capabilities)(struct AVFormatContext *s, struct > AVDeviceCapabilitiesQuery *caps); > enum AVCodecID data_codec; /**< default data codec */ > + /** > + * Initialize format. May allocate data here, and set any > AVFormatContext or > + * AVStream parameters that need to be set before packets are sent. > + * Must not write output. > + * > + * FIXME: Data allocated here would be leaked if there's a failure before > + * write_header is called. Ban allocations? Add a `deinit` cleanup > function? > + */ > + int (*init)(struct AVFormatContext *); > + /** > + * Set up any necessary bitstream filtering and extract any extra data > needed > + * for the global header. > + * Return 0 if more packets from this stream must be checked; 1 if not. > + */ > + int (*check_bitstream)(struct AVFormatContext *, const AVPacket *pkt); > } AVOutputFormat; > /** > * @} > @@ -1167,6 +1182,18 @@ typedef struct AVStream { > AVRational display_aspect_ratio; > > struct FFFrac *priv_pts; > + > + /** > + * bitstream filter to run on stream > + * - encoding: Set by muxer or user using av_add_bitstream_filter > + * - decoding: unused > + */ > + AVBitStreamFilterContext *bsfc; > + > + /** > + * internal check if check_bitstream should still be run on each packet > + */ > + int bitstream_checked; > } AVStream; > > AVRational av_stream_get_r_frame_rate(const AVStream *s); > @@ -1782,6 +1809,8 @@ typedef struct AVFormatContext { > * Demuxing: Set by user. > */ > int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char > *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); > + > + int header_written; > } AVFormatContext; > > int av_format_get_probe_score(const AVFormatContext *s); > diff --git a/libavformat/mux.c b/libavformat/mux.c > index c9ef490..b5b2c8a 100644 > --- a/libavformat/mux.c > +++ b/libavformat/mux.c > @@ -400,7 +400,7 @@ FF_ENABLE_DEPRECATION_WARNINGS > *options = tmp; > } > > - return 0; > + return s->oformat->init ? s->oformat->init(s) : 0; > > fail: > av_dict_free(&tmp); > @@ -451,7 +451,7 @@ int avformat_write_header(AVFormatContext *s, > AVDictionary **options) > if ((ret = init_muxer(s, options)) < 0) > return ret; > > - if (s->oformat->write_header) { > + if (s->oformat->write_header && !s->oformat->check_bitstream) { > ret = s->oformat->write_header(s); > if (ret >= 0 && s->pb && s->pb->error < 0) > ret = s->pb->error; > @@ -459,6 +459,7 @@ int avformat_write_header(AVFormatContext *s, > AVDictionary **options) > return ret; > if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & > AVFMT_FLAG_FLUSH_PACKETS) > avio_flush(s->pb); > + s->header_written = 1; > } > > if ((ret = init_pts(s)) < 0) > @@ -951,6 +952,18 @@ int av_interleaved_write_frame(AVFormatContext *s, > AVPacket *pkt) > ret = AVERROR(EINVAL); > goto fail; > } > + > + if (s->oformat->check_bitstream) { > + if (!st->bitstream_checked) { > + if ((ret = s->oformat->check_bitstream(s, pkt)) < 0) > + goto fail; > + else if (ret == 1) > + st->bitstream_checked = 1; > + } > + } > + > + if ((ret = av_apply_bitstream_filters(s, pkt, st->bsfc)) < 0) > + goto fail; > } else { > av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n"); > flush = 1; > @@ -967,10 +980,22 @@ int av_interleaved_write_frame(AVFormatContext *s, > AVPacket *pkt) > if (ret <= 0) //FIXME cleanup needed for ret<0 ? > return ret; > > + if (!s->header_written && s->oformat->write_header) { > + ret = s->oformat->write_header(s); > + if (ret >= 0 && s->pb && s->pb->error < 0) > + ret = s->pb->error; > + if (ret < 0) > + goto fail2; > + if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & > AVFMT_FLAG_FLUSH_PACKETS) > + avio_flush(s->pb); > + s->header_written = 1; > + } > + > ret = write_packet(s, &opkt); > if (ret >= 0) > s->streams[opkt.stream_index]->nb_frames++; > > +fail2: > av_free_packet(&opkt); > > if (ret < 0) > @@ -1008,7 +1033,7 @@ int av_write_trailer(AVFormatContext *s) > } > > fail: > - if (s->oformat->write_trailer) > + if (s->header_written && s->oformat->write_trailer)
this changes the behavior in case no packets are written as then also no header or trailer is ever written while previously a header and trailer was written [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB No snowflake in an avalanche ever feels responsible. -- Voltaire
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel