aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Sabatini <stefasab@gmail.com>2013-08-08 12:11:59 +0200
committerStefano Sabatini <stefasab@gmail.com>2013-08-21 17:44:35 +0200
commit5ae3563359cd8319311eaff3c78ce67c295916d0 (patch)
tree07255dd549cab11679dd1a3eb57bcb706017d108
parente6876c7b7b5524fcb6acadf711cda592687402f7 (diff)
downloadffmpeg-5ae3563359cd8319311eaff3c78ce67c295916d0.tar.gz
lavf/tee: add special select option
-rw-r--r--doc/muxers.texi5
-rw-r--r--libavformat/tee.c71
-rw-r--r--libavformat/version.h2
3 files changed, 64 insertions, 14 deletions
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 52da73e955..c9c4416bc1 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -871,6 +871,11 @@ separated by @code{/}. If the stream specifier is not specified, the
bistream filters will be applied to all streams in the output.
Several bitstream filters can be specified, separated by ",".
+
+@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.
@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 f7a8f41cdc..111966cf3b 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -30,6 +30,10 @@
typedef struct {
AVFormatContext *avf;
AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+
+ /** map from input to output streams indexes,
+ * disabled output streams are set to -1 */
+ int *stream_map;
} TeeSlave;
typedef struct TeeContext {
@@ -134,24 +138,54 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
AVDictionary *options = NULL;
AVDictionaryEntry *entry;
char *filename;
- char *format = NULL;
+ char *format = NULL, *select = NULL;
AVFormatContext *avf2 = NULL;
AVStream *st, *st2;
+ int stream_count;
if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
return ret;
- if ((entry = av_dict_get(options, "f", NULL, 0))) {
- format = entry->value;
- entry->value = NULL; /* prevent it from being freed */
- av_dict_set(&options, "f", NULL, 0);
- }
+
+#define STEAL_OPTION(option, field) do { \
+ if ((entry = av_dict_get(options, option, NULL, 0))) { \
+ field = entry->value; \
+ entry->value = NULL; /* prevent it from being freed */ \
+ av_dict_set(&options, option, NULL, 0); \
+ } \
+ } while (0)
+
+ STEAL_OPTION("f", format);
+ STEAL_OPTION("select", select);
ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
if (ret < 0)
goto end;
+ tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
+ if (!tee_slave->stream_map) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ stream_count = 0;
for (i = 0; i < avf->nb_streams; i++) {
st = avf->streams[i];
+ if (select) {
+ 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 end;
+ }
+
+ 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 end;
@@ -266,6 +300,7 @@ static void close_slaves(AVFormatContext *avf)
bsf = bsf_next;
}
}
+ av_freep(&tee->slaves[i].stream_map);
avio_close(avf2->pb);
avf2->pb = NULL;
@@ -329,6 +364,15 @@ static int tee_write_header(AVFormatContext *avf)
}
tee->nb_slaves = nb_slaves;
+
+ for (i = 0; i < avf->nb_streams; i++) {
+ int j, mapped = 0;
+ for (j = 0; j < tee->nb_slaves; j++)
+ mapped += tee->slaves[j].stream_map[i] >= 0;
+ if (!mapped)
+ av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
+ "to any slave.\n", i);
+ }
return 0;
fail:
@@ -408,29 +452,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].avf;
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].bsfs[s]);
+ filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsfs[s2]);
if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0)
if (!ret_all)
ret_all = ret;
diff --git a/libavformat/version.h b/libavformat/version.h
index 112401a96b..956e6d6d94 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -31,7 +31,7 @@
#define LIBAVFORMAT_VERSION_MAJOR 55
#define LIBAVFORMAT_VERSION_MINOR 14
-#define LIBAVFORMAT_VERSION_MICRO 100
+#define LIBAVFORMAT_VERSION_MICRO 101
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \