Browse code

lavf/tee: add special select option

Stefano Sabatini authored on 2013/08/08 19:11:59
Showing 3 changed files
... ...
@@ -871,6 +871,11 @@ separated by @code{/}. If the stream specifier is not specified, the
871 871
 bistream filters will be applied to all streams in the output.
872 872
 
873 873
 Several bitstream filters can be specified, separated by ",".
874
+
875
+@item select
876
+Select the streams that should be mapped to the slave output,
877
+specified by a stream specifier. If not specified, this defaults to
878
+all the input streams.
874 879
 @end table
875 880
 
876 881
 Example: encode something and both archive it in a WebM file and stream it
... ...
@@ -30,6 +30,10 @@
30 30
 typedef struct {
31 31
     AVFormatContext *avf;
32 32
     AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
33
+
34
+    /** map from input to output streams indexes,
35
+     * disabled output streams are set to -1 */
36
+    int *stream_map;
33 37
 } TeeSlave;
34 38
 
35 39
 typedef struct TeeContext {
... ...
@@ -134,24 +138,54 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
134 134
     AVDictionary *options = NULL;
135 135
     AVDictionaryEntry *entry;
136 136
     char *filename;
137
-    char *format = NULL;
137
+    char *format = NULL, *select = NULL;
138 138
     AVFormatContext *avf2 = NULL;
139 139
     AVStream *st, *st2;
140
+    int stream_count;
140 141
 
141 142
     if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
142 143
         return ret;
143
-    if ((entry = av_dict_get(options, "f", NULL, 0))) {
144
-        format = entry->value;
145
-        entry->value = NULL; /* prevent it from being freed */
146
-        av_dict_set(&options, "f", NULL, 0);
147
-    }
144
+
145
+#define STEAL_OPTION(option, field) do {                                \
146
+        if ((entry = av_dict_get(options, option, NULL, 0))) {          \
147
+            field = entry->value;                                       \
148
+            entry->value = NULL; /* prevent it from being freed */      \
149
+            av_dict_set(&options, option, NULL, 0);                     \
150
+        }                                                               \
151
+    } while (0)
152
+
153
+    STEAL_OPTION("f", format);
154
+    STEAL_OPTION("select", select);
148 155
 
149 156
     ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
150 157
     if (ret < 0)
151 158
         goto end;
152 159
 
160
+    tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
161
+    if (!tee_slave->stream_map) {
162
+        ret = AVERROR(ENOMEM);
163
+        goto end;
164
+    }
165
+
166
+    stream_count = 0;
153 167
     for (i = 0; i < avf->nb_streams; i++) {
154 168
         st = avf->streams[i];
169
+        if (select) {
170
+            ret = avformat_match_stream_specifier(avf, avf->streams[i], select);
171
+            if (ret < 0) {
172
+                av_log(avf, AV_LOG_ERROR,
173
+                       "Invalid stream specifier '%s' for output '%s'\n",
174
+                       select, slave);
175
+                goto end;
176
+            }
177
+
178
+            if (ret == 0) { /* no match */
179
+                tee_slave->stream_map[i] = -1;
180
+                continue;
181
+            }
182
+        }
183
+        tee_slave->stream_map[i] = stream_count++;
184
+
155 185
         if (!(st2 = avformat_new_stream(avf2, NULL))) {
156 186
             ret = AVERROR(ENOMEM);
157 187
             goto end;
... ...
@@ -266,6 +300,7 @@ static void close_slaves(AVFormatContext *avf)
266 266
                 bsf = bsf_next;
267 267
             }
268 268
         }
269
+        av_freep(&tee->slaves[i].stream_map);
269 270
 
270 271
         avio_close(avf2->pb);
271 272
         avf2->pb = NULL;
... ...
@@ -329,6 +364,15 @@ static int tee_write_header(AVFormatContext *avf)
329 329
     }
330 330
 
331 331
     tee->nb_slaves = nb_slaves;
332
+
333
+    for (i = 0; i < avf->nb_streams; i++) {
334
+        int j, mapped = 0;
335
+        for (j = 0; j < tee->nb_slaves; j++)
336
+            mapped += tee->slaves[j].stream_map[i] >= 0;
337
+        if (!mapped)
338
+            av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
339
+                   "to any slave.\n", i);
340
+    }
332 341
     return 0;
333 342
 
334 343
 fail:
... ...
@@ -408,29 +452,30 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
408 408
     AVPacket pkt2;
409 409
     int ret_all = 0, ret;
410 410
     unsigned i, s;
411
+    int s2;
411 412
     AVRational tb, tb2;
412 413
 
413 414
     for (i = 0; i < tee->nb_slaves; i++) {
414 415
         avf2 = tee->slaves[i].avf;
415 416
         s = pkt->stream_index;
416
-        if (s >= avf2->nb_streams) {
417
-            if (!ret_all)
418
-                ret_all = AVERROR(EINVAL);
417
+        s2 = tee->slaves[i].stream_map[s];
418
+        if (s2 < 0)
419 419
             continue;
420
-        }
420
+
421 421
         if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
422 422
             (ret = av_dup_packet(&pkt2))< 0)
423 423
             if (!ret_all) {
424 424
                 ret = ret_all;
425 425
                 continue;
426 426
             }
427
-        tb  = avf ->streams[s]->time_base;
428
-        tb2 = avf2->streams[s]->time_base;
427
+        tb  = avf ->streams[s ]->time_base;
428
+        tb2 = avf2->streams[s2]->time_base;
429 429
         pkt2.pts      = av_rescale_q(pkt->pts,      tb, tb2);
430 430
         pkt2.dts      = av_rescale_q(pkt->dts,      tb, tb2);
431 431
         pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
432
+        pkt2.stream_index = s2;
432 433
 
433
-        filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsfs[s]);
434
+        filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsfs[s2]);
434 435
         if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0)
435 436
             if (!ret_all)
436 437
                 ret_all = ret;
... ...
@@ -31,7 +31,7 @@
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 55
33 33
 #define LIBAVFORMAT_VERSION_MINOR 14
34
-#define LIBAVFORMAT_VERSION_MICRO 100
34
+#define LIBAVFORMAT_VERSION_MICRO 101
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
37 37
                                                LIBAVFORMAT_VERSION_MINOR, \