From: Gyan Doshi <ffmpeg@gyani.pro>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH 11/13] avformat/demux: support inserting bitstream filters in demuxing scenarios
Date: Tue, 28 Nov 2023 09:30:04 +0530
Message-ID: <2eeae382-e529-4cc1-a48b-ee6b6d7ce559@gyani.pro> (raw)
In-Reply-To: <20231127184357.3361-2-jamrial@gmail.com>
On 2023-11-28 12:13 am, James Almer wrote:
> Packets will be passed to the bsf immediately after being generated by a
> demuxer, and no further data will be read from the input until all packets
> have been returned by the bsf.
Do you plan to add a lib/cli option for user-specified insertions?
Will be useful for something like dts2pts in some cases.
Regards,
Gyan
>
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> libavformat/avformat.c | 47 ++++++++++++
> libavformat/demux.c | 162 ++++++++++++++++++++++++++++++-----------
> libavformat/internal.h | 13 +++-
> libavformat/mux.c | 43 -----------
> libavformat/mux.h | 11 ---
> libavformat/rawenc.c | 1 +
> 6 files changed, 181 insertions(+), 96 deletions(-)
>
> diff --git a/libavformat/avformat.c b/libavformat/avformat.c
> index a02ec965dd..a41c0b391c 100644
> --- a/libavformat/avformat.c
> +++ b/libavformat/avformat.c
> @@ -1033,3 +1033,50 @@ FF_ENABLE_DEPRECATION_WARNINGS
> *pb = NULL;
> return ret;
> }
> +
> +int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char *args)
> +{
> + int ret;
> + const AVBitStreamFilter *bsf;
> + FFStream *const sti = ffstream(st);
> + AVBSFContext *bsfc;
> +
> + av_assert0(!sti->bsfc);
> +
> + if (name) {
> + bsf = av_bsf_get_by_name(name);
> + if (!bsf) {
> + av_log(NULL, AV_LOG_ERROR, "Unknown bitstream filter '%s'\n", name);
> + return AVERROR_BSF_NOT_FOUND;
> + }
> + ret = av_bsf_alloc(bsf, &bsfc);
> + } else
> + ret = av_bsf_get_null_filter(&bsfc);
> + if (ret < 0)
> + return ret;
> +
> + bsfc->time_base_in = st->time_base;
> + if ((ret = avcodec_parameters_copy(bsfc->par_in, st->codecpar)) < 0) {
> + av_bsf_free(&bsfc);
> + return ret;
> + }
> +
> + if (args && bsfc->filter->priv_class) {
> + if ((ret = av_set_options_string(bsfc->priv_data, args, "=", ":")) < 0) {
> + av_bsf_free(&bsfc);
> + return ret;
> + }
> + }
> +
> + if ((ret = av_bsf_init(bsfc)) < 0) {
> + av_bsf_free(&bsfc);
> + return ret;
> + }
> +
> + sti->bsfc = bsfc;
> +
> + av_log(NULL, AV_LOG_VERBOSE,
> + "Automatically inserted bitstream filter '%s'; args='%s'\n",
> + name, args ? args : "");
> + return 1;
> +}
> diff --git a/libavformat/demux.c b/libavformat/demux.c
> index 6f640b92b1..fb9bf9e4ac 100644
> --- a/libavformat/demux.c
> +++ b/libavformat/demux.c
> @@ -540,6 +540,109 @@ static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_in
> return 1;
> }
>
> +static void update_timestamps(AVFormatContext *s, AVStream *st, AVPacket *pkt)
> +{
> + FFStream *const sti = ffstream(st);
> +
> + if (update_wrap_reference(s, st, pkt->stream_index, pkt) && sti->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
> + // correct first time stamps to negative values
> + if (!is_relative(sti->first_dts))
> + sti->first_dts = wrap_timestamp(st, sti->first_dts);
> + if (!is_relative(st->start_time))
> + st->start_time = wrap_timestamp(st, st->start_time);
> + if (!is_relative(sti->cur_dts))
> + sti->cur_dts = wrap_timestamp(st, sti->cur_dts);
> + }
> +
> + pkt->dts = wrap_timestamp(st, pkt->dts);
> + pkt->pts = wrap_timestamp(st, pkt->pts);
> +
> + force_codec_ids(s, st);
> +
> + /* TODO: audio: time filter; video: frame reordering (pts != dts) */
> + if (s->use_wallclock_as_timestamps)
> + pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
> +}
> +
> +static int filter_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt)
> +{
> + FFFormatContext *const si = ffformatcontext(s);
> + FFStream *const sti = ffstream(st);
> + const AVPacket *pkt1;
> + int err;
> +
> + if (!sti->bsfc) {
> + const PacketListEntry *pktl = si->raw_packet_buffer.head;
> + if (AVPACKET_IS_EMPTY(pkt))
> + return 0;
> +
> + update_timestamps(s, st, pkt);
> +
> + if (!pktl && sti->request_probe <= 0)
> + return 0;
> +
> + err = avpriv_packet_list_put(&si->raw_packet_buffer, pkt, NULL, 0);
> + if (err < 0) {
> + av_packet_unref(pkt);
> + return err;
> + }
> +
> + pkt1 = &si->raw_packet_buffer.tail->pkt;
> + si->raw_packet_buffer_size += pkt1->size;
> +
> + if (sti->request_probe <= 0)
> + return 0;
> +
> + return probe_codec(s, s->streams[pkt1->stream_index], pkt1);
> + }
> +
> + err = av_bsf_send_packet(sti->bsfc, pkt);
> + if (err < 0) {
> + av_log(s, AV_LOG_ERROR,
> + "Failed to send packet to filter %s for stream %d\n",
> + sti->bsfc->filter->name, st->index);
> + return err;
> + }
> +
> + do {
> + AVStream *out_st;
> + FFStream *out_sti;
> +
> + err = av_bsf_receive_packet(sti->bsfc, pkt);
> + if (err < 0) {
> + if (err == AVERROR(EAGAIN) || err == AVERROR_EOF)
> + return 0;
> + av_log(s, AV_LOG_ERROR, "Error applying bitstream filters to an output "
> + "packet for stream #%d: %s\n", st->index, av_err2str(err));
> + if (!(s->error_recognition & AV_EF_EXPLODE) && err != AVERROR(ENOMEM))
> + continue;
> + return err;
> + }
> + out_st = s->streams[pkt->stream_index];
> + out_sti = ffstream(out_st);
> +
> + update_timestamps(s, out_st, pkt);
> +
> + err = avpriv_packet_list_put(&si->raw_packet_buffer, pkt, NULL, 0);
> + if (err < 0) {
> + av_packet_unref(pkt);
> + return err;
> + }
> +
> + pkt1 = &si->raw_packet_buffer.tail->pkt;
> + si->raw_packet_buffer_size += pkt1->size;
> +
> + if (out_sti->request_probe <= 0)
> + continue;
> +
> + err = probe_codec(s, out_st, pkt1);
> + if (err < 0)
> + return err;
> + } while (1);
> +
> + return 0;
> +}
> +
> int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
> {
> FFFormatContext *const si = ffformatcontext(s);
> @@ -557,9 +660,6 @@ FF_ENABLE_DEPRECATION_WARNINGS
>
> for (;;) {
> PacketListEntry *pktl = si->raw_packet_buffer.head;
> - AVStream *st;
> - FFStream *sti;
> - const AVPacket *pkt1;
>
> if (pktl) {
> AVStream *const st = s->streams[pktl->pkt.stream_index];
> @@ -582,16 +682,27 @@ FF_ENABLE_DEPRECATION_WARNINGS
> We must re-call the demuxer to get the real packet. */
> if (err == FFERROR_REDO)
> continue;
> - if (!pktl || err == AVERROR(EAGAIN))
> + if (err == AVERROR(EAGAIN))
> return err;
> for (unsigned i = 0; i < s->nb_streams; i++) {
> AVStream *const st = s->streams[i];
> FFStream *const sti = ffstream(st);
> + int ret;
> +
> + // Drain buffered packets in the bsf context on eof
> + if (err == AVERROR_EOF)
> + if ((ret = filter_packet(s, st, pkt)) < 0)
> + return ret;
> + pktl = si->raw_packet_buffer.head;
> + if (!pktl)
> + continue;
> if (sti->probe_packets || sti->request_probe > 0)
> - if ((err = probe_codec(s, st, NULL)) < 0)
> - return err;
> + if ((ret = probe_codec(s, st, NULL)) < 0)
> + return ret;
> av_assert0(sti->request_probe <= 0);
> }
> + if (!pktl)
> + return err;
> continue;
> }
>
> @@ -616,42 +727,11 @@ FF_ENABLE_DEPRECATION_WARNINGS
> av_assert0(pkt->stream_index < (unsigned)s->nb_streams &&
> "Invalid stream index.\n");
>
> - st = s->streams[pkt->stream_index];
> - sti = ffstream(st);
> -
> - if (update_wrap_reference(s, st, pkt->stream_index, pkt) && sti->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
> - // correct first time stamps to negative values
> - if (!is_relative(sti->first_dts))
> - sti->first_dts = wrap_timestamp(st, sti->first_dts);
> - if (!is_relative(st->start_time))
> - st->start_time = wrap_timestamp(st, st->start_time);
> - if (!is_relative(sti->cur_dts))
> - sti->cur_dts = wrap_timestamp(st, sti->cur_dts);
> - }
> -
> - pkt->dts = wrap_timestamp(st, pkt->dts);
> - pkt->pts = wrap_timestamp(st, pkt->pts);
> -
> - force_codec_ids(s, st);
> -
> - /* TODO: audio: time filter; video: frame reordering (pts != dts) */
> - if (s->use_wallclock_as_timestamps)
> - pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
> -
> - if (!pktl && sti->request_probe <= 0)
> - return 0;
> -
> - err = avpriv_packet_list_put(&si->raw_packet_buffer,
> - pkt, NULL, 0);
> - if (err < 0) {
> - av_packet_unref(pkt);
> - return err;
> - }
> - pkt1 = &si->raw_packet_buffer.tail->pkt;
> - si->raw_packet_buffer_size += pkt1->size;
> -
> - if ((err = probe_codec(s, st, pkt1)) < 0)
> + err = filter_packet(s, s->streams[pkt->stream_index], pkt);
> + if (err < 0)
> return err;
> + if (!AVPACKET_IS_EMPTY(pkt))
> + return 0;
> }
> }
>
> diff --git a/libavformat/internal.h b/libavformat/internal.h
> index c6181683ef..0a5d512697 100644
> --- a/libavformat/internal.h
> +++ b/libavformat/internal.h
> @@ -212,7 +212,7 @@ typedef struct FFStream {
> /**
> * bitstream filter to run on stream
> * - encoding: Set by muxer using ff_stream_add_bitstream_filter
> - * - decoding: unused
> + * - decoding: Set by demuxer using ff_stream_add_bitstream_filter
> */
> struct AVBSFContext *bsfc;
>
> @@ -757,4 +757,15 @@ int ff_match_url_ext(const char *url, const char *extensions);
> struct FFOutputFormat;
> void avpriv_register_devices(const struct FFOutputFormat * const o[], const AVInputFormat * const i[]);
>
> +/**
> + * Add a bitstream filter to a stream.
> + *
> + * @param st output stream to add a filter to
> + * @param name the name of the filter to add
> + * @param args filter-specific argument string
> + * @return >0 on success;
> + * AVERROR code on failure
> + */
> +int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char *args);
> +
> #endif /* AVFORMAT_INTERNAL_H */
> diff --git a/libavformat/mux.c b/libavformat/mux.c
> index de10d2c008..4bc8627617 100644
> --- a/libavformat/mux.c
> +++ b/libavformat/mux.c
> @@ -1344,49 +1344,6 @@ int av_get_output_timestamp(struct AVFormatContext *s, int stream,
> return 0;
> }
>
> -int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char *args)
> -{
> - int ret;
> - const AVBitStreamFilter *bsf;
> - FFStream *const sti = ffstream(st);
> - AVBSFContext *bsfc;
> -
> - av_assert0(!sti->bsfc);
> -
> - if (!(bsf = av_bsf_get_by_name(name))) {
> - av_log(NULL, AV_LOG_ERROR, "Unknown bitstream filter '%s'\n", name);
> - return AVERROR_BSF_NOT_FOUND;
> - }
> -
> - if ((ret = av_bsf_alloc(bsf, &bsfc)) < 0)
> - return ret;
> -
> - bsfc->time_base_in = st->time_base;
> - if ((ret = avcodec_parameters_copy(bsfc->par_in, st->codecpar)) < 0) {
> - av_bsf_free(&bsfc);
> - return ret;
> - }
> -
> - if (args && bsfc->filter->priv_class) {
> - if ((ret = av_set_options_string(bsfc->priv_data, args, "=", ":")) < 0) {
> - av_bsf_free(&bsfc);
> - return ret;
> - }
> - }
> -
> - if ((ret = av_bsf_init(bsfc)) < 0) {
> - av_bsf_free(&bsfc);
> - return ret;
> - }
> -
> - sti->bsfc = bsfc;
> -
> - av_log(NULL, AV_LOG_VERBOSE,
> - "Automatically inserted bitstream filter '%s'; args='%s'\n",
> - name, args ? args : "");
> - return 1;
> -}
> -
> int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
> AVFormatContext *src, int interleave)
> {
> diff --git a/libavformat/mux.h b/libavformat/mux.h
> index b9ec75641d..ab3e8edd60 100644
> --- a/libavformat/mux.h
> +++ b/libavformat/mux.h
> @@ -171,17 +171,6 @@ const AVPacket *ff_interleaved_peek(AVFormatContext *s, int stream);
>
> int ff_get_muxer_ts_offset(AVFormatContext *s, int stream_index, int64_t *offset);
>
> -/**
> - * Add a bitstream filter to a stream.
> - *
> - * @param st output stream to add a filter to
> - * @param name the name of the filter to add
> - * @param args filter-specific argument string
> - * @return >0 on success;
> - * AVERROR code on failure
> - */
> -int ff_stream_add_bitstream_filter(AVStream *st, const char *name, const char *args);
> -
> /**
> * Write a packet to another muxer than the one the user originally
> * intended. Useful when chaining muxers, where one muxer internally
> diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
> index f916db13a2..ec31d76d88 100644
> --- a/libavformat/rawenc.c
> +++ b/libavformat/rawenc.c
> @@ -25,6 +25,7 @@
> #include "libavutil/intreadwrite.h"
>
> #include "avformat.h"
> +#include "internal.h"
> #include "rawenc.h"
> #include "mux.h"
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2023-11-28 4:00 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-26 1:28 [FFmpeg-devel] [PATCH v5 0/9] avformat: introduce AVStreamGroup James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 1/9] avutil/mem: add av_dynarray2_add_nofree James Almer
2023-11-30 10:39 ` Anton Khirnov
2023-11-30 13:10 ` James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 2/9] avcodec/get_bits: add get_leb() James Almer
2023-11-26 13:40 ` Leo Izen
2023-11-26 13:43 ` James Almer
2023-11-30 10:40 ` Anton Khirnov
2023-11-30 12:49 ` Paul B Mahol
2023-11-30 13:08 ` James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 3/9] avformat/aviobuf: add ffio_read_leb() and ffio_write_leb() James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 4/9] avutil: introduce an Immersive Audio Model and Formats API James Almer
2023-11-30 11:01 ` Anton Khirnov
2023-11-30 13:01 ` James Almer
2023-11-30 13:47 ` Anton Khirnov
2023-11-30 14:27 ` James Almer
2023-11-30 14:30 ` Anton Khirnov
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 5/9] avformat: introduce AVStreamGroup James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 6/9] ffmpeg: add support for muxing AVStreamGroups James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 7/9] avcodec/packet: add IAMF Parameters side data types James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 8/9] avformat: Immersive Audio Model and Formats demuxer James Almer
2023-11-26 1:28 ` [FFmpeg-devel] [PATCH 9/9] avformat: Immersive Audio Model and Formats muxer James Almer
2023-11-27 18:43 ` [FFmpeg-devel] [PATCH 10/13] avcodec: add an Immersive Audio Model and Formats frame split bsf James Almer
2023-11-27 18:43 ` [FFmpeg-devel] [PATCH 11/13] avformat/demux: support inserting bitstream filters in demuxing scenarios James Almer
2023-11-28 4:00 ` Gyan Doshi [this message]
2023-11-29 21:55 ` James Almer
2023-11-30 4:01 ` Gyan Doshi
2023-11-27 18:43 ` [FFmpeg-devel] [PATCH 12/13] avformat/mov: make MOVStreamContext refcounted James Almer
2023-11-27 18:43 ` [FFmpeg-devel] [PATCH 13/13] avformat/mov: add support for Immersive Audio Model and Formats in ISOBMFF James Almer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2eeae382-e529-4cc1-a48b-ee6b6d7ce559@gyani.pro \
--to=ffmpeg@gyani.pro \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git