FFmpeg
Loading...
Searching...
No Matches
tee.c
Go to the documentation of this file.
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/mem.h"
26#include "libavutil/opt.h"
27#include "libavcodec/bsf.h"
28#include "internal.h"
29#include "avformat.h"
30#include "mux.h"
31#include "tee_common.h"
32
37
38#define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
39
40typedef struct {
42 AVBSFContext **bsfs; ///< bitstream filters per stream
43
47
48 /** map from input to output streams indexes,
49 * disabled output streams are set to -1 */
52} TeeSlave;
53
54typedef struct TeeContext {
55 const AVClass *class;
56 unsigned nb_slaves;
57 unsigned nb_alive;
62
63static const char *const slave_delim = "|";
64static const char *const slave_bsfs_spec_sep = "/";
65static const char *const slave_select_sep = ",";
66
67#define OFFSET(x) offsetof(TeeContext, x)
68static const AVOption tee_options[] = {
69 {"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from encoder",
70 OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
71 {"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options),
73 {NULL}
74};
75
76static const AVClass tee_muxer_class = {
77 .class_name = "Tee muxer",
78 .item_name = av_default_item_name,
79 .option = tee_options,
80 .version = LIBAVUTIL_VERSION_INT,
81};
82
83static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave)
84{
85 if (!opt) {
87 return 0;
88 } else if (!av_strcasecmp("abort", opt)) {
90 return 0;
91 } else if (!av_strcasecmp("ignore", opt)) {
93 return 0;
94 }
95 /* Set failure behaviour to abort, so invalid option error will not be ignored */
97 return AVERROR(EINVAL);
98}
99
100static int parse_slave_fifo_policy(const char *use_fifo, TeeSlave *tee_slave)
101{
102 /*TODO - change this to use proper function for parsing boolean
103 * options when there is one */
104 if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) {
105 tee_slave->use_fifo = 1;
106 } else if (av_match_name(use_fifo, "false,n,no,disable,disabled,off,0")) {
107 tee_slave->use_fifo = 0;
108 } else {
109 return AVERROR(EINVAL);
110 }
111 return 0;
112}
113
114static int parse_slave_fifo_options(const char *fifo_options, TeeSlave *tee_slave)
115{
116 return av_dict_parse_string(&tee_slave->fifo_options, fifo_options, "=", ":", 0);
117}
118
119static int close_slave(TeeSlave *tee_slave)
120{
121 AVFormatContext *avf;
122 int ret = 0;
123
124 av_dict_free(&tee_slave->fifo_options);
125 avf = tee_slave->avf;
126 if (!avf)
127 return 0;
128
129 if (tee_slave->header_written)
130 ret = av_write_trailer(avf);
131
132 if (tee_slave->bsfs) {
133 for (unsigned i = 0; i < avf->nb_streams; ++i)
134 av_bsf_free(&tee_slave->bsfs[i]);
135 }
136 av_freep(&tee_slave->stream_map);
137 av_freep(&tee_slave->bsfs);
138
139 ff_format_io_close(avf, &avf->pb);
141 tee_slave->avf = NULL;
142 return ret;
143}
144
146{
147 TeeContext *tee = avf->priv_data;
148
149 for (unsigned i = 0; i < tee->nb_slaves; i++) {
150 close_slave(&tee->slaves[i]);
151 }
152 av_freep(&tee->slaves);
153}
154
155static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
156{
157 int ret;
158 AVDictionary *options = NULL, *bsf_options = NULL;
160 char *filename;
161 char *format = NULL, *select = NULL;
162 AVFormatContext *avf2 = NULL;
163 int stream_count;
164 int fullret;
165 char *subselect = NULL, *next_subselect = NULL, *first_subselect = NULL, *tmp_select = NULL;
166
167 if ((ret = ff_tee_parse_slave_options(avf, slave, &options, &filename)) < 0)
168 return ret;
169
171
172#define CONSUME_OPTION(option, field, action) do { \
173 AVDictionaryEntry *en = av_dict_get(options, option, NULL, 0); \
174 if (en) { \
175 field = en->value; \
176 { action } \
177 av_dict_set(&options, option, NULL, 0); \
178 } \
179 } while (0)
180#define STEAL_OPTION(option, field) \
181 CONSUME_OPTION(option, field, \
182 en->value = NULL; /* prevent it from being freed */)
183#define PROCESS_OPTION(option, function, on_error) do { \
184 const char *value; \
185 CONSUME_OPTION(option, value, if ((ret = function) < 0) \
186 { { on_error } goto end; }); \
187 } while (0)
188
189 STEAL_OPTION("f", format);
190 STEAL_OPTION("select", select);
191 PROCESS_OPTION("onfail",
193 av_log(avf, AV_LOG_ERROR, "Invalid onfail option value, "
194 "valid options are 'abort' and 'ignore'\n"););
195 PROCESS_OPTION("use_fifo",
196 parse_slave_fifo_policy(value, tee_slave),
197 av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n",
198 av_err2str(ret)););
199 PROCESS_OPTION("fifo_options",
200 parse_slave_fifo_options(value, tee_slave), ;);
201 entry = NULL;
202 while ((entry = av_dict_get(options, "bsfs", NULL, AV_DICT_IGNORE_SUFFIX))) {
203 /* trim out strlen("bsfs") characters from key */
204 av_dict_set(&bsf_options, entry->key + 4, entry->value, 0);
205 av_dict_set(&options, entry->key, NULL, 0);
206 }
207
208 if (tee_slave->use_fifo) {
209
210 if (options) {
211 char *format_options_str = NULL;
212 ret = av_dict_get_string(options, &format_options_str, '=', ':');
213 if (ret < 0)
214 goto end;
215
216 ret = av_dict_set(&tee_slave->fifo_options, "format_opts", format_options_str,
218 if (ret < 0)
219 goto end;
220 }
221
222 if (format) {
223 ret = av_dict_set(&tee_slave->fifo_options, "fifo_format", format,
225 format = NULL;
226 if (ret < 0)
227 goto end;
228 }
229
231 options = tee_slave->fifo_options;
232 tee_slave->fifo_options = NULL;
233 }
235 tee_slave->use_fifo ? "fifo" :format, filename);
236 if (ret < 0)
237 goto end;
238 tee_slave->avf = avf2;
239 av_dict_copy(&avf2->metadata, avf->metadata, 0);
240 avf2->opaque = avf->opaque;
241 avf2->io_open = avf->io_open;
242 avf2->io_close2 = avf->io_close2;
244 avf2->flags = avf->flags;
246
247 tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
248 if (!tee_slave->stream_map) {
249 ret = AVERROR(ENOMEM);
250 goto end;
251 }
252
253 stream_count = 0;
254 for (unsigned i = 0; i < avf->nb_streams; i++) {
255 const AVStream *st = avf->streams[i];
256 AVStream *st2;
257 if (select) {
258 tmp_select = av_strdup(select); // av_strtok is destructive so we regenerate it in each loop
259 if (!tmp_select) {
260 ret = AVERROR(ENOMEM);
261 goto end;
262 }
263 fullret = 0;
264 first_subselect = tmp_select;
265 next_subselect = NULL;
266 while (subselect = av_strtok(first_subselect, slave_select_sep, &next_subselect)) {
267 first_subselect = NULL;
268
269 ret = avformat_match_stream_specifier(avf, avf->streams[i], subselect);
270 if (ret < 0) {
271 av_log(avf, AV_LOG_ERROR,
272 "Invalid stream specifier '%s' for output '%s'\n",
273 subselect, slave);
274 goto end;
275 }
276 if (ret != 0) {
277 fullret = 1; // match
278 break;
279 }
280 }
281 av_freep(&tmp_select);
282
283 if (fullret == 0) { /* no match */
284 tee_slave->stream_map[i] = -1;
285 continue;
286 }
287 }
288 tee_slave->stream_map[i] = stream_count++;
289
290 st2 = ff_stream_clone(avf2, st);
291 if (!st2) {
292 ret = AVERROR(ENOMEM);
293 goto end;
294 }
295 }
296
297 for (unsigned i = 0; i < avf->nb_programs; i++) {
298 ret = av_program_copy(avf2, (const AVFormatContext *)avf, avf->programs[i]->id, 0);
299 if (ret < 0) {
300 av_log(avf, AV_LOG_ERROR, "unable to transfer program %d to child muxer\n", avf->programs[i]->id);
301 goto end;
302 }
303 }
304
305 ret = ff_format_output_open(avf2, filename, &options);
306 if (ret < 0) {
307 av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave,
308 av_err2str(ret));
309 goto end;
310 }
311
312 if ((ret = avformat_write_header(avf2, &options)) < 0) {
313 av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
314 slave, av_err2str(ret));
315 goto end;
316 }
317 tee_slave->header_written = 1;
318
319 tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(*tee_slave->bsfs));
320 if (!tee_slave->bsfs) {
321 ret = AVERROR(ENOMEM);
322 goto end;
323 }
324
325 entry = NULL;
326 while (entry = av_dict_iterate(bsf_options, NULL)) {
327 const char *spec = entry->key;
328 if (*spec) {
329 if (strspn(spec, slave_bsfs_spec_sep) != 1) {
330 av_log(avf, AV_LOG_ERROR,
331 "Specifier separator in '%s' is '%c', but only characters '%s' "
332 "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep);
333 ret = AVERROR(EINVAL);
334 goto end;
335 }
336 spec++; /* consume separator */
337 }
338
339 for (unsigned i = 0; i < avf2->nb_streams; i++) {
340 ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec);
341 if (ret < 0) {
342 av_log(avf, AV_LOG_ERROR,
343 "Invalid stream specifier '%s' in bsfs option '%s' for slave "
344 "output '%s'\n", spec, entry->key, filename);
345 goto end;
346 }
347
348 if (ret > 0) {
349 av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave "
350 "output '%s'\n", spec, entry->value, i, filename);
351 if (tee_slave->bsfs[i]) {
353 "Duplicate bsfs specification associated to stream %d of slave "
354 "output '%s', filters will be ignored\n", i, filename);
355 continue;
356 }
357 ret = av_bsf_list_parse_str(entry->value, &tee_slave->bsfs[i]);
358 if (ret < 0) {
359 av_log(avf, AV_LOG_ERROR,
360 "Error parsing bitstream filter sequence '%s' associated to "
361 "stream %d of slave output '%s'\n", entry->value, i, filename);
362 goto end;
363 }
364 }
365 }
366
367 av_dict_set(&bsf_options, entry->key, NULL, 0);
368 }
369
370 for (unsigned i = 0; i < avf->nb_streams; i++){
371 int target_stream = tee_slave->stream_map[i];
372 if (target_stream < 0)
373 continue;
374
375 if (!tee_slave->bsfs[target_stream]) {
376 /* Add pass-through bitstream filter */
377 ret = av_bsf_get_null_filter(&tee_slave->bsfs[target_stream]);
378 if (ret < 0) {
379 av_log(avf, AV_LOG_ERROR,
380 "Failed to create pass-through bitstream filter: %s\n",
381 av_err2str(ret));
382 goto end;
383 }
384 }
385
386 tee_slave->bsfs[target_stream]->time_base_in = avf->streams[i]->time_base;
387 ret = avcodec_parameters_copy(tee_slave->bsfs[target_stream]->par_in,
388 avf->streams[i]->codecpar);
389 if (ret < 0)
390 goto end;
391
392 ret = av_bsf_init(tee_slave->bsfs[target_stream]);
393 if (ret < 0) {
394 av_log(avf, AV_LOG_ERROR,
395 "Failed to initialize bitstream filter(s): %s\n",
396 av_err2str(ret));
397 goto end;
398 }
399 }
400
401 if (options) {
402 entry = NULL;
403 while ((entry = av_dict_iterate(options, entry)))
404 av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
406 goto end;
407 }
408
409end:
411 av_free(select);
413 av_dict_free(&bsf_options);
414 av_freep(&tmp_select);
415 return ret;
416}
417
418static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
419{
420 av_log(log_ctx, log_level, "filename:'%s' format:%s\n",
421 slave->avf->url, slave->avf->oformat->name);
422 for (unsigned i = 0; i < slave->avf->nb_streams; i++) {
423 AVStream *st = slave->avf->streams[i];
424 AVBSFContext *bsf = slave->bsfs[i];
425 const char *bsf_name;
426
427 av_log(log_ctx, log_level, " stream:%d codec:%s type:%s",
430
431 bsf_name = bsf->filter->priv_class ?
432 bsf->filter->priv_class->item_name(bsf) : bsf->filter->name;
433 av_log(log_ctx, log_level, " bsfs: %s\n", bsf_name);
434 }
435}
436
437static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
438{
439 TeeContext *tee = avf->priv_data;
440 TeeSlave *tee_slave = &tee->slaves[slave_idx];
441
442 tee->nb_alive--;
443
444 close_slave(tee_slave);
445
446 if (!tee->nb_alive) {
447 av_log(avf, AV_LOG_ERROR, "All tee outputs failed.\n");
448 return err_n;
449 } else if (tee_slave->on_fail == ON_SLAVE_FAILURE_ABORT) {
450 av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed, aborting.\n", slave_idx);
451 return err_n;
452 } else {
453 av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed: %s, continuing with %u/%u slaves.\n",
454 slave_idx, av_err2str(err_n), tee->nb_alive, tee->nb_slaves);
455 return 0;
456 }
457}
458
460{
461 TeeContext *tee = avf->priv_data;
462 unsigned nb_slaves = 0;
463 const char *filename = avf->url;
464 char **slaves = NULL;
465 int ret;
466
467 while (*filename) {
468 char *slave = av_get_token(&filename, slave_delim);
469 if (!slave) {
470 ret = AVERROR(ENOMEM);
471 goto fail;
472 }
473 ret = av_dynarray_add_nofree(&slaves, &nb_slaves, slave);
474 if (ret < 0) {
475 av_free(slave);
476 goto fail;
477 }
478 if (strspn(filename, slave_delim))
479 filename++;
480 }
481
482 if (!FF_ALLOCZ_TYPED_ARRAY(tee->slaves, nb_slaves)) {
483 ret = AVERROR(ENOMEM);
484 goto fail;
485 }
486 tee->nb_slaves = tee->nb_alive = nb_slaves;
487
488 for (unsigned i = 0; i < nb_slaves; i++) {
489
490 tee->slaves[i].use_fifo = tee->use_fifo;
491 ret = av_dict_copy(&tee->slaves[i].fifo_options, tee->fifo_options, 0);
492 if (ret < 0)
493 goto fail;
494
495 if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) {
496 ret = tee_process_slave_failure(avf, i, ret);
497 if (ret < 0)
498 goto fail;
499 } else {
500 log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE);
501 }
502 av_freep(&slaves[i]);
503 }
504
505 for (unsigned i = 0; i < avf->nb_streams; i++) {
506 int mapped = 0;
507 for (unsigned j = 0; j < tee->nb_slaves; j++)
508 if (tee->slaves[j].avf)
509 mapped += tee->slaves[j].stream_map[i] >= 0;
510 if (!mapped)
511 av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
512 "to any slave.\n", i);
513 }
514 av_free(slaves);
515 return 0;
516
517fail:
518 for (unsigned i = 0; i < nb_slaves; i++)
519 av_freep(&slaves[i]);
520 close_slaves(avf);
521 av_free(slaves);
522 return ret;
523}
524
526{
527 TeeContext *tee = avf->priv_data;
528 int ret_all = 0, ret;
529
530 for (unsigned i = 0; i < tee->nb_slaves; i++) {
531 if ((ret = close_slave(&tee->slaves[i])) < 0) {
532 ret = tee_process_slave_failure(avf, i, ret);
533 if (!ret_all && ret < 0)
534 ret_all = ret;
535 }
536 }
537 av_freep(&tee->slaves);
538 return ret_all;
539}
540
542{
543 TeeContext *tee = avf->priv_data;
544 AVPacket *const pkt2 = ffformatcontext(avf)->pkt;
545 int ret_all = 0, ret;
546 unsigned s;
547 int s2;
548
549 for (unsigned i = 0; i < tee->nb_slaves; i++) {
550 AVFormatContext *avf2 = tee->slaves[i].avf;
551 AVBSFContext *bsfs;
552
553 if (!avf2)
554 continue;
555
556 /* Flush slave if pkt is NULL*/
557 if (!pkt) {
558 ret = av_interleaved_write_frame(avf2, NULL);
559 if (ret < 0) {
560 ret = tee_process_slave_failure(avf, i, ret);
561 if (!ret_all && ret < 0)
562 ret_all = ret;
563 }
564 continue;
565 }
566
567 s = pkt->stream_index;
568 s2 = tee->slaves[i].stream_map[s];
569 if (s2 < 0)
570 continue;
571
572 if ((ret = av_packet_ref(pkt2, pkt)) < 0) {
573 if (!ret_all)
574 ret_all = ret;
575 continue;
576 }
577 bsfs = tee->slaves[i].bsfs[s2];
578 pkt2->stream_index = s2;
579
580 ret = av_bsf_send_packet(bsfs, pkt2);
581 if (ret < 0) {
582 av_packet_unref(pkt2);
583 av_log(avf, AV_LOG_ERROR, "Error while sending packet to bitstream filter: %s\n",
584 av_err2str(ret));
585 ret = tee_process_slave_failure(avf, i, ret);
586 if (!ret_all && ret < 0)
587 ret_all = ret;
588 }
589
590 while(1) {
591 ret = av_bsf_receive_packet(bsfs, pkt2);
592 if (ret == AVERROR(EAGAIN)) {
593 ret = 0;
594 break;
595 } else if (ret < 0) {
596 break;
597 }
598
600 avf2->streams[s2]->time_base);
601 ret = av_interleaved_write_frame(avf2, pkt2);
602 if (ret < 0)
603 break;
604 };
605
606 if (ret < 0) {
607 ret = tee_process_slave_failure(avf, i, ret);
608 if (!ret_all && ret < 0)
609 ret_all = ret;
610 }
611 }
612 return ret_all;
613}
614
616 .p.name = "tee",
617 .p.long_name = NULL_IF_CONFIG_SMALL("Multiple muxer tee"),
618 .priv_data_size = sizeof(TeeContext),
622 .p.priv_class = &tee_muxer_class,
623 .p.flags = AVFMT_NOFILE | AVFMT_TS_NEGATIVE,
624 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
625};
static const char *const format[]
Definition af_aiir.c:444
const FFOutputFormat ff_tee_muxer
Definition tee.c:615
#define entry
int ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition avformat.c:961
AVStream * ff_stream_clone(AVFormatContext *dst_ctx, const AVStream *src)
Create a new stream and copy to it all parameters from a source stream, with the exception of the ind...
Definition avformat.c:251
Main libavformat public API header.
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition avformat.h:488
#define AVFMT_TS_NEGATIVE
Format allows muxing negative timestamps.
Definition avformat.h:510
int avformat_alloc_output_context2(AVFormatContext **ctx, const AVOutputFormat *oformat, const char *format_name, const char *filename)
Allocate an AVFormatContext for an output format.
Definition mux.c:95
Convenience header that includes libavutil's core.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Definition codec_par.c:107
#define NULL
Definition coverity.c:32
static AVPacket * pkt
double value
Definition eval.c:102
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
Definition ffmpeg_mux.c:204
static void write_header(FFV1Context *f)
Definition ffv1enc.c:384
#define fail
Definition test.h:479
#define AV_OPT_FLAG_ENCODING_PARAM
A generic parameter which can be set by the user for muxing or encoding.
Definition opt.h:351
@ AV_OPT_TYPE_DICT
Underlying C type is AVDictionary*.
Definition opt.h:289
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
void av_bsf_free(AVBSFContext **pctx)
Free a bitstream filter context and everything associated with it; write NULL into the supplied point...
Definition bsf.c:47
int av_bsf_init(AVBSFContext *ctx)
Prepare the filter for use, after all the parameters and options have been set.
Definition bsf.c:147
int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt)
Retrieve a filtered packet.
Definition bsf.c:228
int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
Submit a packet for filtering.
Definition bsf.c:200
int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf_lst)
Parse string describing list of bitstream filters and create single AVBSFContext describing the whole...
Definition bsf.c:524
int av_bsf_get_null_filter(AVBSFContext **bsf)
Get null/pass-through bitstream filter.
Definition bsf.c:551
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Definition utils.c:421
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition packet.c:442
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
Convert valid timing fields (timestamps / durations) in a packet from one timebase to another.
Definition packet.c:538
int av_program_copy(AVFormatContext *dst, const AVFormatContext *src, int progid, int flags)
Copy an AVProgram from one AVFormatContext to another.
Definition avformat.c:349
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition avformat.c:150
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition mux.c:467
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file ensuring correct interleaving.
Definition mux.c:1223
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition mux.c:1238
int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
Check if the stream st contained in s is matched by the stream specifier spec.
Definition avformat.c:742
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition dict.c:60
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key,...
Definition dict.h:75
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:42
int av_dict_get_string(const AVDictionary *m, char **buffer, const char key_val_sep, const char pairs_sep)
Get dictionary entries as a string.
Definition dict.c:260
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition dict.c:247
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition dict.h:79
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition dict.c:210
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
#define AVERROR_OPTION_NOT_FOUND
Option not found.
Definition error.h:63
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition mem.c:313
const char * av_get_media_type_string(enum AVMediaType media_type)
Return a string describing the media_type enum, NULL if media_type is unknown.
Definition utils.c:28
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition avstring.c:179
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition avstring.c:208
int av_match_name(const char *name, const char *names)
Match instances of a name in a comma-separated list of names.
Definition avstring.c:341
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition avstring.c:143
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
static av_always_inline FFFormatContext * ffformatcontext(AVFormatContext *s)
Definition internal.h:130
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define FF_ALLOCZ_TYPED_ARRAY(p, nelem)
Definition internal.h:72
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **options)
Utility function to open IO stream of output format.
Definition mux_utils.c:127
#define FF_OFMT_FLAG_ALLOW_FLUSH
This flag indicates that the muxer stores data internally and supports flushing it.
Definition mux.h:38
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
The bitstream filter state.
Definition bsf.h:68
AVRational time_base_out
The timebase used for the timestamps of the output packets.
Definition bsf.h:108
AVCodecParameters * par_in
Parameters of the input stream.
Definition bsf.h:90
AVRational time_base_in
The timebase used for the timestamps of the input packets.
Definition bsf.h:102
const struct AVBitStreamFilter * filter
The bitstream filter this context is an instance of.
Definition bsf.h:77
const AVClass * priv_class
A class for the private data, used to declare bitstream filter private AVOptions.
Definition bsf.h:130
const char * name
Definition bsf.h:112
Describe the class of an AVClass context structure.
Definition log.h:76
const char *(* item_name)(void *ctx)
A pointer to a function which returns the name of a context instance ctx associated with the class.
Definition log.h:87
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
Format I/O context.
Definition avformat.h:1333
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition avformat.h:1389
int(* io_close2)(struct AVFormatContext *s, AVIOContext *pb)
A callback for closing the streams opened with AVFormatContext.io_open().
Definition avformat.h:1963
AVIOContext * pb
I/O context.
Definition avformat.h:1375
AVDictionary * metadata
Metadata that applies to the whole file.
Definition avformat.h:1580
int flags
Flags modifying the (de)muxer behaviour.
Definition avformat.h:1484
const struct AVOutputFormat * oformat
The output container format.
Definition avformat.h:1352
AVProgram ** programs
Definition avformat.h:1546
int strict_std_compliance
Allow non-standard and experimental extension.
Definition avformat.h:1707
unsigned int nb_programs
Definition avformat.h:1545
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition avformat.h:1618
char * url
input or output URL.
Definition avformat.h:1449
void * opaque
User data.
Definition avformat.h:1912
void * priv_data
Format private data.
Definition avformat.h:1361
AVStream ** streams
A list of all streams in the file.
Definition avformat.h:1401
int(* io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
A callback for opening new IO streams.
Definition avformat.h:1953
AVOption.
Definition opt.h:428
const char * name
Definition avformat.h:527
This structure stores compressed data.
Definition packet.h:580
int stream_index
Definition packet.h:605
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition avformat.h:805
AVPacket * pkt
Used to hold temporary packets for the generic demuxing code.
Definition internal.h:111
AVDictionary * fifo_options
Definition tee.c:60
TeeSlave * slaves
Definition tee.c:58
unsigned nb_slaves
Definition tee.c:56
unsigned nb_alive
Definition tee.c:57
int use_fifo
Definition tee.c:59
Definition tee.c:40
int header_written
Definition tee.c:51
AVFormatContext * avf
Definition tee.c:41
int * stream_map
map from input to output streams indexes, disabled output streams are set to -1
Definition tee.c:50
AVDictionary * fifo_options
Definition tee.c:46
AVBSFContext ** bsfs
bitstream filters per stream
Definition tee.c:42
SlaveFailurePolicy on_fail
Definition tee.c:44
int use_fifo
Definition tee.c:45
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
SlaveFailurePolicy
Definition tee.c:33
@ ON_SLAVE_FAILURE_ABORT
Definition tee.c:34
@ ON_SLAVE_FAILURE_IGNORE
Definition tee.c:35
static int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave)
Definition tee.c:83
static const AVOption tee_options[]
Definition tee.c:68
static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
Definition tee.c:437
#define STEAL_OPTION(option, field)
static int tee_write_trailer(AVFormatContext *avf)
Definition tee.c:525
#define DEFAULT_SLAVE_FAILURE_POLICY
Definition tee.c:38
static const char *const slave_select_sep
Definition tee.c:65
static int parse_slave_fifo_policy(const char *use_fifo, TeeSlave *tee_slave)
Definition tee.c:100
#define PROCESS_OPTION(option, function, on_error)
static const char *const slave_delim
Definition tee.c:63
static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
Definition tee.c:541
static int close_slave(TeeSlave *tee_slave)
Definition tee.c:119
static const char *const slave_bsfs_spec_sep
Definition tee.c:64
static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
Definition tee.c:155
#define OFFSET(x)
Definition tee.c:67
static int parse_slave_fifo_options(const char *fifo_options, TeeSlave *tee_slave)
Definition tee.c:114
static int tee_write_header(AVFormatContext *avf)
Definition tee.c:459
static const AVClass tee_muxer_class
Definition tee.c:76
static void close_slaves(AVFormatContext *avf)
Definition tee.c:145
static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
Definition tee.c:418
int ff_tee_parse_slave_options(void *log, char *slave, AVDictionary **options, char **filename)
Definition tee_common.c:33
static int write_trailer(AVFormatContext *s1)
Definition v4l2enc.c:101