-
-
Save rcombs/742d985f3dd5848d7f2d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ffmpeg.c b/ffmpeg.c | |
index e31a2c6..e6cd0e8 100644 | |
--- a/ffmpeg.c | |
+++ b/ffmpeg.c | |
@@ -682,47 +682,10 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) | |
if (bsfc) | |
av_packet_split_side_data(pkt); | |
- while (bsfc) { | |
- AVPacket new_pkt = *pkt; | |
- AVDictionaryEntry *bsf_arg = av_dict_get(ost->bsf_args, | |
- bsfc->filter->name, | |
- NULL, 0); | |
- int a = av_bitstream_filter_filter(bsfc, avctx, | |
- bsf_arg ? bsf_arg->value : NULL, | |
- &new_pkt.data, &new_pkt.size, | |
- pkt->data, pkt->size, | |
- pkt->flags & AV_PKT_FLAG_KEY); | |
- if(a == 0 && new_pkt.data != pkt->data) { | |
- uint8_t *t = av_malloc(new_pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); //the new should be a subset of the old so cannot overflow | |
- if(t) { | |
- memcpy(t, new_pkt.data, new_pkt.size); | |
- memset(t + new_pkt.size, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
- new_pkt.data = t; | |
- new_pkt.buf = NULL; | |
- a = 1; | |
- } else | |
- a = AVERROR(ENOMEM); | |
- } | |
- if (a > 0) { | |
- pkt->side_data = NULL; | |
- pkt->side_data_elems = 0; | |
- av_free_packet(pkt); | |
- new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size, | |
- av_buffer_default_free, NULL, 0); | |
- if (!new_pkt.buf) | |
- exit_program(1); | |
- } else if (a < 0) { | |
- new_pkt = *pkt; | |
- av_log(NULL, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s", | |
- bsfc->filter->name, pkt->stream_index, | |
- avctx->codec ? avctx->codec->name : "copy"); | |
- print_error("", a); | |
- if (exit_on_error) | |
- exit_program(1); | |
- } | |
- *pkt = new_pkt; | |
- | |
- bsfc = bsfc->next; | |
+ if (ret = av_apply_bitstream_filters(s, pkt, bsfc, ost->bsf_args) < 0) { | |
+ print_error("", ret); | |
+ if (exit_on_error) | |
+ exit_program(1); | |
} | |
if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) { | |
diff --git a/libavformat/avformat.h b/libavformat/avformat.h | |
index e2a27d4..62807c4 100644 | |
--- a/libavformat/avformat.h | |
+++ b/libavformat/avformat.h | |
@@ -598,6 +598,10 @@ typedef struct AVOutputFormat { | |
*/ | |
int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); | |
enum AVCodecID data_codec; /**< default data codec */ | |
+ /** | |
+ * Check if a packet requires a bitstream filter. If so, | |
+ */ | |
+ int (*check_bitstream)(struct AVFormatContext *, const AVPacket *pkt); | |
} AVOutputFormat; | |
/** | |
* @} | |
@@ -1167,6 +1171,14 @@ typedef struct AVStream { | |
AVRational display_aspect_ratio; | |
struct FFFrac *priv_pts; | |
+ | |
+ /** | |
+ * bitstream filter to run on stream | |
+ * - encoding: Set by muxer | |
+ * - decoding: unused | |
+ */ | |
+ int bitstream_checked; | |
+ AVBitStreamFilterContext *bsfc; | |
} AVStream; | |
AVRational av_stream_get_r_frame_rate(const AVStream *s); | |
@@ -1782,6 +1794,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); | |
@@ -2728,6 +2742,8 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, | |
int avformat_queue_attached_pictures(AVFormatContext *s); | |
+int av_apply_bitstream_filters(AVFormatContext *s, AVPacket *pkt, | |
+ AVBitStreamFilterContext *bsfc, AVDictionary *bsf_args); | |
/** | |
* @} | |
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c | |
index 1fb39fe..b26d864 100644 | |
--- a/libavformat/matroskaenc.c | |
+++ b/libavformat/matroskaenc.c | |
@@ -2106,6 +2106,23 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance) | |
return 0; | |
} | |
+static int mkv_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) | |
+{ | |
+ AVStream *st = s->streams[pkt->stream_index]; | |
+ if (st->codec->codec_id == AV_CODEC_ID_AAC) { | |
+ if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { | |
+ if (!(st->bsfc = av_bitstream_filter_init("aac_adtstoasc"))) { | |
+ av_log(s, AV_LOG_FATAL, "Unknown bitstream filter aac_adtstoasc\n"); | |
+ return AVERROR(EINVAL); | |
+ } | |
+ } | |
+ } | |
+ | |
+ st->bitstream_checked = 1; | |
+ | |
+ return 0; | |
+} | |
+ | |
static const AVCodecTag additional_audio_tags[] = { | |
{ AV_CODEC_ID_ALAC, 0XFFFFFFFF }, | |
{ AV_CODEC_ID_EAC3, 0XFFFFFFFF }, | |
@@ -2179,6 +2196,7 @@ AVOutputFormat ff_matroska_muxer = { | |
}, | |
.subtitle_codec = AV_CODEC_ID_ASS, | |
.query_codec = mkv_query_codec, | |
+ .check_bitstream = mkv_check_bitstream, | |
.priv_class = &matroska_class, | |
}; | |
#endif | |
@@ -2198,11 +2216,12 @@ AVOutputFormat ff_webm_muxer = { | |
.extensions = "webm", | |
.priv_data_size = sizeof(MatroskaMuxContext), | |
.audio_codec = CONFIG_LIBOPUS_ENCODER ? AV_CODEC_ID_OPUS : AV_CODEC_ID_VORBIS, | |
- .video_codec = CONFIG_LIBVPX_VP9_ENCODER? AV_CODEC_ID_VP9 : AV_CODEC_ID_VP8, | |
+ .video_codec = CONFIG_LIBVPX_VP9_ENCODER ? AV_CODEC_ID_VP9 : AV_CODEC_ID_VP8, | |
.subtitle_codec = AV_CODEC_ID_WEBVTT, | |
.write_header = mkv_write_header, | |
.write_packet = mkv_write_flush_packet, | |
.write_trailer = mkv_write_trailer, | |
+ .check_bitstream = mkv_check_bitstream, | |
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | | |
AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH, | |
.priv_class = &webm_class, | |
@@ -2228,6 +2247,7 @@ AVOutputFormat ff_matroska_audio_muxer = { | |
.write_header = mkv_write_header, | |
.write_packet = mkv_write_flush_packet, | |
.write_trailer = mkv_write_trailer, | |
+ .check_bitstream = mkv_check_bitstream, | |
.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT | | |
AVFMT_ALLOW_FLUSH, | |
.codec_tag = (const AVCodecTag* const []){ | |
diff --git a/libavformat/mux.c b/libavformat/mux.c | |
index c9ef490..e9de72f 100644 | |
--- a/libavformat/mux.c | |
+++ b/libavformat/mux.c | |
@@ -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,16 @@ 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; | |
+ } | |
+ } | |
+ | |
+ if ((ret = av_apply_bitstream_filters(s, pkt, st->bsfc, NULL)) < 0) | |
+ goto fail; | |
} else { | |
av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame FLUSH\n"); | |
flush = 1; | |
@@ -967,10 +978,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) | |
diff --git a/libavformat/utils.c b/libavformat/utils.c | |
index 689473e..c98b8e0 100644 | |
--- a/libavformat/utils.c | |
+++ b/libavformat/utils.c | |
@@ -4596,3 +4596,53 @@ uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type, | |
sd->size = size; | |
return data; | |
} | |
+ | |
+int av_apply_bitstream_filters(AVFormatContext *s, AVPacket *pkt, | |
+ AVBitStreamFilterContext *bsfc, AVDictionary *bsf_args) | |
+{ | |
+ int ret = 0; | |
+ AVStream *st = s->streams[pkt->stream_index]; | |
+ while (bsfc) { | |
+ AVPacket new_pkt = *pkt; | |
+ AVDictionaryEntry *bsf_arg = av_dict_get(bsf_args, bsfc->filter->name, NULL, 0); | |
+ int a = av_bitstream_filter_filter(bsfc, st->codec, | |
+ bsf_arg ? bsf_arg->value : NULL, | |
+ &new_pkt.data, &new_pkt.size, | |
+ pkt->data, pkt->size, | |
+ pkt->flags & AV_PKT_FLAG_KEY); | |
+ if(a == 0 && new_pkt.data != pkt->data) { | |
+ uint8_t *t = av_malloc(new_pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); //the new should be a subset of the old so cannot overflow | |
+ if (t) { | |
+ memcpy(t, new_pkt.data, new_pkt.size); | |
+ memset(t + new_pkt.size, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
+ new_pkt.data = t; | |
+ new_pkt.buf = NULL; | |
+ a = 1; | |
+ } else { | |
+ a = AVERROR(ENOMEM); | |
+ } | |
+ } | |
+ if (a > 0) { | |
+ new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size, | |
+ av_buffer_default_free, NULL, 0); | |
+ if (new_pkt.buf) { | |
+ pkt->side_data = NULL; | |
+ pkt->side_data_elems = 0; | |
+ av_free_packet(pkt); | |
+ } else { | |
+ a = AVERROR(ENOMEM); | |
+ } | |
+ } | |
+ if (a < 0) { | |
+ av_log(s, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s", | |
+ bsfc->filter->name, pkt->stream_index, | |
+ st->codec->codec ? st->codec->codec->name : "copy"); | |
+ ret = a; | |
+ break; | |
+ } | |
+ *pkt = new_pkt; | |
+ | |
+ bsfc = bsfc->next; | |
+ } | |
+ return ret; | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment