FFmpeg
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/opt.h"
26 #include "internal.h"
27 #include "avformat.h"
28 #include "avio_internal.h"
29 #include "tee_common.h"
30 
31 typedef enum {
35 
36 #define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
37 
38 typedef struct {
40  AVBSFContext **bsfs; ///< bitstream filters per stream
41 
43  int use_fifo;
45 
46  /** map from input to output streams indexes,
47  * disabled output streams are set to -1 */
48  int *stream_map;
50 } TeeSlave;
51 
52 typedef struct TeeContext {
53  const AVClass *class;
54  unsigned nb_slaves;
55  unsigned nb_alive;
57  int use_fifo;
59 } TeeContext;
60 
61 static const char *const slave_delim = "|";
62 static const char *const slave_bsfs_spec_sep = "/";
63 static const char *const slave_select_sep = ",";
64 
65 #define OFFSET(x) offsetof(TeeContext, x)
66 static const AVOption options[] = {
67  {"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from encoder",
68  OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
69  {"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options),
71  {NULL}
72 };
73 
74 static const AVClass tee_muxer_class = {
75  .class_name = "Tee muxer",
76  .item_name = av_default_item_name,
77  .option = options,
78  .version = LIBAVUTIL_VERSION_INT,
79 };
80 
81 static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave)
82 {
83  if (!opt) {
85  return 0;
86  } else if (!av_strcasecmp("abort", opt)) {
87  tee_slave->on_fail = ON_SLAVE_FAILURE_ABORT;
88  return 0;
89  } else if (!av_strcasecmp("ignore", opt)) {
90  tee_slave->on_fail = ON_SLAVE_FAILURE_IGNORE;
91  return 0;
92  }
93  /* Set failure behaviour to abort, so invalid option error will not be ignored */
94  tee_slave->on_fail = ON_SLAVE_FAILURE_ABORT;
95  return AVERROR(EINVAL);
96 }
97 
98 static int parse_slave_fifo_options(const char *use_fifo,
99  const char *fifo_options, TeeSlave *tee_slave)
100 {
101  int ret = 0;
102 
103  if (use_fifo) {
104  /*TODO - change this to use proper function for parsing boolean
105  * options when there is one */
106  if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) {
107  tee_slave->use_fifo = 1;
108  } else if (av_match_name(use_fifo, "false,n,no,disable,disabled,off,0")) {
109  tee_slave->use_fifo = 0;
110  } else {
111  return AVERROR(EINVAL);
112  }
113  }
114 
115  if (fifo_options)
116  ret = av_dict_parse_string(&tee_slave->fifo_options, fifo_options, "=", ":", 0);
117 
118  return ret;
119 }
120 
121 static int close_slave(TeeSlave *tee_slave)
122 {
123  AVFormatContext *avf;
124  unsigned i;
125  int ret = 0;
126 
127  av_dict_free(&tee_slave->fifo_options);
128  avf = tee_slave->avf;
129  if (!avf)
130  return 0;
131 
132  if (tee_slave->header_written)
133  ret = av_write_trailer(avf);
134 
135  if (tee_slave->bsfs) {
136  for (i = 0; i < avf->nb_streams; ++i)
137  av_bsf_free(&tee_slave->bsfs[i]);
138  }
139  av_freep(&tee_slave->stream_map);
140  av_freep(&tee_slave->bsfs);
141 
142  ff_format_io_close(avf, &avf->pb);
144  tee_slave->avf = NULL;
145  return ret;
146 }
147 
148 static void close_slaves(AVFormatContext *avf)
149 {
150  TeeContext *tee = avf->priv_data;
151  unsigned i;
152 
153  for (i = 0; i < tee->nb_slaves; i++) {
154  close_slave(&tee->slaves[i]);
155  }
156  av_freep(&tee->slaves);
157 }
158 
159 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
160 {
161  int i, ret;
162  AVDictionary *options = NULL, *bsf_options = NULL;
163  AVDictionaryEntry *entry;
164  char *filename;
165  char *format = NULL, *select = NULL, *on_fail = NULL;
166  char *use_fifo = NULL, *fifo_options_str = NULL;
167  AVFormatContext *avf2 = NULL;
168  AVStream *st, *st2;
169  int stream_count;
170  int fullret;
171  char *subselect = NULL, *next_subselect = NULL, *first_subselect = NULL, *tmp_select = NULL;
172 
173  if ((ret = ff_tee_parse_slave_options(avf, slave, &options, &filename)) < 0)
174  return ret;
175 
176 #define STEAL_OPTION(option, field) do { \
177  if ((entry = av_dict_get(options, option, NULL, 0))) { \
178  field = entry->value; \
179  entry->value = NULL; /* prevent it from being freed */ \
180  av_dict_set(&options, option, NULL, 0); \
181  } \
182  } while (0)
183 
184  STEAL_OPTION("f", format);
185  STEAL_OPTION("select", select);
186  STEAL_OPTION("onfail", on_fail);
187  STEAL_OPTION("use_fifo", use_fifo);
188  STEAL_OPTION("fifo_options", fifo_options_str);
189  entry = NULL;
190  while ((entry = av_dict_get(options, "bsfs", entry, AV_DICT_IGNORE_SUFFIX))) {
191  /* trim out strlen("bsfs") characters from key */
192  av_dict_set(&bsf_options, entry->key + 4, entry->value, 0);
193  av_dict_set(&options, entry->key, NULL, 0);
194  }
195 
196  ret = parse_slave_failure_policy_option(on_fail, tee_slave);
197  if (ret < 0) {
198  av_log(avf, AV_LOG_ERROR,
199  "Invalid onfail option value, valid options are 'abort' and 'ignore'\n");
200  goto end;
201  }
202 
203  ret = parse_slave_fifo_options(use_fifo, fifo_options_str, tee_slave);
204  if (ret < 0) {
205  av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n", av_err2str(ret));
206  goto end;
207  }
208 
209  if (tee_slave->use_fifo) {
210 
211  if (options) {
212  char *format_options_str = NULL;
213  ret = av_dict_get_string(options, &format_options_str, '=', ':');
214  if (ret < 0)
215  goto end;
216 
217  ret = av_dict_set(&tee_slave->fifo_options, "format_opts", format_options_str,
219  if (ret < 0)
220  goto end;
221  }
222 
223  if (format) {
224  ret = av_dict_set(&tee_slave->fifo_options, "fifo_format", format,
226  format = NULL;
227  if (ret < 0)
228  goto end;
229  }
230 
232  options = tee_slave->fifo_options;
233  tee_slave->fifo_options = NULL;
234  }
236  tee_slave->use_fifo ? "fifo" :format, filename);
237  if (ret < 0)
238  goto end;
239  tee_slave->avf = avf2;
240  av_dict_copy(&avf2->metadata, avf->metadata, 0);
241  avf2->opaque = avf->opaque;
242  avf2->io_open = avf->io_open;
243  avf2->io_close = avf->io_close;
245  avf2->flags = avf->flags;
247 
248  tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
249  if (!tee_slave->stream_map) {
250  ret = AVERROR(ENOMEM);
251  goto end;
252  }
253 
254  stream_count = 0;
255  for (i = 0; i < avf->nb_streams; i++) {
256  st = avf->streams[i];
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  if (!(st2 = avformat_new_stream(avf2, NULL))) {
291  ret = AVERROR(ENOMEM);
292  goto end;
293  }
294 
296  if (ret < 0)
297  goto end;
298  }
299 
300  ret = ff_format_output_open(avf2, filename, &options);
301  if (ret < 0) {
302  av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave,
303  av_err2str(ret));
304  goto end;
305  }
306 
307  if ((ret = avformat_write_header(avf2, &options)) < 0) {
308  av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
309  slave, av_err2str(ret));
310  goto end;
311  }
312  tee_slave->header_written = 1;
313 
314  tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(*tee_slave->bsfs));
315  if (!tee_slave->bsfs) {
316  ret = AVERROR(ENOMEM);
317  goto end;
318  }
319 
320  entry = NULL;
321  while (entry = av_dict_get(bsf_options, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
322  const char *spec = entry->key;
323  if (*spec) {
324  if (strspn(spec, slave_bsfs_spec_sep) != 1) {
325  av_log(avf, AV_LOG_ERROR,
326  "Specifier separator in '%s' is '%c', but only characters '%s' "
327  "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep);
328  ret = AVERROR(EINVAL);
329  goto end;
330  }
331  spec++; /* consume separator */
332  }
333 
334  for (i = 0; i < avf2->nb_streams; i++) {
335  ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec);
336  if (ret < 0) {
337  av_log(avf, AV_LOG_ERROR,
338  "Invalid stream specifier '%s' in bsfs option '%s' for slave "
339  "output '%s'\n", spec, entry->key, filename);
340  goto end;
341  }
342 
343  if (ret > 0) {
344  av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave "
345  "output '%s'\n", spec, entry->value, i, filename);
346  if (tee_slave->bsfs[i]) {
347  av_log(avf, AV_LOG_WARNING,
348  "Duplicate bsfs specification associated to stream %d of slave "
349  "output '%s', filters will be ignored\n", i, filename);
350  continue;
351  }
352  ret = av_bsf_list_parse_str(entry->value, &tee_slave->bsfs[i]);
353  if (ret < 0) {
354  av_log(avf, AV_LOG_ERROR,
355  "Error parsing bitstream filter sequence '%s' associated to "
356  "stream %d of slave output '%s'\n", entry->value, i, filename);
357  goto end;
358  }
359  }
360  }
361 
362  av_dict_set(&bsf_options, entry->key, NULL, 0);
363  }
364 
365  for (i = 0; i < avf->nb_streams; i++){
366  int target_stream = tee_slave->stream_map[i];
367  if (target_stream < 0)
368  continue;
369 
370  if (!tee_slave->bsfs[target_stream]) {
371  /* Add pass-through bitstream filter */
372  ret = av_bsf_get_null_filter(&tee_slave->bsfs[target_stream]);
373  if (ret < 0) {
374  av_log(avf, AV_LOG_ERROR,
375  "Failed to create pass-through bitstream filter: %s\n",
376  av_err2str(ret));
377  goto end;
378  }
379  }
380 
381  tee_slave->bsfs[target_stream]->time_base_in = avf->streams[i]->time_base;
382  ret = avcodec_parameters_copy(tee_slave->bsfs[target_stream]->par_in,
383  avf->streams[i]->codecpar);
384  if (ret < 0)
385  goto end;
386 
387  ret = av_bsf_init(tee_slave->bsfs[target_stream]);
388  if (ret < 0) {
389  av_log(avf, AV_LOG_ERROR,
390  "Failed to initialize bitstream filter(s): %s\n",
391  av_err2str(ret));
392  goto end;
393  }
394  }
395 
396  if (options) {
397  entry = NULL;
398  while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX)))
399  av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
401  goto end;
402  }
403 
404 end:
405  av_free(format);
406  av_free(select);
407  av_free(on_fail);
408  av_free(use_fifo);
409  av_free(fifo_options_str);
411  av_dict_free(&bsf_options);
412  av_freep(&tmp_select);
413  return ret;
414 }
415 
416 static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
417 {
418  int i;
419  av_log(log_ctx, log_level, "filename:'%s' format:%s\n",
420  slave->avf->url, slave->avf->oformat->name);
421  for (i = 0; i < slave->avf->nb_streams; i++) {
422  AVStream *st = slave->avf->streams[i];
423  AVBSFContext *bsf = slave->bsfs[i];
424  const char *bsf_name;
425 
426  av_log(log_ctx, log_level, " stream:%d codec:%s type:%s",
429 
430  bsf_name = bsf->filter->priv_class ?
431  bsf->filter->priv_class->item_name(bsf) : bsf->filter->name;
432  av_log(log_ctx, log_level, " bsfs: %s\n", bsf_name);
433  }
434 }
435 
436 static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
437 {
438  TeeContext *tee = avf->priv_data;
439  TeeSlave *tee_slave = &tee->slaves[slave_idx];
440 
441  tee->nb_alive--;
442 
443  close_slave(tee_slave);
444 
445  if (!tee->nb_alive) {
446  av_log(avf, AV_LOG_ERROR, "All tee outputs failed.\n");
447  return err_n;
448  } else if (tee_slave->on_fail == ON_SLAVE_FAILURE_ABORT) {
449  av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed, aborting.\n", slave_idx);
450  return err_n;
451  } else {
452  av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed: %s, continuing with %u/%u slaves.\n",
453  slave_idx, av_err2str(err_n), tee->nb_alive, tee->nb_slaves);
454  return 0;
455  }
456 }
457 
459 {
460  TeeContext *tee = avf->priv_data;
461  unsigned nb_slaves = 0, i;
462  const char *filename = avf->url;
463  char **slaves = NULL;
464  int ret;
465 
466  while (*filename) {
467  char *slave = av_get_token(&filename, slave_delim);
468  if (!slave) {
469  ret = AVERROR(ENOMEM);
470  goto fail;
471  }
472  ret = av_dynarray_add_nofree(&slaves, &nb_slaves, slave);
473  if (ret < 0) {
474  av_free(slave);
475  goto fail;
476  }
477  if (strspn(filename, slave_delim))
478  filename++;
479  }
480 
481  if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves)))) {
482  ret = AVERROR(ENOMEM);
483  goto fail;
484  }
485  tee->nb_slaves = tee->nb_alive = nb_slaves;
486 
487  for (i = 0; i < nb_slaves; i++) {
488 
489  tee->slaves[i].use_fifo = tee->use_fifo;
490  ret = av_dict_copy(&tee->slaves[i].fifo_options, tee->fifo_options, 0);
491  if (ret < 0)
492  goto fail;
493 
494  if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) {
496  if (ret < 0)
497  goto fail;
498  } else {
499  log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE);
500  }
501  av_freep(&slaves[i]);
502  }
503 
504  for (i = 0; i < avf->nb_streams; i++) {
505  int j, mapped = 0;
506  for (j = 0; j < tee->nb_slaves; j++)
507  if (tee->slaves[j].avf)
508  mapped += tee->slaves[j].stream_map[i] >= 0;
509  if (!mapped)
510  av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
511  "to any slave.\n", i);
512  }
513  av_free(slaves);
514  return 0;
515 
516 fail:
517  for (i = 0; i < nb_slaves; i++)
518  av_freep(&slaves[i]);
519  close_slaves(avf);
520  av_free(slaves);
521  return ret;
522 }
523 
525 {
526  TeeContext *tee = avf->priv_data;
527  int ret_all = 0, ret;
528  unsigned i;
529 
530  for (i = 0; i < tee->nb_slaves; i++) {
531  if ((ret = close_slave(&tee->slaves[i])) < 0) {
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  AVFormatContext *avf2;
545  AVBSFContext *bsfs;
546  AVPacket pkt2;
547  int ret_all = 0, ret;
548  unsigned i, s;
549  int s2;
550 
551  for (i = 0; i < tee->nb_slaves; i++) {
552  if (!(avf2 = tee->slaves[i].avf))
553  continue;
554 
555  /* Flush slave if pkt is NULL*/
556  if (!pkt) {
558  if (ret < 0) {
560  if (!ret_all && ret < 0)
561  ret_all = ret;
562  }
563  continue;
564  }
565 
566  s = pkt->stream_index;
567  s2 = tee->slaves[i].stream_map[s];
568  if (s2 < 0)
569  continue;
570 
571  if ((ret = av_packet_ref(&pkt2, pkt)) < 0)
572  if (!ret_all) {
573  ret_all = ret;
574  continue;
575  }
576  bsfs = tee->slaves[i].bsfs[s2];
577  pkt2.stream_index = s2;
578 
579  ret = av_bsf_send_packet(bsfs, &pkt2);
580  if (ret < 0) {
581  av_log(avf, AV_LOG_ERROR, "Error while sending packet to bitstream filter: %s\n",
582  av_err2str(ret));
584  if (!ret_all && ret < 0)
585  ret_all = ret;
586  }
587 
588  while(1) {
589  ret = av_bsf_receive_packet(bsfs, &pkt2);
590  if (ret == AVERROR(EAGAIN)) {
591  ret = 0;
592  break;
593  } else if (ret < 0) {
594  break;
595  }
596 
597  av_packet_rescale_ts(&pkt2, bsfs->time_base_out,
598  avf2->streams[s2]->time_base);
599  ret = av_interleaved_write_frame(avf2, &pkt2);
600  if (ret < 0)
601  break;
602  };
603 
604  if (ret < 0) {
606  if (!ret_all && ret < 0)
607  ret_all = ret;
608  }
609  }
610  return ret_all;
611 }
612 
614  .name = "tee",
615  .long_name = NULL_IF_CONFIG_SMALL("Multiple muxer tee"),
616  .priv_data_size = sizeof(TeeContext),
620  .priv_class = &tee_muxer_class,
622 };
AVBSFContext::par_in
AVCodecParameters * par_in
Parameters of the input stream.
Definition: bsf.h:77
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
ON_SLAVE_FAILURE_IGNORE
@ ON_SLAVE_FAILURE_IGNORE
Definition: tee.c:33
AVOutputFormat::name
const char * name
Definition: avformat.h:491
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4509
TeeSlave::bsfs
AVBSFContext ** bsfs
bitstream filters per stream
Definition: tee.c:40
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
TeeSlave::stream_map
int * stream_map
map from input to output streams indexes, disabled output streams are set to -1
Definition: tee.c:48
av_get_token
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:151
ff_format_output_open
int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **options)
Utility function to open IO stream of output format.
Definition: utils.c:5682
AVBitStreamFilter::name
const char * name
Definition: bsf.h:99
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:215
av_bsf_init
int av_bsf_init(AVBSFContext *ctx)
Prepare the filter for use, after all the parameters and options have been set.
Definition: bsf.c:148
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1300
AVFormatContext::strict_std_compliance
int strict_std_compliance
Allow non-standard and experimental extension.
Definition: avformat.h:1542
OFFSET
#define OFFSET(x)
Definition: tee.c:65
ff_tee_parse_slave_options
int ff_tee_parse_slave_options(void *log, char *slave, AVDictionary **options, char **filename)
Definition: tee_common.c:32
AVOption
AVOption.
Definition: opt.h:248
AV_DICT_IGNORE_SUFFIX
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key,...
Definition: dict.h:70
av_mallocz_array
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:190
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
tee_write_trailer
static int tee_write_trailer(AVFormatContext *avf)
Definition: tee.c:524
AVDictionary
Definition: dict.c:30
tee_write_packet
static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
Definition: tee.c:541
TeeContext::use_fifo
int use_fifo
Definition: tee.c:57
TeeContext::nb_slaves
unsigned nb_slaves
Definition: tee.c:54
AVBSFContext
The bitstream filter state.
Definition: bsf.h:49
ON_SLAVE_FAILURE_ABORT
@ ON_SLAVE_FAILURE_ABORT
Definition: tee.c:32
STEAL_OPTION
#define STEAL_OPTION(option, field)
tee_common.h
AVFormatContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1512
fail
#define fail()
Definition: checkasm.h:133
AVERROR_OPTION_NOT_FOUND
#define AVERROR_OPTION_NOT_FOUND
Option not found.
Definition: error.h:61
av_bsf_get_null_filter
int av_bsf_get_null_filter(AVBSFContext **bsf)
Get null/pass-through bitstream filter.
Definition: bsf.c:557
AV_DICT_DONT_STRDUP_VAL
#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:74
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
AVFormatContext::metadata
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1474
av_dict_get
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:40
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_OPT_FLAG_ENCODING_PARAM
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:278
tee_muxer_class
static const AVClass tee_muxer_class
Definition: tee.c:74
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1363
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
AVDictionaryEntry::key
char * key
Definition: dict.h:82
slave_bsfs_spec_sep
static const char *const slave_bsfs_spec_sep
Definition: tee.c:62
av_strtok
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:186
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
TeeContext::slaves
TeeSlave * slaves
Definition: tee.c:56
AVBSFContext::time_base_in
AVRational time_base_in
The timebase used for the timestamps of the input packets.
Definition: bsf.h:89
TeeContext::fifo_options
AVDictionary * fifo_options
Definition: tee.c:58
slave_select_sep
static const char *const slave_select_sep
Definition: tee.c:63
AVFormatContext::opaque
void * opaque
User data.
Definition: avformat.h:1752
tee_process_slave_failure
static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
Definition: tee.c:436
avformat_write_header
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:506
AVFormatContext
Format I/O context.
Definition: avformat.h:1232
parse_slave_fifo_options
static int parse_slave_fifo_options(const char *use_fifo, const char *fifo_options, TeeSlave *tee_slave)
Definition: tee.c:98
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1038
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:902
NULL
#define NULL
Definition: coverity.c:32
av_bsf_list_parse_str
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:523
write_trailer
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:98
AV_OPT_TYPE_DICT
@ AV_OPT_TYPE_DICT
Definition: opt.h:232
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
close_slave
static int close_slave(TeeSlave *tee_slave)
Definition: tee.c:121
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1274
TeeContext::nb_alive
unsigned nb_alive
Definition: tee.c:55
AVBitStreamFilter::priv_class
const AVClass * priv_class
A class for the private data, used to declare bitstream filter private AVOptions.
Definition: bsf.h:117
av_packet_ref
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: avpacket.c:641
AVFormatContext::oformat
ff_const59 struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1251
TeeSlave::on_fail
SlaveFailurePolicy on_fail
Definition: tee.c:42
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1288
s2
#define s2
Definition: regdef.h:39
TeeSlave
Definition: tee.c:38
avformat_match_stream_specifier
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: utils.c:5326
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
ff_tee_muxer
AVOutputFormat ff_tee_muxer
Definition: tee.c:613
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
AVFormatContext::url
char * url
input or output URL.
Definition: avformat.h:1328
AVFMT_ALLOW_FLUSH
#define AVFMT_ALLOW_FLUSH
Format allows flushing.
Definition: avformat.h:471
close_slaves
static void close_slaves(AVFormatContext *avf)
Definition: tee.c:148
AVFMT_NOFILE
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:458
TeeSlave::fifo_options
AVDictionary * fifo_options
Definition: tee.c:44
DEFAULT_SLAVE_FAILURE_POLICY
#define DEFAULT_SLAVE_FAILURE_POLICY
Definition: tee.c:36
TeeContext
Definition: tee.c:52
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:203
avformat_alloc_output_context2
int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat, const char *format_name, const char *filename)
Allocate an AVFormatContext for an output format.
Definition: mux.c:136
options
static const AVOption options[]
Definition: tee.c:66
av_packet_rescale_ts
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: avpacket.c:737
TeeSlave::use_fifo
int use_fifo
Definition: tee.c:43
write_packet
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:729
avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: codec_par.c:72
avcodec_get_name
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Definition: utils.c:471
open_slave
static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
Definition: tee.c:159
av_write_trailer
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1274
i
int i
Definition: input.c:407
av_bsf_receive_packet
int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt)
Retrieve a filtered packet.
Definition: bsf.c:227
AVOutputFormat
Definition: avformat.h:490
avio_internal.h
TeeSlave::header_written
int header_written
Definition: tee.c:49
AVBSFContext::time_base_out
AVRational time_base_out
The timebase used for the timestamps of the output packets.
Definition: bsf.h:95
AVFMT_TS_NEGATIVE
#define AVFMT_TS_NEGATIVE
Format allows muxing negative timestamps.
Definition: avformat.h:475
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:873
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
avformat.h
av_bsf_send_packet
int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
Submit a packet for filtering.
Definition: bsf.c:201
parse_slave_failure_policy_option
static int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave)
Definition: tee.c:81
log_slave
static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
Definition: tee.c:416
av_dynarray_add_nofree
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition: mem.c:296
av_get_media_type_string
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:71
ff_stream_encode_params_copy
int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src)
Copy encoding parameters from source to destination stream.
Definition: utils.c:4316
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:245
SlaveFailurePolicy
SlaveFailurePolicy
Definition: tee.c:31
tee_write_header
static int tee_write_header(AVFormatContext *avf)
Definition: tee.c:458
av_match_name
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:353
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4436
av_dict_parse_string
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:180
AVFormatContext::io_close
void(* io_close)(struct AVFormatContext *s, AVIOContext *pb)
A callback for closing the streams opened with AVFormatContext.io_open().
Definition: avformat.h:1834
AVFormatContext::io_open
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:1828
slave_delim
static const char *const slave_delim
Definition: tee.c:61
AVPacket::stream_index
int stream_index
Definition: packet.h:371
AVBSFContext::filter
const struct AVBitStreamFilter * filter
The bitstream filter this context is an instance of.
Definition: bsf.h:58
ff_format_io_close
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: utils.c:5692
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
avutil.h
TeeSlave::avf
AVFormatContext * avf
Definition: tee.c:39
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:81
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
AVPacket
This structure stores compressed data.
Definition: packet.h:346
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:242
av_interleaved_write_frame
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file ensuring correct interleaving.
Definition: mux.c:1259
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
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:70
av_dict_get_string
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:230
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:217
av_bsf_free
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:40
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVDictionaryEntry::value
char * value
Definition: dict.h:83
avstring.h
AVClass::item_name
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:78
write_header
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:346
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1260