[FFmpeg-devel] [RFC] lavf/tee per-output stream selection
Nicolas George
nicolas.george at normalesup.org
Sun Aug 4 12:07:14 CEST 2013
Le sextidi 16 thermidor, an CCXXI, Stefano Sabatini a écrit :
> >From 7b08890d825abc7df66bd49e8cbb1f4ae5c888b1 Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Sat, 3 Aug 2013 11:23:59 +0200
> Subject: [PATCH] lavf/tee: add special select option
>
> TODO: bump micro
> ---
> doc/muxers.texi | 5 +++++
> libavformat/tee.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
> 2 files changed, 45 insertions(+), 8 deletions(-)
>
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index 7c5a1c8..37a1734 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -844,6 +844,11 @@ The BNF description of the bitstream filters specification is given by:
> @var{BSF} ::= @var{BSF_NAME}[+ at var{STREAM_SPECIFIER}]
> @var{BSFS} ::= @var{BSF}[, at var{BSFS}]
> @end example
> +
> + at item select
> +Select the streams that should be mapped to the slave output,
> +specified by a stream specifier. If not specified, this defaults to
> +all the input streams.
Examples may be welcome. Is it possible to have several stream specifiers,
i.e. map "video + English audio + French audio" to "video + English audio"
and "video + French audio"?
> @end table
>
> Example: encode something and both archive it in a WebM file and stream it
> diff --git a/libavformat/tee.c b/libavformat/tee.c
> index 90947c7..4604ab4 100644
> --- a/libavformat/tee.c
> +++ b/libavformat/tee.c
> @@ -30,6 +30,7 @@
> typedef struct {
> AVFormatContext *fmt_ctx;
> AVBitStreamFilterContext **bsf_ctxs; ///< bitstream filters per stream
> + int *stream_map; ///< map between input and output streams, disabled streams are set to -1
Nit: please try to keep lines below 80 chars.
Also, the comment is unclear about the direction of the map, it could be
either:
stream_num_in_slave = stream_map[stream_num_in_global]
stream_num_in_global = stream_map[stream_num_in_slave]
> } TeeSlave;
>
> typedef struct TeeContext {
> @@ -179,9 +180,10 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
> AVDictionary *options = NULL;
> AVDictionaryEntry *entry;
> char *filename;
> - char *format = NULL, *bsfs = NULL;
> + char *format = NULL, *bsfs = NULL, *select = NULL;
> AVFormatContext *avf2 = NULL;
> AVStream *st, *st2;
> + int stream_count;
>
> if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
> return ret;
> @@ -195,14 +197,42 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
> entry->value = NULL; /* prevent it from being freed */
> av_dict_set(&options, "bsfs", NULL, 0);
> }
> + if ((entry = av_dict_get(options, "select", NULL, 0))) {
> + select = entry->value;
> + entry->value = NULL; /* prevent it from being freed */
> + av_dict_set(&options, "select", NULL, 0);
> + }
This hunk really needs factoring.
>
> ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
> if (ret < 0)
> goto fail;
> av_free(format);
>
> + tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(int));
sizeof(*tee_slave->stream_map)
> + if (!tee_slave->stream_map) {
> + ret = AVERROR(ENOMEM);
> + goto fail;
> + }
> +
> + stream_count = 0;
> for (i = 0; i < avf->nb_streams; i++) {
> st = avf->streams[i];
> + if (select && select[0]) {
Why select[0]?
> + ret = avformat_match_stream_specifier(avf, avf->streams[i], select);
> + if (ret < 0) {
> + av_log(avf, AV_LOG_ERROR,
> + "Invalid stream specifier '%s' for output '%s'\n",
> + select, slave);
> + goto fail;
> + }
> +
> + if (ret == 0) { /* no match */
> + tee_slave->stream_map[i] = -1;
> + continue;
> + }
> + }
> + tee_slave->stream_map[i] = stream_count++;
> +
> if (!(st2 = avformat_new_stream(avf2, NULL))) {
> ret = AVERROR(ENOMEM);
> goto fail;
> @@ -277,6 +307,7 @@ static void close_slaves(AVFormatContext *avf)
> av_bitstream_filter_close(bsf_ctx);
> }
> }
> + av_freep(&tee->slaves[i].stream_map);
>
> avio_close(avf2->pb);
> avf2->pb = NULL;
> @@ -419,29 +450,30 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
> AVPacket pkt2;
> int ret_all = 0, ret;
> unsigned i, s;
> + int s2;
> AVRational tb, tb2;
>
> for (i = 0; i < tee->nb_slaves; i++) {
> avf2 = tee->slaves[i].fmt_ctx;
> s = pkt->stream_index;
> - if (s >= avf2->nb_streams) {
> - if (!ret_all)
> - ret_all = AVERROR(EINVAL);
> + s2 = tee->slaves[i].stream_map[s];
> + if (s2 < 0)
> continue;
> - }
> +
> if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
> (ret = av_dup_packet(&pkt2))< 0)
> if (!ret_all) {
> ret = ret_all;
> continue;
> }
> - tb = avf ->streams[s]->time_base;
> - tb2 = avf2->streams[s]->time_base;
> + tb = avf ->streams[s ]->time_base;
> + tb2 = avf2->streams[s2]->time_base;
> pkt2.pts = av_rescale_q(pkt->pts, tb, tb2);
> pkt2.dts = av_rescale_q(pkt->dts, tb, tb2);
> pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
> + pkt2.stream_index = s2;
>
> - filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsf_ctxs[s]);
> + filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsf_ctxs[s2]);
> if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0)
> if (!ret_all)
> ret_all = ret;
> >From 371a649c329f57b023fdfe6d9eedbd46b2d7991c Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Sat, 3 Aug 2013 14:05:13 +0200
> Subject: [PATCH] doc/muxers: add elaborate example for the tee muxer
>
> ---
> doc/muxers.texi | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index 37a1734..beceeab 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -859,6 +859,16 @@ ffmpeg -i ... -c:v libx264 -c:a mp2 -f tee -map 0:v -map 0:a
> "archive-20121107.mkv|[f=mpegts]udp://10.0.1.255:1234/"
> @end example
>
> +Example: use @command{ffmpeg} to encode the input, and send the output
> +to three different destinations. The @code{dump_extra} bitstream
> +filter is used to add extradata information to all the video keyframes
> +in output, as requested by the MPEG-TS format. The @filename{out.aac}
> +output is filtered in order to contain only audio packets.
> + at example
> +ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac -strict experimental
> + -f tee "[bsfs=dump_extra+v]out.ts|[movflags=+faststart]out.mp4|[select=a]out.aac"
> + at end example
> +
> Note: some codecs may need different options depending on the output format;
> the auto-detection of this can not work with the tee muxer. The main example
> is the @option{global_header} flag.
This one seems ok.
Regards,
--
Nicolas George
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20130804/28426b66/attachment.asc>
More information about the ffmpeg-devel
mailing list