]> git.sesse.net Git - ffmpeg/blob - libavformat/tee.c
Merge commit 'b13fc1e344011949929975a3451f78f226aa1de3'
[ffmpeg] / libavformat / tee.c
1 /*
2  * Tee pseudo-muxer
3  * Copyright (c) 2012 Nicolas George
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22
23 #include "libavutil/avutil.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/opt.h"
26 #include "internal.h"
27 #include "avformat.h"
28 #include "avio_internal.h"
29 #include "tee_common.h"
30
31 typedef enum {
32     ON_SLAVE_FAILURE_ABORT  = 1,
33     ON_SLAVE_FAILURE_IGNORE = 2
34 } SlaveFailurePolicy;
35
36 #define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
37
38 typedef struct {
39     AVFormatContext *avf;
40     AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
41
42     SlaveFailurePolicy on_fail;
43
44     /** map from input to output streams indexes,
45      * disabled output streams are set to -1 */
46     int *stream_map;
47     int header_written;
48 } TeeSlave;
49
50 typedef struct TeeContext {
51     const AVClass *class;
52     unsigned nb_slaves;
53     unsigned nb_alive;
54     TeeSlave *slaves;
55 } TeeContext;
56
57 static const char *const slave_delim     = "|";
58 static const char *const slave_bsfs_spec_sep = "/";
59 static const char *const slave_select_sep = ",";
60
61 static const AVClass tee_muxer_class = {
62     .class_name = "Tee muxer",
63     .item_name  = av_default_item_name,
64     .version    = LIBAVUTIL_VERSION_INT,
65 };
66
67 /**
68  * Parse list of bitstream filters and add them to the list of filters
69  * pointed to by bsfs.
70  *
71  * The list must be specified in the form:
72  * BSFS ::= BSF[,BSFS]
73  */
74 static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
75                       AVBitStreamFilterContext **bsfs)
76 {
77     char *bsf_name, *buf, *dup, *saveptr;
78     int ret = 0;
79
80     if (!(dup = buf = av_strdup(bsfs_spec)))
81         return AVERROR(ENOMEM);
82
83     while (bsf_name = av_strtok(buf, ",", &saveptr)) {
84         AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
85
86         if (!bsf) {
87             av_log(log_ctx, AV_LOG_ERROR,
88                    "Cannot initialize bitstream filter with name '%s', "
89                    "unknown filter or internal error happened\n",
90                    bsf_name);
91             ret = AVERROR_UNKNOWN;
92             goto end;
93         }
94
95         /* append bsf context to the list of bsf contexts */
96         *bsfs = bsf;
97         bsfs = &bsf->next;
98
99         buf = NULL;
100     }
101
102 end:
103     av_free(dup);
104     return ret;
105 }
106
107 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave)
108 {
109     if (!opt) {
110         tee_slave->on_fail = DEFAULT_SLAVE_FAILURE_POLICY;
111         return 0;
112     } else if (!av_strcasecmp("abort", opt)) {
113         tee_slave->on_fail = ON_SLAVE_FAILURE_ABORT;
114         return 0;
115     } else if (!av_strcasecmp("ignore", opt)) {
116         tee_slave->on_fail = ON_SLAVE_FAILURE_IGNORE;
117         return 0;
118     }
119     /* Set failure behaviour to abort, so invalid option error will not be ignored */
120     tee_slave->on_fail = ON_SLAVE_FAILURE_ABORT;
121     return AVERROR(EINVAL);
122 }
123
124 static int close_slave(TeeSlave *tee_slave)
125 {
126     AVFormatContext *avf;
127     unsigned i;
128     int ret = 0;
129
130     avf = tee_slave->avf;
131     if (!avf)
132         return 0;
133
134     if (tee_slave->header_written)
135         ret = av_write_trailer(avf);
136
137     if (tee_slave->bsfs) {
138         for (i = 0; i < avf->nb_streams; ++i) {
139             AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];
140             while (bsf) {
141                 bsf_next = bsf->next;
142                 av_bitstream_filter_close(bsf);
143                 bsf = bsf_next;
144             }
145         }
146     }
147     av_freep(&tee_slave->stream_map);
148     av_freep(&tee_slave->bsfs);
149
150     ff_format_io_close(avf, &avf->pb);
151     avformat_free_context(avf);
152     tee_slave->avf = NULL;
153     return ret;
154 }
155
156 static void close_slaves(AVFormatContext *avf)
157 {
158     TeeContext *tee = avf->priv_data;
159     unsigned i;
160
161     for (i = 0; i < tee->nb_slaves; i++) {
162         close_slave(&tee->slaves[i]);
163     }
164     av_freep(&tee->slaves);
165 }
166
167 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
168 {
169     int i, ret;
170     AVDictionary *options = NULL;
171     AVDictionaryEntry *entry;
172     char *filename;
173     char *format = NULL, *select = NULL, *on_fail = NULL;
174     AVFormatContext *avf2 = NULL;
175     AVStream *st, *st2;
176     int stream_count;
177     int fullret;
178     char *subselect = NULL, *next_subselect = NULL, *first_subselect = NULL, *tmp_select = NULL;
179
180     if ((ret = ff_tee_parse_slave_options(avf, slave, &options, &filename)) < 0)
181         return ret;
182
183 #define STEAL_OPTION(option, field) do {                                \
184         if ((entry = av_dict_get(options, option, NULL, 0))) {          \
185             field = entry->value;                                       \
186             entry->value = NULL; /* prevent it from being freed */      \
187             av_dict_set(&options, option, NULL, 0);                     \
188         }                                                               \
189     } while (0)
190
191     STEAL_OPTION("f", format);
192     STEAL_OPTION("select", select);
193     STEAL_OPTION("onfail", on_fail);
194
195     ret = parse_slave_failure_policy_option(on_fail, tee_slave);
196     if (ret < 0) {
197         av_log(avf, AV_LOG_ERROR,
198                "Invalid onfail option value, valid options are 'abort' and 'ignore'\n");
199         goto end;
200     }
201
202     ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
203     if (ret < 0)
204         goto end;
205     tee_slave->avf = avf2;
206     av_dict_copy(&avf2->metadata, avf->metadata, 0);
207     avf2->opaque   = avf->opaque;
208     avf2->io_open  = avf->io_open;
209     avf2->io_close = avf->io_close;
210
211     tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
212     if (!tee_slave->stream_map) {
213         ret = AVERROR(ENOMEM);
214         goto end;
215     }
216
217     stream_count = 0;
218     for (i = 0; i < avf->nb_streams; i++) {
219         st = avf->streams[i];
220         if (select) {
221             tmp_select = av_strdup(select);  // av_strtok is destructive so we regenerate it in each loop
222             if (!tmp_select) {
223                 ret = AVERROR(ENOMEM);
224                 goto end;
225             }
226             fullret = 0;
227             first_subselect = tmp_select;
228             next_subselect = NULL;
229             while (subselect = av_strtok(first_subselect, slave_select_sep, &next_subselect)) {
230                 first_subselect = NULL;
231
232                 ret = avformat_match_stream_specifier(avf, avf->streams[i], subselect);
233                 if (ret < 0) {
234                     av_log(avf, AV_LOG_ERROR,
235                            "Invalid stream specifier '%s' for output '%s'\n",
236                            subselect, slave);
237                     goto end;
238                 }
239                 if (ret != 0) {
240                     fullret = 1; // match
241                     break;
242                 }
243             }
244             av_freep(&tmp_select);
245
246             if (fullret == 0) { /* no match */
247                 tee_slave->stream_map[i] = -1;
248                 continue;
249             }
250         }
251         tee_slave->stream_map[i] = stream_count++;
252
253         if (!(st2 = avformat_new_stream(avf2, NULL))) {
254             ret = AVERROR(ENOMEM);
255             goto end;
256         }
257
258         ret = ff_stream_encode_params_copy(st2, st);
259         if (ret < 0)
260             goto end;
261     }
262
263     ret = ff_format_output_open(avf2, filename, NULL);
264     if (ret < 0) {
265         av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave,
266                av_err2str(ret));
267         goto end;
268     }
269
270     if ((ret = avformat_write_header(avf2, &options)) < 0) {
271         av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
272                slave, av_err2str(ret));
273         goto end;
274     }
275     tee_slave->header_written = 1;
276
277     tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(*tee_slave->bsfs));
278     if (!tee_slave->bsfs) {
279         ret = AVERROR(ENOMEM);
280         goto end;
281     }
282
283     entry = NULL;
284     while (entry = av_dict_get(options, "bsfs", NULL, AV_DICT_IGNORE_SUFFIX)) {
285         const char *spec = entry->key + strlen("bsfs");
286         if (*spec) {
287             if (strspn(spec, slave_bsfs_spec_sep) != 1) {
288                 av_log(avf, AV_LOG_ERROR,
289                        "Specifier separator in '%s' is '%c', but only characters '%s' "
290                        "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep);
291                 ret = AVERROR(EINVAL);
292                 goto end;
293             }
294             spec++; /* consume separator */
295         }
296
297         for (i = 0; i < avf2->nb_streams; i++) {
298             ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec);
299             if (ret < 0) {
300                 av_log(avf, AV_LOG_ERROR,
301                        "Invalid stream specifier '%s' in bsfs option '%s' for slave "
302                        "output '%s'\n", spec, entry->key, filename);
303                 goto end;
304             }
305
306             if (ret > 0) {
307                 av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave "
308                        "output '%s'\n", spec, entry->value, i, filename);
309                 if (tee_slave->bsfs[i]) {
310                     av_log(avf, AV_LOG_WARNING,
311                            "Duplicate bsfs specification associated to stream %d of slave "
312                            "output '%s', filters will be ignored\n", i, filename);
313                     continue;
314                 }
315                 ret = parse_bsfs(avf, entry->value, &tee_slave->bsfs[i]);
316                 if (ret < 0) {
317                     av_log(avf, AV_LOG_ERROR,
318                            "Error parsing bitstream filter sequence '%s' associated to "
319                            "stream %d of slave output '%s'\n", entry->value, i, filename);
320                     goto end;
321                 }
322             }
323         }
324
325         av_dict_set(&options, entry->key, NULL, 0);
326     }
327
328     if (options) {
329         entry = NULL;
330         while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX)))
331             av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
332         ret = AVERROR_OPTION_NOT_FOUND;
333         goto end;
334     }
335
336 end:
337     av_free(format);
338     av_free(select);
339     av_free(on_fail);
340     av_dict_free(&options);
341     av_freep(&tmp_select);
342     return ret;
343 }
344
345 static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
346 {
347     int i;
348     av_log(log_ctx, log_level, "filename:'%s' format:%s\n",
349            slave->avf->filename, slave->avf->oformat->name);
350     for (i = 0; i < slave->avf->nb_streams; i++) {
351         AVStream *st = slave->avf->streams[i];
352         AVBitStreamFilterContext *bsf = slave->bsfs[i];
353
354         av_log(log_ctx, log_level, "    stream:%d codec:%s type:%s",
355                i, avcodec_get_name(st->codecpar->codec_id),
356                av_get_media_type_string(st->codecpar->codec_type));
357         if (bsf) {
358             av_log(log_ctx, log_level, " bsfs:");
359             while (bsf) {
360                 av_log(log_ctx, log_level, "%s%s",
361                        bsf->filter->name, bsf->next ? "," : "");
362                 bsf = bsf->next;
363             }
364         }
365         av_log(log_ctx, log_level, "\n");
366     }
367 }
368
369 static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
370 {
371     TeeContext *tee = avf->priv_data;
372     TeeSlave *tee_slave = &tee->slaves[slave_idx];
373
374     tee->nb_alive--;
375
376     close_slave(tee_slave);
377
378     if (!tee->nb_alive) {
379         av_log(avf, AV_LOG_ERROR, "All tee outputs failed.\n");
380         return err_n;
381     } else if (tee_slave->on_fail == ON_SLAVE_FAILURE_ABORT) {
382         av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed, aborting.\n", slave_idx);
383         return err_n;
384     } else {
385         av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed: %s, continuing with %u/%u slaves.\n",
386                slave_idx, av_err2str(err_n), tee->nb_alive, tee->nb_slaves);
387         return 0;
388     }
389 }
390
391 static int tee_write_header(AVFormatContext *avf)
392 {
393     TeeContext *tee = avf->priv_data;
394     unsigned nb_slaves = 0, i;
395     const char *filename = avf->filename;
396     char **slaves = NULL;
397     int ret;
398
399     while (*filename) {
400         char *slave = av_get_token(&filename, slave_delim);
401         if (!slave) {
402             ret = AVERROR(ENOMEM);
403             goto fail;
404         }
405         ret = av_dynarray_add_nofree(&slaves, &nb_slaves, slave);
406         if (ret < 0) {
407             av_free(slave);
408             goto fail;
409         }
410         if (strspn(filename, slave_delim))
411             filename++;
412     }
413
414     if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves)))) {
415         ret = AVERROR(ENOMEM);
416         goto fail;
417     }
418     tee->nb_slaves = tee->nb_alive = nb_slaves;
419
420     for (i = 0; i < nb_slaves; i++) {
421         if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) {
422             ret = tee_process_slave_failure(avf, i, ret);
423             if (ret < 0)
424                 goto fail;
425         } else {
426             log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE);
427         }
428         av_freep(&slaves[i]);
429     }
430
431     for (i = 0; i < avf->nb_streams; i++) {
432         int j, mapped = 0;
433         for (j = 0; j < tee->nb_slaves; j++)
434             if (tee->slaves[j].avf)
435                 mapped += tee->slaves[j].stream_map[i] >= 0;
436         if (!mapped)
437             av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
438                    "to any slave.\n", i);
439     }
440     av_free(slaves);
441     return 0;
442
443 fail:
444     for (i = 0; i < nb_slaves; i++)
445         av_freep(&slaves[i]);
446     close_slaves(avf);
447     av_free(slaves);
448     return ret;
449 }
450
451 static int tee_write_trailer(AVFormatContext *avf)
452 {
453     TeeContext *tee = avf->priv_data;
454     int ret_all = 0, ret;
455     unsigned i;
456
457     for (i = 0; i < tee->nb_slaves; i++) {
458         if ((ret = close_slave(&tee->slaves[i])) < 0) {
459             ret = tee_process_slave_failure(avf, i, ret);
460             if (!ret_all && ret < 0)
461                 ret_all = ret;
462         }
463     }
464     av_freep(&tee->slaves);
465     return ret_all;
466 }
467
468 static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
469 {
470     TeeContext *tee = avf->priv_data;
471     AVFormatContext *avf2;
472     AVPacket pkt2;
473     int ret_all = 0, ret;
474     unsigned i, s;
475     int s2;
476     AVRational tb, tb2;
477
478     for (i = 0; i < tee->nb_slaves; i++) {
479         if (!(avf2 = tee->slaves[i].avf))
480             continue;
481
482         /* Flush slave if pkt is NULL*/
483         if (!pkt) {
484             ret = av_interleaved_write_frame(avf2, NULL);
485             if (ret < 0) {
486                 ret = tee_process_slave_failure(avf, i, ret);
487                 if (!ret_all && ret < 0)
488                     ret_all = ret;
489             }
490             continue;
491         }
492
493         s = pkt->stream_index;
494         s2 = tee->slaves[i].stream_map[s];
495         if (s2 < 0)
496             continue;
497
498         memset(&pkt2, 0, sizeof(AVPacket));
499         if ((ret = av_packet_ref(&pkt2, pkt)) < 0)
500             if (!ret_all) {
501                 ret_all = ret;
502                 continue;
503             }
504         tb  = avf ->streams[s ]->time_base;
505         tb2 = avf2->streams[s2]->time_base;
506         av_packet_rescale_ts(&pkt2, tb, tb2);
507         pkt2.stream_index = s2;
508
509         if ((ret = av_apply_bitstream_filters(avf2->streams[s2]->codec, &pkt2,
510                                               tee->slaves[i].bsfs[s2])) < 0 ||
511             (ret = av_interleaved_write_frame(avf2, &pkt2)) < 0) {
512             ret = tee_process_slave_failure(avf, i, ret);
513             if (!ret_all && ret < 0)
514                 ret_all = ret;
515         }
516     }
517     return ret_all;
518 }
519
520 AVOutputFormat ff_tee_muxer = {
521     .name              = "tee",
522     .long_name         = NULL_IF_CONFIG_SMALL("Multiple muxer tee"),
523     .priv_data_size    = sizeof(TeeContext),
524     .write_header      = tee_write_header,
525     .write_trailer     = tee_write_trailer,
526     .write_packet      = tee_write_packet,
527     .priv_class        = &tee_muxer_class,
528     .flags             = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
529 };