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/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 
33 typedef enum {
37 
38 #define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
39 
40 typedef struct {
42  AVBSFContext **bsfs; ///< bitstream filters per stream
43 
45  int use_fifo;
47 
48  /** map from input to output streams indexes,
49  * disabled output streams are set to -1 */
50  int *stream_map;
52 } TeeSlave;
53 
54 typedef struct TeeContext {
55  const AVClass *class;
56  unsigned nb_slaves;
57  unsigned nb_alive;
59  int use_fifo;
61 } TeeContext;
62 
63 static const char *const slave_delim = "|";
64 static const char *const slave_bsfs_spec_sep = "/";
65 static const char *const slave_select_sep = ",";
66 
67 #define OFFSET(x) offsetof(TeeContext, x)
68 static const AVOption 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 
76 static const AVClass tee_muxer_class = {
77  .class_name = "Tee muxer",
78  .item_name = av_default_item_name,
79  .option = options,
80  .version = LIBAVUTIL_VERSION_INT,
81 };
82 
83 static 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)) {
89  tee_slave->on_fail = ON_SLAVE_FAILURE_ABORT;
90  return 0;
91  } else if (!av_strcasecmp("ignore", opt)) {
92  tee_slave->on_fail = ON_SLAVE_FAILURE_IGNORE;
93  return 0;
94  }
95  /* Set failure behaviour to abort, so invalid option error will not be ignored */
96  tee_slave->on_fail = ON_SLAVE_FAILURE_ABORT;
97  return AVERROR(EINVAL);
98 }
99 
100 static 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 
114 static 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 
119 static 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 
145 static void close_slaves(AVFormatContext *avf)
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 
155 static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
156 {
157  int ret;
158  AVDictionary *options = NULL, *bsf_options = NULL;
159  const AVDictionaryEntry *entry;
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 
170 #define CONSUME_OPTION(option, field, action) do { \
171  AVDictionaryEntry *en = av_dict_get(options, option, NULL, 0); \
172  if (en) { \
173  field = en->value; \
174  { action } \
175  av_dict_set(&options, option, NULL, 0); \
176  } \
177  } while (0)
178 #define STEAL_OPTION(option, field) \
179  CONSUME_OPTION(option, field, \
180  en->value = NULL; /* prevent it from being freed */)
181 #define PROCESS_OPTION(option, function, on_error) do { \
182  const char *value; \
183  CONSUME_OPTION(option, value, if ((ret = function) < 0) \
184  { { on_error } goto end; }); \
185  } while (0)
186 
187  STEAL_OPTION("f", format);
188  STEAL_OPTION("select", select);
189  PROCESS_OPTION("onfail",
191  av_log(avf, AV_LOG_ERROR, "Invalid onfail option value, "
192  "valid options are 'abort' and 'ignore'\n"););
193  PROCESS_OPTION("use_fifo",
194  parse_slave_fifo_policy(value, tee_slave),
195  av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n",
196  av_err2str(ret)););
197  PROCESS_OPTION("fifo_options",
198  parse_slave_fifo_options(value, tee_slave), ;);
199  entry = NULL;
200  while ((entry = av_dict_get(options, "bsfs", entry, AV_DICT_IGNORE_SUFFIX))) {
201  /* trim out strlen("bsfs") characters from key */
202  av_dict_set(&bsf_options, entry->key + 4, entry->value, 0);
203  av_dict_set(&options, entry->key, NULL, 0);
204  }
205 
206  if (tee_slave->use_fifo) {
207 
208  if (options) {
209  char *format_options_str = NULL;
210  ret = av_dict_get_string(options, &format_options_str, '=', ':');
211  if (ret < 0)
212  goto end;
213 
214  ret = av_dict_set(&tee_slave->fifo_options, "format_opts", format_options_str,
216  if (ret < 0)
217  goto end;
218  }
219 
220  if (format) {
221  ret = av_dict_set(&tee_slave->fifo_options, "fifo_format", format,
223  format = NULL;
224  if (ret < 0)
225  goto end;
226  }
227 
229  options = tee_slave->fifo_options;
230  tee_slave->fifo_options = NULL;
231  }
233  tee_slave->use_fifo ? "fifo" :format, filename);
234  if (ret < 0)
235  goto end;
236  tee_slave->avf = avf2;
237  av_dict_copy(&avf2->metadata, avf->metadata, 0);
238  avf2->opaque = avf->opaque;
239  avf2->io_open = avf->io_open;
240  avf2->io_close2 = avf->io_close2;
242  avf2->flags = avf->flags;
244 
245  tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
246  if (!tee_slave->stream_map) {
247  ret = AVERROR(ENOMEM);
248  goto end;
249  }
250 
251  stream_count = 0;
252  for (unsigned i = 0; i < avf->nb_streams; i++) {
253  const AVStream *st = avf->streams[i];
254  AVStream *st2;
255  if (select) {
256  tmp_select = av_strdup(select); // av_strtok is destructive so we regenerate it in each loop
257  if (!tmp_select) {
258  ret = AVERROR(ENOMEM);
259  goto end;
260  }
261  fullret = 0;
262  first_subselect = tmp_select;
263  next_subselect = NULL;
264  while (subselect = av_strtok(first_subselect, slave_select_sep, &next_subselect)) {
265  first_subselect = NULL;
266 
267  ret = avformat_match_stream_specifier(avf, avf->streams[i], subselect);
268  if (ret < 0) {
269  av_log(avf, AV_LOG_ERROR,
270  "Invalid stream specifier '%s' for output '%s'\n",
271  subselect, slave);
272  goto end;
273  }
274  if (ret != 0) {
275  fullret = 1; // match
276  break;
277  }
278  }
279  av_freep(&tmp_select);
280 
281  if (fullret == 0) { /* no match */
282  tee_slave->stream_map[i] = -1;
283  continue;
284  }
285  }
286  tee_slave->stream_map[i] = stream_count++;
287 
288  st2 = ff_stream_clone(avf2, st);
289  if (!st2) {
290  ret = AVERROR(ENOMEM);
291  goto end;
292  }
293  }
294 
295  ret = ff_format_output_open(avf2, filename, &options);
296  if (ret < 0) {
297  av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave,
298  av_err2str(ret));
299  goto end;
300  }
301 
302  if ((ret = avformat_write_header(avf2, &options)) < 0) {
303  av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
304  slave, av_err2str(ret));
305  goto end;
306  }
307  tee_slave->header_written = 1;
308 
309  tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(*tee_slave->bsfs));
310  if (!tee_slave->bsfs) {
311  ret = AVERROR(ENOMEM);
312  goto end;
313  }
314 
315  entry = NULL;
316  while (entry = av_dict_iterate(bsf_options, NULL)) {
317  const char *spec = entry->key;
318  if (*spec) {
319  if (strspn(spec, slave_bsfs_spec_sep) != 1) {
320  av_log(avf, AV_LOG_ERROR,
321  "Specifier separator in '%s' is '%c', but only characters '%s' "
322  "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep);
323  ret = AVERROR(EINVAL);
324  goto end;
325  }
326  spec++; /* consume separator */
327  }
328 
329  for (unsigned i = 0; i < avf2->nb_streams; i++) {
330  ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec);
331  if (ret < 0) {
332  av_log(avf, AV_LOG_ERROR,
333  "Invalid stream specifier '%s' in bsfs option '%s' for slave "
334  "output '%s'\n", spec, entry->key, filename);
335  goto end;
336  }
337 
338  if (ret > 0) {
339  av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave "
340  "output '%s'\n", spec, entry->value, i, filename);
341  if (tee_slave->bsfs[i]) {
342  av_log(avf, AV_LOG_WARNING,
343  "Duplicate bsfs specification associated to stream %d of slave "
344  "output '%s', filters will be ignored\n", i, filename);
345  continue;
346  }
347  ret = av_bsf_list_parse_str(entry->value, &tee_slave->bsfs[i]);
348  if (ret < 0) {
349  av_log(avf, AV_LOG_ERROR,
350  "Error parsing bitstream filter sequence '%s' associated to "
351  "stream %d of slave output '%s'\n", entry->value, i, filename);
352  goto end;
353  }
354  }
355  }
356 
357  av_dict_set(&bsf_options, entry->key, NULL, 0);
358  }
359 
360  for (unsigned i = 0; i < avf->nb_streams; i++){
361  int target_stream = tee_slave->stream_map[i];
362  if (target_stream < 0)
363  continue;
364 
365  if (!tee_slave->bsfs[target_stream]) {
366  /* Add pass-through bitstream filter */
367  ret = av_bsf_get_null_filter(&tee_slave->bsfs[target_stream]);
368  if (ret < 0) {
369  av_log(avf, AV_LOG_ERROR,
370  "Failed to create pass-through bitstream filter: %s\n",
371  av_err2str(ret));
372  goto end;
373  }
374  }
375 
376  tee_slave->bsfs[target_stream]->time_base_in = avf->streams[i]->time_base;
377  ret = avcodec_parameters_copy(tee_slave->bsfs[target_stream]->par_in,
378  avf->streams[i]->codecpar);
379  if (ret < 0)
380  goto end;
381 
382  ret = av_bsf_init(tee_slave->bsfs[target_stream]);
383  if (ret < 0) {
384  av_log(avf, AV_LOG_ERROR,
385  "Failed to initialize bitstream filter(s): %s\n",
386  av_err2str(ret));
387  goto end;
388  }
389  }
390 
391  if (options) {
392  entry = NULL;
393  while ((entry = av_dict_iterate(options, entry)))
394  av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
396  goto end;
397  }
398 
399 end:
400  av_free(format);
401  av_free(select);
403  av_dict_free(&bsf_options);
404  av_freep(&tmp_select);
405  return ret;
406 }
407 
408 static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
409 {
410  av_log(log_ctx, log_level, "filename:'%s' format:%s\n",
411  slave->avf->url, slave->avf->oformat->name);
412  for (unsigned i = 0; i < slave->avf->nb_streams; i++) {
413  AVStream *st = slave->avf->streams[i];
414  AVBSFContext *bsf = slave->bsfs[i];
415  const char *bsf_name;
416 
417  av_log(log_ctx, log_level, " stream:%d codec:%s type:%s",
420 
421  bsf_name = bsf->filter->priv_class ?
422  bsf->filter->priv_class->item_name(bsf) : bsf->filter->name;
423  av_log(log_ctx, log_level, " bsfs: %s\n", bsf_name);
424  }
425 }
426 
427 static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
428 {
429  TeeContext *tee = avf->priv_data;
430  TeeSlave *tee_slave = &tee->slaves[slave_idx];
431 
432  tee->nb_alive--;
433 
434  close_slave(tee_slave);
435 
436  if (!tee->nb_alive) {
437  av_log(avf, AV_LOG_ERROR, "All tee outputs failed.\n");
438  return err_n;
439  } else if (tee_slave->on_fail == ON_SLAVE_FAILURE_ABORT) {
440  av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed, aborting.\n", slave_idx);
441  return err_n;
442  } else {
443  av_log(avf, AV_LOG_ERROR, "Slave muxer #%u failed: %s, continuing with %u/%u slaves.\n",
444  slave_idx, av_err2str(err_n), tee->nb_alive, tee->nb_slaves);
445  return 0;
446  }
447 }
448 
450 {
451  TeeContext *tee = avf->priv_data;
452  unsigned nb_slaves = 0;
453  const char *filename = avf->url;
454  char **slaves = NULL;
455  int ret;
456 
457  while (*filename) {
458  char *slave = av_get_token(&filename, slave_delim);
459  if (!slave) {
460  ret = AVERROR(ENOMEM);
461  goto fail;
462  }
463  ret = av_dynarray_add_nofree(&slaves, &nb_slaves, slave);
464  if (ret < 0) {
465  av_free(slave);
466  goto fail;
467  }
468  if (strspn(filename, slave_delim))
469  filename++;
470  }
471 
472  if (!FF_ALLOCZ_TYPED_ARRAY(tee->slaves, nb_slaves)) {
473  ret = AVERROR(ENOMEM);
474  goto fail;
475  }
476  tee->nb_slaves = tee->nb_alive = nb_slaves;
477 
478  for (unsigned i = 0; i < nb_slaves; i++) {
479 
480  tee->slaves[i].use_fifo = tee->use_fifo;
481  ret = av_dict_copy(&tee->slaves[i].fifo_options, tee->fifo_options, 0);
482  if (ret < 0)
483  goto fail;
484 
485  if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) {
487  if (ret < 0)
488  goto fail;
489  } else {
490  log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE);
491  }
492  av_freep(&slaves[i]);
493  }
494 
495  for (unsigned i = 0; i < avf->nb_streams; i++) {
496  int mapped = 0;
497  for (unsigned j = 0; j < tee->nb_slaves; j++)
498  if (tee->slaves[j].avf)
499  mapped += tee->slaves[j].stream_map[i] >= 0;
500  if (!mapped)
501  av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
502  "to any slave.\n", i);
503  }
504  av_free(slaves);
505  return 0;
506 
507 fail:
508  for (unsigned i = 0; i < nb_slaves; i++)
509  av_freep(&slaves[i]);
510  close_slaves(avf);
511  av_free(slaves);
512  return ret;
513 }
514 
516 {
517  TeeContext *tee = avf->priv_data;
518  int ret_all = 0, ret;
519 
520  for (unsigned i = 0; i < tee->nb_slaves; i++) {
521  if ((ret = close_slave(&tee->slaves[i])) < 0) {
523  if (!ret_all && ret < 0)
524  ret_all = ret;
525  }
526  }
527  av_freep(&tee->slaves);
528  return ret_all;
529 }
530 
532 {
533  TeeContext *tee = avf->priv_data;
534  AVPacket *const pkt2 = ffformatcontext(avf)->pkt;
535  int ret_all = 0, ret;
536  unsigned s;
537  int s2;
538 
539  for (unsigned i = 0; i < tee->nb_slaves; i++) {
540  AVFormatContext *avf2 = tee->slaves[i].avf;
541  AVBSFContext *bsfs;
542 
543  if (!avf2)
544  continue;
545 
546  /* Flush slave if pkt is NULL*/
547  if (!pkt) {
549  if (ret < 0) {
551  if (!ret_all && ret < 0)
552  ret_all = ret;
553  }
554  continue;
555  }
556 
557  s = pkt->stream_index;
558  s2 = tee->slaves[i].stream_map[s];
559  if (s2 < 0)
560  continue;
561 
562  if ((ret = av_packet_ref(pkt2, pkt)) < 0) {
563  if (!ret_all)
564  ret_all = ret;
565  continue;
566  }
567  bsfs = tee->slaves[i].bsfs[s2];
568  pkt2->stream_index = s2;
569 
570  ret = av_bsf_send_packet(bsfs, pkt2);
571  if (ret < 0) {
572  av_packet_unref(pkt2);
573  av_log(avf, AV_LOG_ERROR, "Error while sending packet to bitstream filter: %s\n",
574  av_err2str(ret));
576  if (!ret_all && ret < 0)
577  ret_all = ret;
578  }
579 
580  while(1) {
581  ret = av_bsf_receive_packet(bsfs, pkt2);
582  if (ret == AVERROR(EAGAIN)) {
583  ret = 0;
584  break;
585  } else if (ret < 0) {
586  break;
587  }
588 
590  avf2->streams[s2]->time_base);
591  ret = av_interleaved_write_frame(avf2, pkt2);
592  if (ret < 0)
593  break;
594  };
595 
596  if (ret < 0) {
598  if (!ret_all && ret < 0)
599  ret_all = ret;
600  }
601  }
602  return ret_all;
603 }
604 
606  .p.name = "tee",
607  .p.long_name = NULL_IF_CONFIG_SMALL("Multiple muxer tee"),
608  .priv_data_size = sizeof(TeeContext),
612  .p.priv_class = &tee_muxer_class,
614  .p.flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
615 #else
616  .p.flags = AVFMT_NOFILE | AVFMT_TS_NEGATIVE,
617 #endif
618  .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
619 };
FF_ALLOCZ_TYPED_ARRAY
#define FF_ALLOCZ_TYPED_ARRAY(p, nelem)
Definition: internal.h:78
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:429
AVBSFContext::par_in
AVCodecParameters * par_in
Parameters of the input stream.
Definition: bsf.h:90
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
ON_SLAVE_FAILURE_IGNORE
@ ON_SLAVE_FAILURE_IGNORE
Definition: tee.c:35
entry
#define entry
Definition: aom_film_grain_template.c:66
AVOutputFormat::name
const char * name
Definition: avformat.h:510
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
TeeSlave::bsfs
AVBSFContext ** bsfs
bitstream filters per stream
Definition: tee.c:42
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:51
TeeSlave::stream_map
int * stream_map
map from input to output streams indexes, disabled output streams are set to -1
Definition: tee.c:50
ffformatcontext
static av_always_inline FFFormatContext * ffformatcontext(AVFormatContext *s)
Definition: internal.h:127
AVBitStreamFilter::name
const char * name
Definition: bsf.h:112
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:207
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1368
AVFormatContext::strict_std_compliance
int strict_std_compliance
Allow non-standard and experimental extension.
Definition: avformat.h:1657
parse_slave_fifo_options
static int parse_slave_fifo_options(const char *fifo_options, TeeSlave *tee_slave)
Definition: tee.c:114
OFFSET
#define OFFSET(x)
Definition: tee.c:67
ff_tee_parse_slave_options
int ff_tee_parse_slave_options(void *log, char *slave, AVDictionary **options, char **filename)
Definition: tee_common.c:33
AVOption
AVOption.
Definition: opt.h:429
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:75
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:225
tee_write_trailer
static int tee_write_trailer(AVFormatContext *avf)
Definition: tee.c:515
AVDictionary
Definition: dict.c:34
tee_write_packet
static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
Definition: tee.c:531
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:52
TeeContext::use_fifo
int use_fifo
Definition: tee.c:59
TeeContext::nb_slaves
unsigned nb_slaves
Definition: tee.c:56
AVBSFContext
The bitstream filter state.
Definition: bsf.h:68
FFOutputFormat::p
AVOutputFormat p
The public AVOutputFormat.
Definition: mux.h:65
ON_SLAVE_FAILURE_ABORT
@ ON_SLAVE_FAILURE_ABORT
Definition: tee.c:34
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:1573
bsf.h
fail
#define fail()
Definition: checkasm.h:188
AVERROR_OPTION_NOT_FOUND
#define AVERROR_OPTION_NOT_FOUND
Option not found.
Definition: error.h:63
parse_slave_fifo_policy
static int parse_slave_fifo_policy(const char *use_fifo, TeeSlave *tee_slave)
Definition: tee.c:100
PROCESS_OPTION
#define PROCESS_OPTION(option, function, on_error)
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:79
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
AVFormatContext::metadata
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1535
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:62
s
#define s(width, name)
Definition: cbs_vp9.c:198
tee_muxer_class
static const AVClass tee_muxer_class
Definition: tee.c:76
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1451
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
slave_bsfs_spec_sep
static const char *const slave_bsfs_spec_sep
Definition: tee.c:64
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:178
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
TeeContext::slaves
TeeSlave * slaves
Definition: tee.c:58
AVBSFContext::time_base_in
AVRational time_base_in
The timebase used for the timestamps of the input packets.
Definition: bsf.h:102
TeeContext::fifo_options
AVDictionary * fifo_options
Definition: tee.c:60
slave_select_sep
static const char *const slave_select_sep
Definition: tee.c:65
AVFormatContext::opaque
void * opaque
User data.
Definition: avformat.h:1862
tee_process_slave_failure
static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, int err_n)
Definition: tee.c:427
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:488
AVFormatContext
Format I/O context.
Definition: avformat.h:1300
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:771
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
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:149
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
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:787
NULL
#define NULL
Definition: coverity.c:32
av_bsf_receive_packet
int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt)
Retrieve a filtered packet.
Definition: bsf.c:230
write_trailer
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:101
AV_OPT_TYPE_DICT
@ AV_OPT_TYPE_DICT
Underlying C type is AVDictionary*.
Definition: opt.h:290
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
close_slave
static int close_slave(TeeSlave *tee_slave)
Definition: tee.c:119
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1342
TeeContext::nb_alive
unsigned nb_alive
Definition: tee.c:57
ff_tee_muxer
const FFOutputFormat ff_tee_muxer
Definition: tee.c:605
AVBitStreamFilter::priv_class
const AVClass * priv_class
A class for the private data, used to declare bitstream filter private AVOptions.
Definition: bsf.h:130
FFOutputFormat
Definition: mux.h:61
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: packet.c:437
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:352
TeeSlave::on_fail
SlaveFailurePolicy on_fail
Definition: tee.c:44
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1356
TeeSlave
Definition: tee.c:40
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: avformat.c:693
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:94
FF_OFMT_FLAG_ALLOW_FLUSH
#define FF_OFMT_FLAG_ALLOW_FLUSH
This flag indicates that the muxer stores data internally and supports flushing it.
Definition: mux.h:38
av_bsf_send_packet
int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
Submit a packet for filtering.
Definition: bsf.c:202
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:122
AVFormatContext::url
char * url
input or output URL.
Definition: avformat.h:1416
close_slaves
static void close_slaves(AVFormatContext *avf)
Definition: tee.c:145
AVFMT_NOFILE
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:468
ff_format_io_close
int ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: avformat.c:958
TeeSlave::fifo_options
AVDictionary * fifo_options
Definition: tee.c:46
DEFAULT_SLAVE_FAILURE_POLICY
#define DEFAULT_SLAVE_FAILURE_POLICY
Definition: tee.c:38
TeeContext
Definition: tee.c:54
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:223
options
static const AVOption options[]
Definition: tee.c:68
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: packet.c:533
TeeSlave::use_fifo
int use_fifo
Definition: tee.c:45
avcodec_get_name
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Definition: utils.c:409
open_slave
static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
Definition: tee.c:155
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:1298
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
TeeSlave::header_written
int header_written
Definition: tee.c:51
else
else
Definition: snow.txt:125
AVBSFContext::time_base_out
AVRational time_base_out
The timebase used for the timestamps of the output packets.
Definition: bsf.h:108
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
FF_API_ALLOW_FLUSH
#define FF_API_ALLOW_FLUSH
Definition: version_major.h:46
write_packet
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
Definition: ffmpeg_mux.c:209
AVFMT_TS_NEGATIVE
#define AVFMT_TS_NEGATIVE
Format allows muxing negative timestamps.
Definition: avformat.h:494
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:748
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:80
av_bsf_get_null_filter
int av_bsf_get_null_filter(AVBSFContext **bsf)
Get null/pass-through bitstream filter.
Definition: bsf.c:553
AVFormatContext::oformat
const struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1319
avformat.h
parse_slave_failure_policy_option
static int parse_slave_failure_policy_option(const char *opt, TeeSlave *tee_slave)
Definition: tee.c:83
log_slave
static void log_slave(TeeSlave *slave, void *log_ctx, int log_level)
Definition: tee.c:408
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:315
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:28
SlaveFailurePolicy
SlaveFailurePolicy
Definition: tee.c:33
tee_write_header
static int tee_write_header(AVFormatContext *avf)
Definition: tee.c:449
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:143
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:345
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: avformat.c:149
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:200
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:1903
slave_delim
static const char *const slave_delim
Definition: tee.c:63
AVPacket::stream_index
int stream_index
Definition: packet.h:541
AVBSFContext::filter
const struct AVBitStreamFilter * filter
The bitstream filter this context is an instance of.
Definition: bsf.h:77
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
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:526
avutil.h
mem.h
TeeSlave::avf
AVFormatContext * avf
Definition: tee.c:41
FFFormatContext::pkt
AVPacket * pkt
Used to hold temporary packets for the generic demuxing code.
Definition: internal.h:111
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVDictionaryEntry
Definition: dict.h:89
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:55
ff_stream_clone
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:317
AVPacket
This structure stores compressed data.
Definition: packet.h:516
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
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:1283
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
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:88
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:250
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:237
AVFormatContext::io_close2
int(* io_close2)(struct AVFormatContext *s, AVIOContext *pb)
A callback for closing the streams opened with AVFormatContext.io_open().
Definition: avformat.h:1917
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: mux_utils.c:128
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
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:86
write_header
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:348
avformat_alloc_output_context2
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
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1328
av_dict_iterate
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition: dict.c:44
avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: codec_par.c:106
mux.h