1 /*
2 * RTMP network protocol
3 * Copyright (c) 2010 Howard Chu
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 /**
23 * @file
24 * RTMP protocol based on http://rtmpdump.mplayerhq.hu/ librtmp
25 */
26
31 #if CONFIG_NETWORK
33 #endif
35
36 #include <librtmp/rtmp.h>
37 #include <librtmp/log.h>
38
56
58 {
59 switch (level) {
60 default:
67 }
68
71 }
72
74 {
77
78 RTMP_Close(r);
80 return 0;
81 }
82
83 /**
84 * Open RTMP connection and verify that the stream can be played.
85 *
86 * URL syntax: rtmp://server[:port][/app][/playpath][ keyword=value]...
87 * where 'app' is first one or two directories in the path
88 * (e.g. /ondemand/, /flash/live/, etc.)
89 * and 'playpath' is a file name (the rest of the path,
90 * may be prefixed with "mp4:")
91 *
92 * Additional RTMP library options may be appended as
93 * space-separated key-value pairs.
94 */
96 {
102
104 default:
111 }
112 RTMP_LogSetLevel(
level);
114
115 if (ctx->
app) len += strlen(ctx->
app) +
sizeof(
" app=");
116 if (ctx->
tcurl) len += strlen(ctx->
tcurl) +
sizeof(
" tcUrl=");
117 if (ctx->
pageurl) len += strlen(ctx->
pageurl) +
sizeof(
" pageUrl=");
119
121 char *sep, *p = ctx->
conn;
123
124 while (p) {
125 options++;
126 p += strspn(p, " ");
127 if (!*p)
128 break;
129 sep = strchr(p, ' ');
130 if (sep)
131 p = sep + 1;
132 else
133 break;
134 }
135 len += options * sizeof(" conn=");
136 len += strlen(ctx->
conn);
137 }
138
140 len += strlen(ctx->
playpath) +
sizeof(
" playpath=");
142 len += sizeof(" live=1");
144 len += strlen(ctx->
subscribe) +
sizeof(
" subscribe=");
145
148
150 len += sizeof(" swfUrl=");
151
153 len += strlen(ctx->
swfverify) +
sizeof(
" swfVfy=1");
154 else
155 len += strlen(ctx->
swfurl);
156 }
157
160
165 }
169 }
173 }
177 }
181 }
183 char *sep, *p = ctx->
conn;
184 while (p) {
186 p += strspn(p, " ");
187 if (!*p)
188 break;
189 sep = strchr(p, ' ');
190 if (sep)
191 *sep = '0円';
193
194 if (sep)
195 p = sep + 1;
196 }
197 }
201 }
207 }
211 }
214
218 } else {
220 }
221 }
222
223 RTMP_Init(r);
224 if (!RTMP_SetupURL(r, filename)) {
226 goto fail;
227 }
228
230 RTMP_EnableWrite(r);
231
232 if (!RTMP_Connect(r,
NULL) || !RTMP_ConnectStream(r, 0)) {
234 goto fail;
235 }
236
237 #if CONFIG_NETWORK
238 if (ctx->
buffer_size >= 0 && (flags & AVIO_FLAG_WRITE)) {
240 setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
241 }
242 #endif
243
245 return 0;
246 fail:
248 if (rc)
249 RTMP_Close(r);
250
251 return rc;
252 }
253
255 {
257 RTMP *
r = &ctx->
rtmp;
258
259 return RTMP_Write(r, buf, size);
260 }
261
263 {
265 RTMP *
r = &ctx->
rtmp;
266
267 return RTMP_Read(r, buf, size);
268 }
269
271 {
273 RTMP *
r = &ctx->
rtmp;
274
275 if (!RTMP_Pause(r, pause))
277 return 0;
278 }
279
281 int64_t timestamp,
int flags)
282 {
284 RTMP *
r = &ctx->
rtmp;
285
288
289 /* seeks are in milliseconds */
290 if (stream_index < 0)
293
294 if (!RTMP_SendSeek(r, timestamp))
296 return timestamp;
297 }
298
300 {
302 RTMP *
r = &ctx->
rtmp;
303
304 return RTMP_Socket(r);
305 }
306
307 #define OFFSET(x) offsetof(LibRTMPContext, x)
308 #define DEC AV_OPT_FLAG_DECODING_PARAM
309 #define ENC AV_OPT_FLAG_ENCODING_PARAM
312 {
"rtmp_buffer",
"Set buffer time in milliseconds. The default is 3000.",
OFFSET(client_buffer_time),
AV_OPT_TYPE_STRING, {.str =
"3000"}, 0, 0,
DEC|
ENC},
315 {
"rtmp_live",
"Specify that the media is a live stream.",
OFFSET(live),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_live"},
319 {
"rtmp_pageurl",
"URL of the web page in which the media was embedded. By default no value will be sent.",
OFFSET(pageurl),
AV_OPT_TYPE_STRING, {.str =
NULL }, 0, 0,
DEC},
321 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str =
NULL }, 0, 0,
DEC},
323 {
"rtmp_swfverify",
"URL to player swf file, compute hash/size automatically. (unimplemented)",
OFFSET(swfverify),
AV_OPT_TYPE_STRING, {.str =
NULL }, 0, 0,
DEC},
325 #if CONFIG_NETWORK
327 #endif
329 };
330
331 #define RTMP_CLASS(flavor)\
332 static const AVClass lib ## flavor ## _class = {\
333 .class_name = "lib" #flavor " protocol",\
334 .item_name = av_default_item_name,\
335 .option = options,\
336 .version = LIBAVUTIL_VERSION_INT,\
337 };
338
350 .priv_data_class = &librtmp_class,
352 };
353
365 .priv_data_class = &librtmpt_class,
367 };
368
380 .priv_data_class = &librtmpe_class,
382 };
383
395 .priv_data_class = &librtmpte_class,
397 };
398
410 .priv_data_class = &librtmps_class,
412 };