3 * Copyright (c) 2016 Michael Niedermayer
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
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 GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/avstring.h"
25 #include "libavutil/dict.h"
26 #include "libavutil/error.h"
27 #include "libavutil/mem.h"
28 #include "tee_common.h"
31 typedef struct ChildContext
{
32 URLContext
*url_context
;
35 typedef struct TeeContext
{
40 static const char *const child_delim
= "|";
42 static int tee_write(URLContext
*h
, const unsigned char *buf
, int size
)
44 TeeContext
*c
= h
->priv_data
;
48 for (i
=0; i
<c
->child_count
; i
++) {
49 int ret
= ffurl_write(c
->child
[i
].url_context
, buf
, size
);
56 static int tee_close(URLContext
*h
)
58 TeeContext
*c
= h
->priv_data
;
62 for (i
=0; i
<c
->child_count
; i
++) {
63 int ret
= ffurl_closep(&c
->child
[i
].url_context
);
73 static int tee_open(URLContext
*h
, const char *filename
, int flags
)
75 TeeContext
*c
= h
->priv_data
;
78 av_strstart(filename
, "tee:", &filename
);
81 char *child_string
= av_get_token(&filename
, child_delim
);
82 char *child_name
= NULL
;
84 AVDictionary
*options
= NULL
;
86 ret
= AVERROR(ENOMEM
);
90 tmp
= av_realloc_array(c
->child
, c
->child_count
+ 1, sizeof(*c
->child
));
92 ret
= AVERROR(ENOMEM
);
96 memset(&c
->child
[c
->child_count
], 0, sizeof(c
->child
[c
->child_count
]));
98 ret
= ff_tee_parse_slave_options(h
, child_string
, &options
, &child_name
);
102 ret
= ffurl_open_whitelist(&c
->child
[c
->child_count
].url_context
, child_name
, flags
,
103 &h
->interrupt_callback
, &options
,
104 h
->protocol_whitelist
, h
->protocol_blacklist
,
107 av_freep(&child_string
);
108 av_dict_free(&options
);
113 if (strspn(filename
, child_delim
))
118 for (i
=0; i
<c
->child_count
; i
++) {
119 h
->is_streamed
|= c
->child
[i
].url_context
->is_streamed
;
122 h
->max_packet_size
= 0;
123 for (i
= 0; i
< c
->child_count
; i
++) {
124 int max
= c
->child
[i
].url_context
->max_packet_size
;
128 if (!h
->max_packet_size
)
129 h
->max_packet_size
= max
;
130 else if (h
->max_packet_size
> max
)
131 h
->max_packet_size
= max
;
139 const URLProtocol ff_tee_protocol
= {
141 .url_open
= tee_open
,
142 .url_write
= tee_write
,
143 .url_close
= tee_close
,
144 .priv_data_size
= sizeof(TeeContext
),
145 .default_whitelist
= "crypto,file,http,https,httpproxy,rtmp,tcp,tls"