FFmpeg
Loading...
Searching...
No Matches
librtmp.c
Go to the documentation of this file.
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
27#include "libavutil/avstring.h"
28#include "libavutil/bprint.h"
30#include "libavutil/opt.h"
31#include "avformat.h"
32#if CONFIG_NETWORK
33#include "network.h"
34#endif
35#include "url.h"
36
37#include <librtmp/rtmp.h>
38#include <librtmp/log.h>
39
40typedef struct LibRTMPContext {
41 const AVClass *class;
42 AVBPrint filename;
43 RTMP rtmp;
44 char *app;
45 char *conn;
46 char *subscribe;
47 char *playpath;
48 char *tcurl;
49 char *flashver;
50 char *swfurl;
51 char *swfverify;
52 char *pageurl;
54 int live;
57
58static void rtmp_log(int level, const char *fmt, va_list args)
59{
60 switch (level) {
61 default:
62 case RTMP_LOGCRIT: level = AV_LOG_FATAL; break;
63 case RTMP_LOGERROR: level = AV_LOG_ERROR; break;
64 case RTMP_LOGWARNING: level = AV_LOG_WARNING; break;
65 case RTMP_LOGINFO: level = AV_LOG_INFO; break;
66 case RTMP_LOGDEBUG: level = AV_LOG_VERBOSE; break;
67 case RTMP_LOGDEBUG2: level = AV_LOG_DEBUG; break;
68 }
69
70 av_vlog(NULL, level, fmt, args);
71 av_log(NULL, level, "\n");
72}
73
75{
76 LibRTMPContext *ctx = s->priv_data;
77 RTMP *r = &ctx->rtmp;
78
79 RTMP_Close(r);
80 av_bprint_finalize(&ctx->filename, NULL);
81 return 0;
82}
83
84/**
85 * Open RTMP connection and verify that the stream can be played.
86 *
87 * URL syntax: rtmp://server[:port][/app][/playpath][ keyword=value]...
88 * where 'app' is first one or two directories in the path
89 * (e.g. /ondemand/, /flash/live/, etc.)
90 * and 'playpath' is a file name (the rest of the path,
91 * may be prefixed with "mp4:")
92 *
93 * Additional RTMP library options may be appended as
94 * space-separated key-value pairs.
95 */
96static int rtmp_open(URLContext *s, const char *uri, int flags)
97{
98 LibRTMPContext *ctx = s->priv_data;
99 RTMP *r = &ctx->rtmp;
100 int rc = 0, level;
101 /* This needs to stay allocated for as long as the RTMP context exists. */
103
104 switch (av_log_get_level()) {
105 default:
106 case AV_LOG_FATAL: level = RTMP_LOGCRIT; break;
107 case AV_LOG_ERROR: level = RTMP_LOGERROR; break;
108 case AV_LOG_WARNING: level = RTMP_LOGWARNING; break;
109 case AV_LOG_INFO: level = RTMP_LOGINFO; break;
110 case AV_LOG_VERBOSE: level = RTMP_LOGDEBUG; break;
111 case AV_LOG_DEBUG: level = RTMP_LOGDEBUG2; break;
112 }
113 RTMP_LogSetLevel(level);
114 RTMP_LogSetCallback(rtmp_log);
115
116 av_bprintf(&ctx->filename, "%s", s->filename);
117 if (ctx->app)
118 av_bprintf(&ctx->filename, " app=%s", ctx->app);
119 if (ctx->tcurl)
120 av_bprintf(&ctx->filename, " tcUrl=%s", ctx->tcurl);
121 if (ctx->pageurl)
122 av_bprintf(&ctx->filename, " pageUrl=%s", ctx->pageurl);
123 if (ctx->swfurl)
124 av_bprintf(&ctx->filename, " swfUrl=%s", ctx->swfurl);
125 if (ctx->flashver)
126 av_bprintf(&ctx->filename, " flashVer=%s", ctx->flashver);
127 if (ctx->conn) {
128 char *sep, *p = ctx->conn;
129 while (p) {
130 av_bprintf(&ctx->filename, " conn=");
131 p += strspn(p, " ");
132 if (!*p)
133 break;
134 sep = strchr(p, ' ');
135 if (sep)
136 *sep = '\0';
137 av_bprintf(&ctx->filename, "%s", p);
138
139 if (sep)
140 p = sep + 1;
141 else
142 break;
143 }
144 }
145 if (ctx->playpath)
146 av_bprintf(&ctx->filename, " playpath=%s", ctx->playpath);
147 if (ctx->live)
148 av_bprintf(&ctx->filename, " live=1");
149 if (ctx->subscribe)
150 av_bprintf(&ctx->filename, " subscribe=%s", ctx->subscribe);
151 if (ctx->client_buffer_time)
152 av_bprintf(&ctx->filename, " buffer=%s", ctx->client_buffer_time);
153 if (ctx->swfurl || ctx->swfverify) {
154 if (ctx->swfverify)
155 av_bprintf(&ctx->filename, " swfUrl=%s swfVfy=1", ctx->swfverify);
156 else
157 av_bprintf(&ctx->filename, " swfUrl=%s", ctx->swfurl);
158 }
159
160 if (!av_bprint_is_complete(&ctx->filename)) {
161 av_bprint_finalize(&ctx->filename, NULL);
162 return AVERROR(ENOMEM);
163 }
164
165 RTMP_Init(r);
166 /* This will modify filename by null terminating the URL portion */
167 if (!RTMP_SetupURL(r, ctx->filename.str)) {
168 rc = AVERROR_UNKNOWN;
169 goto fail;
170 }
171
173 RTMP_EnableWrite(r);
174
175 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0)) {
176 rc = AVERROR_UNKNOWN;
177 goto fail;
178 }
179
180#if CONFIG_NETWORK
181 if (ctx->buffer_size >= 0 && (flags & AVIO_FLAG_WRITE)) {
182 int tmp = ctx->buffer_size;
183 if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp))) {
184 rc = AVERROR_EXTERNAL;
185 goto fail;
186 }
187 }
188#endif
189
190 s->is_streamed = 1;
191 return 0;
192fail:
193
194 if (rc)
195 RTMP_Close(r);
196 av_bprint_finalize(&ctx->filename, NULL);
197
198 return rc;
199}
200
201static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
202{
203 LibRTMPContext *ctx = s->priv_data;
204 RTMP *r = &ctx->rtmp;
205
206 int ret = RTMP_Write(r, buf, size);
207 if (!ret)
208 return AVERROR_EOF;
209 return ret;
210}
211
212static int rtmp_read(URLContext *s, uint8_t *buf, int size)
213{
214 LibRTMPContext *ctx = s->priv_data;
215 RTMP *r = &ctx->rtmp;
216
217 int ret = RTMP_Read(r, buf, size);
218 if (!ret)
219 return AVERROR_EOF;
220 return ret;
221}
222
223static int rtmp_read_pause(void *opaque, int pause)
224{
225 URLContext *s = opaque;
226 LibRTMPContext *ctx = s->priv_data;
227 RTMP *r = &ctx->rtmp;
228
229 if (!RTMP_Pause(r, pause))
230 return AVERROR_UNKNOWN;
231 return 0;
232}
233
234static int64_t rtmp_read_seek(void *opaque, int stream_index,
235 int64_t timestamp, int flags)
236{
237 URLContext *s = opaque;
238 LibRTMPContext *ctx = s->priv_data;
239 RTMP *r = &ctx->rtmp;
240
242 return AVERROR(ENOSYS);
243
244 /* seeks are in milliseconds */
245 if (stream_index < 0)
246 timestamp = av_rescale_rnd(timestamp, 1000, AV_TIME_BASE,
248
249 if (!RTMP_SendSeek(r, timestamp))
250 return AVERROR_UNKNOWN;
251 return timestamp;
252}
253
255{
256 LibRTMPContext *ctx = s->priv_data;
257 RTMP *r = &ctx->rtmp;
258
259 return RTMP_Socket(r);
260}
261
262#define OFFSET(x) offsetof(LibRTMPContext, x)
263#define DEC AV_OPT_FLAG_DECODING_PARAM
264#define ENC AV_OPT_FLAG_ENCODING_PARAM
265static const AVOption options[] = {
266 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
267 {"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},
268 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
269 {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
270 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, .unit = "rtmp_live"},
271 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, .unit = "rtmp_live"},
272 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, .unit = "rtmp_live"},
273 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, .unit = "rtmp_live"},
274 {"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},
275 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
276 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
277 {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
278 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically. (unimplemented)", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
279 {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
280#if CONFIG_NETWORK
281 {"rtmp_buffer_size", "set buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC|ENC },
282#endif
283 { NULL },
284};
285
286#define RTMP_CLASS(flavor)\
287static const AVClass lib ## flavor ## _class = {\
288 .class_name = "lib" #flavor " protocol",\
289 .item_name = av_default_item_name,\
290 .option = options,\
291 .version = LIBAVUTIL_VERSION_INT,\
292};
293
294RTMP_CLASS(rtmp)
296 .name = "rtmp",
297 .url_open = rtmp_open,
298 .url_read = rtmp_read,
299 .url_write = rtmp_write,
300 .url_close = rtmp_close,
301 .url_read_pause = rtmp_read_pause,
302 .url_read_seek = rtmp_read_seek,
303 .url_get_file_handle = rtmp_get_file_handle,
304 .priv_data_size = sizeof(LibRTMPContext),
305 .priv_data_class = &librtmp_class,
307};
308
309RTMP_CLASS(rtmpt)
311 .name = "rtmpt",
312 .url_open = rtmp_open,
313 .url_read = rtmp_read,
314 .url_write = rtmp_write,
315 .url_close = rtmp_close,
316 .url_read_pause = rtmp_read_pause,
317 .url_read_seek = rtmp_read_seek,
318 .url_get_file_handle = rtmp_get_file_handle,
319 .priv_data_size = sizeof(LibRTMPContext),
320 .priv_data_class = &librtmpt_class,
322};
323
324RTMP_CLASS(rtmpe)
326 .name = "rtmpe",
327 .url_open = rtmp_open,
328 .url_read = rtmp_read,
329 .url_write = rtmp_write,
330 .url_close = rtmp_close,
331 .url_read_pause = rtmp_read_pause,
332 .url_read_seek = rtmp_read_seek,
333 .url_get_file_handle = rtmp_get_file_handle,
334 .priv_data_size = sizeof(LibRTMPContext),
335 .priv_data_class = &librtmpe_class,
337};
338
339RTMP_CLASS(rtmpte)
341 .name = "rtmpte",
342 .url_open = rtmp_open,
343 .url_read = rtmp_read,
344 .url_write = rtmp_write,
345 .url_close = rtmp_close,
346 .url_read_pause = rtmp_read_pause,
347 .url_read_seek = rtmp_read_seek,
348 .url_get_file_handle = rtmp_get_file_handle,
349 .priv_data_size = sizeof(LibRTMPContext),
350 .priv_data_class = &librtmpte_class,
352};
353
354RTMP_CLASS(rtmps)
356 .name = "rtmps",
357 .url_open = rtmp_open,
358 .url_read = rtmp_read,
359 .url_write = rtmp_write,
360 .url_close = rtmp_close,
361 .url_read_pause = rtmp_read_pause,
362 .url_read_seek = rtmp_read_seek,
363 .url_get_file_handle = rtmp_get_file_handle,
364 .priv_data_size = sizeof(LibRTMPContext),
365 .priv_data_class = &librtmps_class,
367};
Main libavformat public API header.
#define AVSEEK_FLAG_BYTE
seeking based on position in bytes
Definition avformat.h:2617
#define AVSEEK_FLAG_BACKWARD
seek backward
Definition avformat.h:2616
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:618
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define AV_BPRINT_SIZE_UNLIMITED
#define ENC
Definition caca.c:198
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition log.h:204
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
void av_vlog(void *avcl, int level, const char *fmt, va_list vl)
Send the specified message to the log if the level is less than or equal to the current av_log_level.
Definition log.c:459
int av_log_get_level(void)
Get the current log level.
Definition log.c:471
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
Rescale a 64-bit integer with specified rounding.
Definition mathematics.c:58
@ AV_ROUND_DOWN
Round toward -infinity.
@ AV_ROUND_UP
Round toward +infinity.
#define AV_TIME_BASE
Internal time base represented as integer.
Definition avutil.h:253
#define r
Definition input.c:42
#define DEC
Definition librsvgdec.c:149
static int rtmp_read(URLContext *s, uint8_t *buf, int size)
Definition librtmp.c:212
static int rtmp_get_file_handle(URLContext *s)
Definition librtmp.c:254
static int rtmp_open(URLContext *s, const char *uri, int flags)
Open RTMP connection and verify that the stream can be played.
Definition librtmp.c:96
static int rtmp_close(URLContext *s)
Definition librtmp.c:74
static int rtmp_read_pause(void *opaque, int pause)
Definition librtmp.c:223
const URLProtocol ff_librtmpe_protocol
Definition librtmp.c:325
static void rtmp_log(int level, const char *fmt, va_list args)
Definition librtmp.c:58
const URLProtocol ff_librtmpt_protocol
Definition librtmp.c:310
const URLProtocol ff_librtmpte_protocol
Definition librtmp.c:340
const URLProtocol ff_librtmps_protocol
Definition librtmp.c:355
const URLProtocol ff_librtmp_protocol
Definition librtmp.c:295
#define OFFSET(x)
Definition librtmp.c:262
#define RTMP_CLASS(flavor)
Definition librtmp.c:286
static int64_t rtmp_read_seek(void *opaque, int stream_index, int64_t timestamp, int flags)
Definition librtmp.c:234
static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
Definition librtmp.c:201
AVOptions.
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
char * swfverify
Definition librtmp.c:51
char * client_buffer_time
Definition librtmp.c:53
char * app
Definition librtmp.c:44
char * conn
Definition librtmp.c:45
AVBPrint filename
Definition librtmp.c:42
char * swfurl
Definition librtmp.c:50
char * subscribe
Definition librtmp.c:46
char * playpath
Definition librtmp.c:47
char * tcurl
Definition librtmp.c:48
char * pageurl
Definition librtmp.c:52
char * flashver
Definition librtmp.c:49
int buffer_size
Definition librtmp.c:55
uint8_t level
Definition svq3.c:208
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
static AVFormatContext * ctx
Definition movenc.c:49
int size
unbuffered private I/O API
#define URL_PROTOCOL_FLAG_NETWORK
Definition url.h:33