Browse code

lavf/tee: allow multiple stream specifiers in select.

It makes possible to put multiple stream specifier into the select
option separated by comma.
eg. select=\'a:0,v\'

Signed-off-by: Bela Bodecs <bodecsb@vivanet.hu>
Signed-off-by: Nicolas George <george@nsup.org>

Bela Bodecs authored on 2015/10/11 04:29:12
Showing 2 changed files
... ...
@@ -1272,7 +1272,8 @@ Several bitstream filters can be specified, separated by ",".
1272 1272
 @item select
1273 1273
 Select the streams that should be mapped to the slave output,
1274 1274
 specified by a stream specifier. If not specified, this defaults to
1275
-all the input streams.
1275
+all the input streams. You may use multiple stream specifiers
1276
+separated by commas (@code{,}) e.g.: @code{a:0,v}
1276 1277
 @end table
1277 1278
 
1278 1279
 @subsection Examples
... ...
@@ -47,6 +47,7 @@ static const char *const slave_opt_open  = "[";
47 47
 static const char *const slave_opt_close = "]";
48 48
 static const char *const slave_opt_delim = ":]"; /* must have the close too */
49 49
 static const char *const slave_bsfs_spec_sep = "/";
50
+static const char *const slave_select_sep = ",";
50 51
 
51 52
 static const AVClass tee_muxer_class = {
52 53
     .class_name = "Tee muxer",
... ...
@@ -142,6 +143,8 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
142 142
     AVFormatContext *avf2 = NULL;
143 143
     AVStream *st, *st2;
144 144
     int stream_count;
145
+    int fullret;
146
+    char *subselect = NULL, *next_subselect = NULL, *first_subselect = NULL, *tmp_select = NULL;
145 147
 
146 148
     if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
147 149
         return ret;
... ...
@@ -172,15 +175,32 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
172 172
     for (i = 0; i < avf->nb_streams; i++) {
173 173
         st = avf->streams[i];
174 174
         if (select) {
175
-            ret = avformat_match_stream_specifier(avf, avf->streams[i], select);
176
-            if (ret < 0) {
177
-                av_log(avf, AV_LOG_ERROR,
178
-                       "Invalid stream specifier '%s' for output '%s'\n",
179
-                       select, slave);
175
+            tmp_select = av_strdup(select);  // av_strtok is destructive so we regenerate it in each loop
176
+            if (!tmp_select) {
177
+                ret = AVERROR(ENOMEM);
180 178
                 goto end;
181 179
             }
180
+            fullret = 0;
181
+            first_subselect = tmp_select;
182
+            next_subselect = NULL;
183
+            while (subselect = av_strtok(first_subselect, slave_select_sep, &next_subselect)) {
184
+                first_subselect = NULL;
185
+
186
+                ret = avformat_match_stream_specifier(avf, avf->streams[i], subselect);
187
+                if (ret < 0) {
188
+                    av_log(avf, AV_LOG_ERROR,
189
+                           "Invalid stream specifier '%s' for output '%s'\n",
190
+                           subselect, slave);
191
+                    goto end;
192
+                }
193
+                if (ret != 0) {
194
+                    fullret = 1; // match
195
+                    break;
196
+                }
197
+            }
198
+            av_freep(&tmp_select);
182 199
 
183
-            if (ret == 0) { /* no match */
200
+            if (fullret == 0) { /* no match */
184 201
                 tee_slave->stream_map[i] = -1;
185 202
                 continue;
186 203
             }
... ...
@@ -282,6 +302,7 @@ end:
282 282
     av_free(format);
283 283
     av_free(select);
284 284
     av_dict_free(&options);
285
+    av_freep(&tmp_select);
285 286
     return ret;
286 287
 }
287 288