tee.c
Go to the documentation of this file.
1 /*
2  * Tee pesudo-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 "avformat.h"
27 
28 #define MAX_SLAVES 16
29 
30 typedef struct TeeContext {
31  const AVClass *class;
32  unsigned nb_slaves;
34 } TeeContext;
35 
36 static const char *const slave_delim = "|";
37 static const char *const slave_opt_open = "[";
38 static const char *const slave_opt_close = "]";
39 static const char *const slave_opt_delim = ":]"; /* must have the close too */
40 
41 static const AVClass tee_muxer_class = {
42  .class_name = "Tee muxer",
43  .item_name = av_default_item_name,
44  .version = LIBAVUTIL_VERSION_INT,
45 };
46 
47 static int parse_slave_options(void *log, char *slave,
48  AVDictionary **options, char **filename)
49 {
50  const char *p;
51  char *key, *val;
52  int ret;
53 
54  if (!strspn(slave, slave_opt_open)) {
55  *filename = slave;
56  return 0;
57  }
58  p = slave + 1;
59  if (strspn(p, slave_opt_close)) {
60  *filename = (char *)p + 1;
61  return 0;
62  }
63  while (1) {
64  ret = av_opt_get_key_value(&p, "=", slave_opt_delim, 0, &key, &val);
65  if (ret < 0) {
66  av_log(log, AV_LOG_ERROR, "No option found near \"%s\"\n", p);
67  goto fail;
68  }
69  ret = av_dict_set(options, key, val,
71  if (ret < 0)
72  goto fail;
73  if (strspn(p, slave_opt_close))
74  break;
75  p++;
76  }
77  *filename = (char *)p + 1;
78  return 0;
79 
80 fail:
81  av_dict_free(options);
82  return ret;
83 }
84 
85 static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf)
86 {
87  int i, ret;
89  AVDictionaryEntry *entry;
90  char *filename;
91  char *format = NULL;
92  AVFormatContext *avf2 = NULL;
93  AVStream *st, *st2;
94 
95  if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
96  return ret;
97  if ((entry = av_dict_get(options, "f", NULL, 0))) {
98  format = entry->value;
99  entry->value = NULL; /* prevent it from being freed */
100  av_dict_set(&options, "f", NULL, 0);
101  }
102 
103  ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
104  if (ret < 0)
105  goto fail;
106  av_free(format);
107 
108  for (i = 0; i < avf->nb_streams; i++) {
109  st = avf->streams[i];
110  if (!(st2 = avformat_new_stream(avf2, NULL))) {
111  ret = AVERROR(ENOMEM);
112  goto fail;
113  }
114  st2->id = st->id;
115  st2->r_frame_rate = st->r_frame_rate;
116  st2->time_base = st->time_base;
117  st2->start_time = st->start_time;
118  st2->duration = st->duration;
119  st2->nb_frames = st->nb_frames;
120  st2->disposition = st->disposition;
122  st2->avg_frame_rate = st->avg_frame_rate;
123  av_dict_copy(&st2->metadata, st->metadata, 0);
124  if ((ret = avcodec_copy_context(st2->codec, st->codec)) < 0)
125  goto fail;
126  }
127 
128  if (!(avf2->oformat->flags & AVFMT_NOFILE)) {
129  if ((ret = avio_open(&avf2->pb, filename, AVIO_FLAG_WRITE)) < 0) {
130  av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n",
131  slave, av_err2str(ret));
132  goto fail;
133  }
134  }
135 
136  if ((ret = avformat_write_header(avf2, &options)) < 0) {
137  av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
138  slave, av_err2str(ret));
139  goto fail;
140  }
141  if (options) {
142  entry = NULL;
143  while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX)))
144  av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
146  goto fail;
147  }
148 
149  *ravf = avf2;
150  return 0;
151 
152 fail:
153  av_dict_free(&options);
154  return ret;
155 }
156 
157 static void close_slaves(AVFormatContext *avf)
158 {
159  TeeContext *tee = avf->priv_data;
160  AVFormatContext *avf2;
161  unsigned i;
162 
163  for (i = 0; i < tee->nb_slaves; i++) {
164  avf2 = tee->slaves[i];
165  avio_close(avf2->pb);
166  avf2->pb = NULL;
167  avformat_free_context(avf2);
168  tee->slaves[i] = NULL;
169  }
170 }
171 
173 {
174  TeeContext *tee = avf->priv_data;
175  unsigned nb_slaves = 0, i;
176  const char *filename = avf->filename;
177  char *slaves[MAX_SLAVES];
178  int ret;
179 
180  while (*filename) {
181  if (nb_slaves == MAX_SLAVES) {
182  av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n",
183  MAX_SLAVES);
184  ret = AVERROR_PATCHWELCOME;
185  goto fail;
186  }
187  if (!(slaves[nb_slaves++] = av_get_token(&filename, slave_delim))) {
188  ret = AVERROR(ENOMEM);
189  goto fail;
190  }
191  if (strspn(filename, slave_delim))
192  filename++;
193  }
194 
195  for (i = 0; i < nb_slaves; i++) {
196  if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0)
197  goto fail;
198  av_freep(&slaves[i]);
199  }
200 
201  tee->nb_slaves = nb_slaves;
202  return 0;
203 
204 fail:
205  for (i = 0; i < nb_slaves; i++)
206  av_freep(&slaves[i]);
207  close_slaves(avf);
208  return ret;
209 }
210 
212 {
213  TeeContext *tee = avf->priv_data;
214  AVFormatContext *avf2;
215  int ret_all = 0, ret;
216  unsigned i;
217 
218  for (i = 0; i < tee->nb_slaves; i++) {
219  avf2 = tee->slaves[i];
220  if ((ret = av_write_trailer(avf2)) < 0)
221  if (!ret_all)
222  ret_all = ret;
223  if (!(avf2->oformat->flags & AVFMT_NOFILE)) {
224  if ((ret = avio_close(avf2->pb)) < 0)
225  if (!ret_all)
226  ret_all = ret;
227  avf2->pb = NULL;
228  }
229  }
230  close_slaves(avf);
231  return ret_all;
232 }
233 
235 {
236  TeeContext *tee = avf->priv_data;
237  AVFormatContext *avf2;
238  AVPacket pkt2;
239  int ret_all = 0, ret;
240  unsigned i, s;
241  AVRational tb, tb2;
242 
243  for (i = 0; i < tee->nb_slaves; i++) {
244  avf2 = tee->slaves[i];
245  s = pkt->stream_index;
246  if (s >= avf2->nb_streams) {
247  if (!ret_all)
248  ret_all = AVERROR(EINVAL);
249  continue;
250  }
251  if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
252  (ret = av_dup_packet(&pkt2))< 0)
253  if (!ret_all) {
254  ret = ret_all;
255  continue;
256  }
257  tb = avf ->streams[s]->time_base;
258  tb2 = avf2->streams[s]->time_base;
259  pkt2.pts = av_rescale_q(pkt->pts, tb, tb2);
260  pkt2.dts = av_rescale_q(pkt->dts, tb, tb2);
261  pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
262  if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0)
263  if (!ret_all)
264  ret_all = ret;
265  }
266  return ret_all;
267 }
268 
270  .name = "tee",
271  .long_name = NULL_IF_CONFIG_SMALL("Multiple muxer tee"),
272  .priv_data_size = sizeof(TeeContext),
276  .priv_class = &tee_muxer_class,
277  .flags = AVFMT_NOFILE,
278 };
int avio_open(AVIOContext **s, const char *url, int flags)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:799
static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
Definition: tee.c:234
const char * s
Definition: avisynth_c.h:668
struct TeeContext TeeContext
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file ensuring correct interleaving.
Definition: mux.c:726
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:383
av_default_item_name
static const char *const slave_opt_delim
Definition: tee.c:39
static int write_packet(AVFormatContext *s, AVPacket *pkt)
static int tee_write_trailer(AVFormatContext *avf)
Definition: tee.c:211
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:709
int av_copy_packet(AVPacket *dst, AVPacket *src)
Copy packet, including contents.
Definition: avpacket.c:236
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
external API header
AVDictionaryEntry * av_dict_get(AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:39
int av_dup_packet(AVPacket *pkt)
Definition: avpacket.c:221
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
Copy the settings of the source AVCodecContext into the destination AVCodecContext.
static const char *const slave_delim
Definition: tee.c:36
#define AV_DICT_DONT_STRDUP_KEY
Take ownership of a key that&#39;s been allocated with av_malloc() and children.
Definition: dict.h:69
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
static const char *const slave_opt_close
Definition: tee.c:38
static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf)
Definition: tee.c:85
Format I/O context.
Definition: avformat.h:944
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:55
AVOutputFormat ff_tee_muxer
Definition: tee.c:269
int flags
can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_RAWPICTURE, AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, AVFMT_TS_NONSTRICT
Definition: avformat.h:397
AVOptions.
static AVPacket pkt
Definition: demuxing.c:56
int id
Format-specific stream ID.
Definition: avformat.h:650
static void close_slaves(AVFormatContext *avf)
Definition: tee.c:157
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
AVStream ** streams
Definition: avformat.h:992
int duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
const OptionDef options[]
Definition: ffserver.c:4697
static int parse_slave_options(void *log, char *slave, AVDictionary **options, char **filename)
Definition: tee.c:47
static int write_trailer(AVFormatContext *s)
struct AVOutputFormat * oformat
Definition: avformat.h:958
int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename)
Allocate an AVFormatContext for an output format.
Definition: mux.c:125
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:130
void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:176
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:821
unsigned nb_slaves
Definition: tee.c:32
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:162
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:716
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:148
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:991
char filename[1024]
input or output filename
Definition: avformat.h:994
static const AVClass tee_muxer_class
Definition: tee.c:41
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that&#39;s been allocated with av_malloc() and chilren.
Definition: dict.h:72
ret
Definition: avfilter.c:821
const char * name
Definition: avformat.h:378
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:110
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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
AVDictionary * metadata
Definition: avformat.h:711
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
Stream structure.
Definition: avformat.h:643
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
NULL
Definition: eval.c:55
Definition: tee.c:30
AVIOContext * pb
I/O context.
Definition: avformat.h:977
static const char *const slave_opt_open
Definition: tee.c:37
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
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:62
Describe the class of an AVClass context structure.
Definition: log.h:50
synthesis window for stochastic i
rational number numerator/denominator
Definition: rational.h:43
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
static int flags
Definition: cpu.c:23
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:696
Main libavformat public API header.
#define MAX_SLAVES
Definition: tee.c:28
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:345
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base...
Definition: avformat.h:689
int disposition
AV_DISPOSITION_* bit field.
Definition: avformat.h:700
int64_t nb_frames
number of frames in this stream if known or 0
Definition: avformat.h:698
char * key
Definition: dict.h:81
AVFormatContext * slaves[MAX_SLAVES]
Definition: tee.c:33
#define AVERROR_OPTION_NOT_FOUND
Option not found.
Definition: error.h:61
char * value
Definition: dict.h:82
int av_opt_get_key_value(const char **ropts, const char *key_val_sep, const char *pairs_sep, unsigned flags, char **rkey, char **rval)
Extract a key-value pair from the beginning of a string.
Definition: opt.c:1120
void * priv_data
Format private data.
Definition: avformat.h:964
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:470
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:769
#define AV_DICT_IGNORE_SUFFIX
Definition: dict.h:68
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:679
AVRational r_frame_rate
Real base framerate of the stream.
Definition: avformat.h:738
This structure stores compressed data.
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
static int tee_write_header(AVFormatContext *avf)
Definition: tee.c:172
#define tb
Definition: regdef.h:68