FFmpeg
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"
29 #include "libavutil/mathematics.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 
40 typedef 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 
58 static 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 
74 static int rtmp_close(URLContext *s)
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  */
96 static 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 
172  if (flags & AVIO_FLAG_WRITE)
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;
192 fail:
193 
194  if (rc)
195  RTMP_Close(r);
196  av_bprint_finalize(&ctx->filename, NULL);
197 
198  return rc;
199 }
200 
201 static 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 
212 static 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 
223 static 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 
234 static 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 
241  if (flags & AVSEEK_FLAG_BYTE)
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
265 static 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)\
287 static 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 
294 RTMP_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 
309 RTMP_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 
324 RTMP_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 
339 RTMP_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 
354 RTMP_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 };
av_vlog
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:431
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:134
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
level
uint8_t level
Definition: svq3.c:204
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
r
const char * r
Definition: vf_curves.c:126
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame 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. Frame references ownership and permissions
opt.h
LibRTMPContext::subscribe
char * subscribe
Definition: librtmp.c:46
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
LibRTMPContext::buffer_size
int buffer_size
Definition: librtmp.c:55
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
ENC
#define ENC
Definition: librtmp.c:264
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
rtmp_read_pause
static int rtmp_read_pause(void *opaque, int pause)
Definition: librtmp.c:223
int64_t
long long int64_t
Definition: coverity.c:34
LibRTMPContext::live
int live
Definition: librtmp.c:54
rtmp_close
static int rtmp_close(URLContext *s)
Definition: librtmp.c:74
ff_librtmps_protocol
const URLProtocol ff_librtmps_protocol
Definition: librtmp.c:355
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
AVOption
AVOption.
Definition: opt.h:346
AVSEEK_FLAG_BYTE
#define AVSEEK_FLAG_BYTE
seeking based on position in bytes
Definition: avformat.h:2434
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
mathematics.h
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
ff_librtmpt_protocol
const URLProtocol ff_librtmpt_protocol
Definition: librtmp.c:310
URLProtocol
Definition: url.h:51
rtmp_open
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
LibRTMPContext::conn
char * conn
Definition: librtmp.c:45
DEC
#define DEC
Definition: librtmp.c:263
fail
#define fail()
Definition: checkasm.h:179
LibRTMPContext::filename
AVBPrint filename
Definition: librtmp.c:42
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
s
#define s(width, name)
Definition: cbs_vp9.c:198
ff_librtmp_protocol
const URLProtocol ff_librtmp_protocol
Definition: librtmp.c:295
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:442
AVSEEK_FLAG_BACKWARD
#define AVSEEK_FLAG_BACKWARD
Definition: avformat.h:2433
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
LibRTMPContext
Definition: librtmp.c:40
LibRTMPContext::pageurl
char * pageurl
Definition: librtmp.c:52
LibRTMPContext::swfverify
char * swfverify
Definition: librtmp.c:51
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:133
av_rescale_rnd
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
rtmp_log
static void rtmp_log(int level, const char *fmt, va_list args)
Definition: librtmp.c:58
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
LibRTMPContext::playpath
char * playpath
Definition: librtmp.c:47
size
int size
Definition: twinvq_data.h:10344
URLProtocol::name
const char * name
Definition: url.h:52
LibRTMPContext::client_buffer_time
char * client_buffer_time
Definition: librtmp.c:53
options
static const AVOption options[]
Definition: librtmp.c:265
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
bprint.h
URLContext
Definition: url.h:35
LibRTMPContext::app
char * app
Definition: librtmp.c:44
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
url.h
rtmp_read
static int rtmp_read(URLContext *s, uint8_t *buf, int size)
Definition: librtmp.c:212
ret
ret
Definition: filter_design.txt:187
AV_LOG_FATAL
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:174
avformat.h
OFFSET
#define OFFSET(x)
Definition: librtmp.c:262
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
network.h
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
ff_librtmpe_protocol
const URLProtocol ff_librtmpe_protocol
Definition: librtmp.c:325
LibRTMPContext::flashver
char * flashver
Definition: librtmp.c:49
LibRTMPContext::swfurl
char * swfurl
Definition: librtmp.c:50
rtmp_write
static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
Definition: librtmp.c:201
ff_librtmpte_protocol
const URLProtocol ff_librtmpte_protocol
Definition: librtmp.c:340
rtmp_get_file_handle
static int rtmp_get_file_handle(URLContext *s)
Definition: librtmp.c:254
LibRTMPContext::tcurl
char * tcurl
Definition: librtmp.c:48
rtmp_read_seek
static int64_t rtmp_read_seek(void *opaque, int stream_index, int64_t timestamp, int flags)
Definition: librtmp.c:234
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
LibRTMPContext::rtmp
RTMP rtmp
Definition: librtmp.c:43
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
RTMP_CLASS
#define RTMP_CLASS(flavor)
Definition: librtmp.c:286
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244