rtmphttp.c
Go to the documentation of this file.
1 /*
2  * RTMP HTTP network protocol
3  * Copyright (c) 2012 Samuel Pitoiset
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 HTTP protocol
25  */
26 
27 #include "libavutil/avstring.h"
28 #include "libavutil/intfloat.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/time.h"
31 #include "internal.h"
32 #include "http.h"
33 #include "rtmp.h"
34 
35 #define RTMPT_DEFAULT_PORT 80
36 #define RTMPTS_DEFAULT_PORT RTMPS_DEFAULT_PORT
37 
38 /* protocol handler context */
39 typedef struct RTMP_HTTPContext {
40  const AVClass *class;
41  URLContext *stream; ///< HTTP stream
42  char host[256]; ///< hostname of the server
43  int port; ///< port to connect (default is 80)
44  char client_id[64]; ///< client ID used for all requests except the first one
45  int seq; ///< sequence ID used for all requests
46  uint8_t *out_data; ///< output buffer
47  int out_size; ///< current output buffer size
48  int out_capacity; ///< current output buffer capacity
49  int initialized; ///< flag indicating when the http context is initialized
50  int finishing; ///< flag indicating when the client closes the connection
51  int nb_bytes_read; ///< number of bytes read since the last request
52  int tls; ///< use Transport Security Layer (RTMPTS)
54 
55 static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
56 {
57  RTMP_HTTPContext *rt = h->priv_data;
58  char uri[2048];
59  uint8_t c;
60  int ret;
61 
62  ff_url_join(uri, sizeof(uri), "http", NULL, rt->host, rt->port,
63  "/%s/%s/%d", cmd, rt->client_id, rt->seq++);
64 
65  av_opt_set_bin(rt->stream->priv_data, "post_data", rt->out_data,
66  rt->out_size, 0);
67 
68  /* send a new request to the server */
69  if ((ret = ff_http_do_new_request(rt->stream, uri)) < 0)
70  return ret;
71 
72  /* re-init output buffer */
73  rt->out_size = 0;
74 
75  /* read the first byte which contains the polling interval */
76  if ((ret = ffurl_read(rt->stream, &c, 1)) < 0)
77  return ret;
78 
79  /* re-init the number of bytes read */
80  rt->nb_bytes_read = 0;
81 
82  return ret;
83 }
84 
85 static int rtmp_http_write(URLContext *h, const uint8_t *buf, int size)
86 {
87  RTMP_HTTPContext *rt = h->priv_data;
88  void *ptr;
89 
90  if (rt->out_size + size > rt->out_capacity) {
91  rt->out_capacity = (rt->out_size + size) * 2;
92  ptr = av_realloc(rt->out_data, rt->out_capacity);
93  if (!ptr)
94  return AVERROR(ENOMEM);
95  rt->out_data = ptr;
96  }
97 
98  memcpy(rt->out_data + rt->out_size, buf, size);
99  rt->out_size += size;
100 
101  return size;
102 }
103 
104 static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
105 {
106  RTMP_HTTPContext *rt = h->priv_data;
107  int ret, off = 0;
108 
109  /* try to read at least 1 byte of data */
110  do {
111  ret = ffurl_read(rt->stream, buf + off, size);
112  if (ret < 0 && ret != AVERROR_EOF)
113  return ret;
114 
115  if (ret == AVERROR_EOF) {
116  if (rt->finishing) {
117  /* Do not send new requests when the client wants to
118  * close the connection. */
119  return AVERROR(EAGAIN);
120  }
121 
122  /* When the client has reached end of file for the last request,
123  * we have to send a new request if we have buffered data.
124  * Otherwise, we have to send an idle POST. */
125  if (rt->out_size > 0) {
126  if ((ret = rtmp_http_send_cmd(h, "send")) < 0)
127  return ret;
128  } else {
129  if (rt->nb_bytes_read == 0) {
130  /* Wait 50ms before retrying to read a server reply in
131  * order to reduce the number of idle requets. */
132  av_usleep(50000);
133  }
134 
135  if ((ret = rtmp_http_write(h, "", 1)) < 0)
136  return ret;
137 
138  if ((ret = rtmp_http_send_cmd(h, "idle")) < 0)
139  return ret;
140  }
141 
142  if (h->flags & AVIO_FLAG_NONBLOCK) {
143  /* no incoming data to handle in nonblocking mode */
144  return AVERROR(EAGAIN);
145  }
146  } else {
147  off += ret;
148  size -= ret;
149  rt->nb_bytes_read += ret;
150  }
151  } while (off <= 0);
152 
153  return off;
154 }
155 
157 {
158  RTMP_HTTPContext *rt = h->priv_data;
159  uint8_t tmp_buf[2048];
160  int ret = 0;
161 
162  if (rt->initialized) {
163  /* client wants to close the connection */
164  rt->finishing = 1;
165 
166  do {
167  ret = rtmp_http_read(h, tmp_buf, sizeof(tmp_buf));
168  } while (ret > 0);
169 
170  /* re-init output buffer before sending the close command */
171  rt->out_size = 0;
172 
173  if ((ret = rtmp_http_write(h, "", 1)) == 1)
174  ret = rtmp_http_send_cmd(h, "close");
175  }
176 
177  av_freep(&rt->out_data);
178  ffurl_close(rt->stream);
179 
180  return ret;
181 }
182 
183 static int rtmp_http_open(URLContext *h, const char *uri, int flags)
184 {
185  RTMP_HTTPContext *rt = h->priv_data;
186  char headers[1024], url[1024];
187  int ret, off = 0;
188 
189  av_url_split(NULL, 0, NULL, 0, rt->host, sizeof(rt->host), &rt->port,
190  NULL, 0, uri);
191 
192  /* This is the first request that is sent to the server in order to
193  * register a client on the server and start a new session. The server
194  * replies with a unique id (usually a number) that is used by the client
195  * for all future requests.
196  * Note: the reply doesn't contain a value for the polling interval.
197  * A successful connect resets the consecutive index that is used
198  * in the URLs. */
199  if (rt->tls) {
200  if (rt->port < 0)
202  ff_url_join(url, sizeof(url), "https", NULL, rt->host, rt->port, "/open/1");
203  } else {
204  if (rt->port < 0)
205  rt->port = RTMPT_DEFAULT_PORT;
206  ff_url_join(url, sizeof(url), "http", NULL, rt->host, rt->port, "/open/1");
207  }
208 
209  /* alloc the http context */
210  if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, NULL)) < 0)
211  goto fail;
212 
213  /* set options */
214  snprintf(headers, sizeof(headers),
215  "Cache-Control: no-cache\r\n"
216  "Content-type: application/x-fcs\r\n"
217  "User-Agent: Shockwave Flash\r\n");
218  av_opt_set(rt->stream->priv_data, "headers", headers, 0);
219  av_opt_set(rt->stream->priv_data, "multiple_requests", "1", 0);
220  av_opt_set_bin(rt->stream->priv_data, "post_data", "", 1, 0);
221 
222  /* open the http context */
223  if ((ret = ffurl_connect(rt->stream, NULL)) < 0)
224  goto fail;
225 
226  /* read the server reply which contains a unique ID */
227  for (;;) {
228  ret = ffurl_read(rt->stream, rt->client_id + off, sizeof(rt->client_id) - off);
229  if (ret == AVERROR_EOF)
230  break;
231  if (ret < 0)
232  goto fail;
233  off += ret;
234  if (off == sizeof(rt->client_id)) {
235  ret = AVERROR(EIO);
236  goto fail;
237  }
238  }
239  while (off > 0 && av_isspace(rt->client_id[off - 1]))
240  off--;
241  rt->client_id[off] = '\0';
242 
243  /* http context is now initialized */
244  rt->initialized = 1;
245  return 0;
246 
247 fail:
248  rtmp_http_close(h);
249  return ret;
250 }
251 
252 #define OFFSET(x) offsetof(RTMP_HTTPContext, x)
253 #define DEC AV_OPT_FLAG_DECODING_PARAM
254 
255 static const AVOption ffrtmphttp_options[] = {
256  {"ffrtmphttp_tls", "Use a HTTPS tunneling connection (RTMPTS).", OFFSET(tls), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC},
257  { NULL },
258 };
259 
260 static const AVClass ffrtmphttp_class = {
261  .class_name = "ffrtmphttp",
262  .item_name = av_default_item_name,
263  .option = ffrtmphttp_options,
264  .version = LIBAVUTIL_VERSION_INT,
265 };
266 
268  .name = "ffrtmphttp",
269  .url_open = rtmp_http_open,
270  .url_read = rtmp_http_read,
271  .url_write = rtmp_http_write,
272  .url_close = rtmp_http_close,
273  .priv_data_size = sizeof(RTMP_HTTPContext),
275  .priv_data_class= &ffrtmphttp_class,
276 };
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
int tls
use Transport Security Layer (RTMPTS)
Definition: rtmphttp.c:52
URLContext * stream
HTTP stream.
Definition: rtmphttp.c:41
int size
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:35
AVOption.
Definition: opt.h:251
av_default_item_name
#define LIBAVUTIL_VERSION_INT
int ffurl_connect(URLContext *uc, AVDictionary **options)
Connect an URLContext that has been allocated by ffurl_alloc.
Definition: avio.c:190
int out_capacity
current output buffer capacity
Definition: rtmphttp.c:48
int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags)
Definition: opt.c:409
int flags
Definition: url.h:46
uint8_t * out_data
output buffer
Definition: rtmphttp.c:46
#define OFFSET(x)
Definition: rtmphttp.c:252
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:56
#define RTMPTS_DEFAULT_PORT
Definition: rtmphttp.c:36
FFmpeg currently uses a custom build this text attempts to document some of its obscure features and options Makefile the full command issued by make and its output will be shown on the screen DESTDIR Destination directory for the install useful to prepare packages or install FFmpeg in cross environments Makefile builds all the libraries and the executables fate Run the fate test note you must have installed it fate list Will list all fate regression test targets install Install headers
Definition: build_system.txt:1
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...) av_printf_format(7
Assemble a URL string from components.
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:55
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:141
AVOptions.
int out_size
current output buffer size
Definition: rtmphttp.c:47
static const AVOption ffrtmphttp_options[]
Definition: rtmphttp.c:255
int nb_bytes_read
number of bytes read since the last request
Definition: rtmphttp.c:51
#define AVERROR_EOF
End of file.
Definition: error.h:55
char client_id[64]
client ID used for all requests except the first one
Definition: rtmphttp.c:44
struct RTMP_HTTPContext RTMP_HTTPContext
int ffurl_alloc(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb)
Create a URLContext for accessing to the resource indicated by url, but do not initiate the connectio...
Definition: avio.c:211
static int rtmp_http_send_cmd(URLContext *h, const char *cmd)
Definition: rtmphttp.c:55
int seq
sequence ID used for all requests
Definition: rtmphttp.c:45
int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.c:298
ret
Definition: avfilter.c:821
static int rtmp_http_open(URLContext *h, const char *uri, int flags)
Definition: rtmphttp.c:183
NULL
Definition: eval.c:55
#define RTMPT_DEFAULT_PORT
Definition: rtmphttp.c:35
static int rtmp_http_close(URLContext *h)
Definition: rtmphttp.c:156
#define DEC
Definition: rtmphttp.c:253
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:351
void * buf
Definition: avisynth_c.h:594
Definition: url.h:41
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition: avio.h:334
static int rtmp_http_write(URLContext *h, const uint8_t *buf, int size)
Definition: rtmphttp.c:85
Describe the class of an AVClass context structure.
Definition: log.h:50
void * priv_data
Definition: url.h:44
const uint8_t ptrdiff_t int h
Definition: hpel_template.c:97
#define snprintf
Definition: snprintf.h:34
static const AVClass ffrtmphttp_class
Definition: rtmphttp.c:260
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
const char * name
Definition: url.h:55
int finishing
flag indicating when the client closes the connection
Definition: rtmphttp.c:50
URLProtocol ff_ffrtmphttp_protocol
Definition: rtmphttp.c:267
static int flags
Definition: cpu.c:23
int ffurl_close(URLContext *h)
Definition: avio.c:359
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:216
static int rtmp_http_read(URLContext *h, uint8_t *buf, int size)
Definition: rtmphttp.c:104
static double c[64]
int port
port to connect (default is 80)
Definition: rtmphttp.c:43
int initialized
flag indicating when the http context is initialized
Definition: rtmphttp.c:49
char host[256]
hostname of the server
Definition: rtmphttp.c:42
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:252
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...
Definition: avio.c:303