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
- VAAPI VP9 hwaccel
- audio high-order multiband parametric equalizer
- automatic bitstream filtering
version 2.8:

View File

@ -15,6 +15,9 @@ libavutil: 2015-08-28
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
Deprecate avfilter_link_set_closed().
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);
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;
/**
* @}

View File

@ -117,6 +117,11 @@ struct AVFormatInternal {
int inject_global_side_data;
int avoid_negative_ts_use_pts;
/**
* Whether or not a header has already been written
*/
int header_written;
};
struct AVStreamInternal {
@ -125,6 +130,18 @@ struct AVStreamInternal {
* from dts.
*/
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__

View File

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

View File

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