lavf: add automatic bitstream filtering; bump version

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.
This commit is contained in:
Rodger Combs 2015-10-07 21:32:14 -05:00
parent 7a161b74ad
commit 1f9139b07b
6 changed files with 91 additions and 4 deletions

View File

@ -48,6 +48,7 @@ version <next>:
- SOFAlizer: virtual binaural acoustics filter - SOFAlizer: virtual binaural acoustics filter
- VAAPI VP9 hwaccel - VAAPI VP9 hwaccel
- audio high-order multiband parametric equalizer - audio high-order multiband parametric equalizer
- automatic bitstream filtering
version 2.8: version 2.8:

View File

@ -15,6 +15,9 @@ libavutil: 2015-08-28
API changes, most recent first: API changes, most recent first:
2015-12-28 - xxxxxxx - lavf 57.21.100 - avformat.h
Add automatic bitstream filtering; add av_apply_bitstream_filters()
2015-12-22 - xxxxxxx - lavfi 6.21.101 - avfilter.h 2015-12-22 - xxxxxxx - lavfi 6.21.101 - avfilter.h
Deprecate avfilter_link_set_closed(). Deprecate avfilter_link_set_closed().
Applications are not supposed to mess with links, Applications are not supposed to mess with links,

View File

@ -600,6 +600,29 @@ typedef struct AVOutputFormat {
*/ */
int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
enum AVCodecID data_codec; /**< default data codec */ 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.
* This method must not write output.
*
* Any allocations made here must be freed in deinit().
*/
int (*init)(struct AVFormatContext *);
/**
* Deinitialize format. If present, this is called whenever the muxer is being
* destroyed, regardless of whether or not the header has been written.
*
* If a trailer is being written, this is called after write_trailer().
*
* This is called if init() fails as well.
*/
void (*deinit)(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; } AVOutputFormat;
/** /**
* @} * @}

View File

@ -117,6 +117,11 @@ struct AVFormatInternal {
int inject_global_side_data; int inject_global_side_data;
int avoid_negative_ts_use_pts; int avoid_negative_ts_use_pts;
/**
* Whether or not a header has already been written
*/
int header_written;
}; };
struct AVStreamInternal { struct AVStreamInternal {
@ -125,6 +130,18 @@ struct AVStreamInternal {
* from dts. * from dts.
*/ */
int reorder; int reorder;
/**
* bitstream filter to run on stream
* - encoding: Set by muxer using ff_stream_add_bitstream_filter
* - decoding: unused
*/
AVBitStreamFilterContext *bsfc;
/**
* Whether or not check_bitstream should still be run on each packet
*/
int bitstream_checked;
}; };
#ifdef __GNUC__ #ifdef __GNUC__

View File

@ -405,6 +405,11 @@ FF_ENABLE_DEPRECATION_WARNINGS
*options = tmp; *options = tmp;
} }
if (s->oformat->init && (ret = s->oformat->init(s)) < 0) {
s->oformat->deinit(s);
goto fail;
}
return 0; return 0;
fail: fail:
@ -456,7 +461,7 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
if ((ret = init_muxer(s, options)) < 0) if ((ret = init_muxer(s, options)) < 0)
return ret; return ret;
if (s->oformat->write_header) { if (s->oformat->write_header && !s->oformat->check_bitstream) {
ret = s->oformat->write_header(s); ret = s->oformat->write_header(s);
if (ret >= 0 && s->pb && s->pb->error < 0) if (ret >= 0 && s->pb && s->pb->error < 0)
ret = s->pb->error; ret = s->pb->error;
@ -464,6 +469,7 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
return ret; return ret;
if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb); avio_flush(s->pb);
s->internal->header_written = 1;
} }
if ((ret = init_pts(s)) < 0) if ((ret = init_pts(s)) < 0)
@ -668,6 +674,18 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
} }
did_split = av_packet_split_side_data(pkt); did_split = av_packet_split_side_data(pkt);
if (!s->internal->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 fail;
if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb);
s->internal->header_written = 1;
}
if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
AVFrame *frame = (AVFrame *)pkt->data; AVFrame *frame = (AVFrame *)pkt->data;
av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
@ -684,7 +702,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
ret = s->pb->error; ret = s->pb->error;
} }
fail:
if (did_split) if (did_split)
av_packet_merge_side_data(pkt); av_packet_merge_side_data(pkt);
@ -1021,6 +1039,17 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
ret = AVERROR(EINVAL); ret = AVERROR(EINVAL);
goto fail; goto fail;
} }
if (s->oformat->check_bitstream) {
if (!st->internal->bitstream_checked) {
if ((ret = s->oformat->check_bitstream(s, pkt)) < 0)
goto fail;
else if (ret == 1)
st->internal->bitstream_checked = 1;
}
}
av_apply_bitstream_filters(st->codec, pkt, st->internal->bsfc);
} else { } else {
av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n"); av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n");
flush = 1; flush = 1;
@ -1077,14 +1106,28 @@ int av_write_trailer(AVFormatContext *s)
goto fail; goto fail;
} }
if (!s->internal->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 fail;
if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb);
s->internal->header_written = 1;
}
fail: fail:
if (s->oformat->write_trailer) if ((s->internal->header_written || !s->oformat->write_header) && s->oformat->write_trailer)
if (ret >= 0) { if (ret >= 0) {
ret = s->oformat->write_trailer(s); ret = s->oformat->write_trailer(s);
} else { } else {
s->oformat->write_trailer(s); s->oformat->write_trailer(s);
} }
if (s->oformat->deinit)
s->oformat->deinit(s);
if (s->pb) if (s->pb)
avio_flush(s->pb); avio_flush(s->pb);
if (ret == 0) if (ret == 0)

View File

@ -30,7 +30,7 @@
#include "libavutil/version.h" #include "libavutil/version.h"
#define LIBAVFORMAT_VERSION_MAJOR 57 #define LIBAVFORMAT_VERSION_MAJOR 57
#define LIBAVFORMAT_VERSION_MINOR 20 #define LIBAVFORMAT_VERSION_MINOR 21
#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \