1 /*
2 * Icecast protocol for FFmpeg
3 * Copyright (c) 2014 Marvin Scholz
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
9 * License 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 GNU
15 * Lesser General Public License for more details.
16 *
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
20 */
21
22
26
29
30
36 // Options
48
49 #define DEFAULT_ICE_USER "source"
50
51 #define NOT_EMPTY(s) (s && s[0])
52
53 #define OFFSET(x) offsetof(IcecastContext, x)
54 #define E AV_OPT_FLAG_ENCODING_PARAM
55
65 {
"legacy_icecast",
"use legacy SOURCE method, for Icecast < v2.4",
OFFSET(legacy_icecast),
AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1,
E },
68 };
69
70
72 {
75 }
76
78 {
81 return 0;
82 }
83
85 {
87
88 // Dict to set options that we pass to the HTTP protocol
90
91 // URI part variables
92 char h_url[1024], host[1024], auth[1024], path[1024];
95 AVBPrint bp;
96
99
101
102 // Build header strings
104 cat_header(&bp,
"Ice-Description",
s->description);
107 cat_header(&bp,
"Ice-Public",
s->public ?
"1" :
"0");
111 }
114
115 // Set options
116 av_dict_set(&opt_dict,
"method",
s->legacy_icecast ?
"SOURCE" :
"PUT", 0);
120 av_dict_set(&opt_dict,
"send_expect_100",
s->legacy_icecast ?
"-1" :
"1", 0);
122 av_dict_set(&opt_dict,
"content_type",
s->content_type, 0);
123 else
124 av_dict_set(&opt_dict,
"content_type",
"audio/mpeg", 0);
127
128 // Parse URI
130 &port, path, sizeof(path), uri);
131
132 // Check for auth data in URI
133 if (auth[0]) {
134 char *sep = strchr(auth, ':');
135 if (sep) {
136 *sep = 0;
137 sep++;
141 }
145 }
146 }
150 }
151 }
152
153 // Build new authstring
155 "%s:%s",
157 s->pass ?
s->pass :
"");
158
159 // Check for mountpoint (path)
160 if (!path[0] || strcmp(path, "/") == 0) {
164 }
165
166 // Build new URI for passing to http protocol
168 s->tls ?
"https" :
"http",
169 auth, host, port, "%s", path);
170 // Finally open http proto handler
172 &opt_dict,
h->protocol_whitelist,
h->protocol_blacklist,
h);
173
177
179 }
180
182 {
184 if (!
s->send_started) {
186 if (!
s->content_type &&
size >= 8) {
187 static const uint8_t oggs[4] = { 0x4F, 0x67, 0x67, 0x53 };
188 static const uint8_t webm[4] = { 0x1A, 0x45, 0xDF, 0xA3 };
189 static const uint8_t opus[8] = { 0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64 };
190 if (memcmp(buf, oggs, sizeof(oggs)) == 0) {
193 } else if (memcmp(buf, opus, sizeof(opus)) == 0) {
196 } else if (memcmp(buf, webm, sizeof(webm)) == 0) {
199 } else {
202 }
203 }
204 }
206 }
207
213 };
214
223 };