FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavformat
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)
53
}
RTMP_HTTPContext
;
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
89
if
(rt->
out_size
+ size > rt->
out_capacity
) {
90
int
err;
91
rt->
out_capacity
= (rt->
out_size
+
size
) * 2;
92
if
((err =
av_reallocp
(&rt->
out_data
, rt->
out_capacity
)) < 0) {
93
rt->
out_size
= 0;
94
rt->
out_capacity
= 0;
95
return
err;
96
}
97
}
98
99
memcpy(rt->
out_data
+ rt->
out_size
, buf, size);
100
rt->
out_size
+=
size
;
101
102
return
size
;
103
}
104
105
static
int
rtmp_http_read
(
URLContext
*h,
uint8_t
*
buf
,
int
size
)
106
{
107
RTMP_HTTPContext
*rt = h->
priv_data
;
108
int
ret
, off = 0;
109
110
/* try to read at least 1 byte of data */
111
do
{
112
ret =
ffurl_read
(rt->
stream
, buf + off, size);
113
if
(ret < 0 && ret !=
AVERROR_EOF
)
114
return
ret
;
115
116
if
(!ret || ret ==
AVERROR_EOF
) {
117
if
(rt->
finishing
) {
118
/* Do not send new requests when the client wants to
119
* close the connection. */
120
return
AVERROR
(EAGAIN);
121
}
122
123
/* When the client has reached end of file for the last request,
124
* we have to send a new request if we have buffered data.
125
* Otherwise, we have to send an idle POST. */
126
if
(rt->
out_size
> 0) {
127
if
((ret =
rtmp_http_send_cmd
(h,
"send"
)) < 0)
128
return
ret
;
129
}
else
{
130
if
(rt->
nb_bytes_read
== 0) {
131
/* Wait 50ms before retrying to read a server reply in
132
* order to reduce the number of idle requets. */
133
av_usleep
(50000);
134
}
135
136
if
((ret =
rtmp_http_write
(h,
""
, 1)) < 0)
137
return
ret
;
138
139
if
((ret =
rtmp_http_send_cmd
(h,
"idle"
)) < 0)
140
return
ret
;
141
}
142
143
if
(h->
flags
&
AVIO_FLAG_NONBLOCK
) {
144
/* no incoming data to handle in nonblocking mode */
145
return
AVERROR
(EAGAIN);
146
}
147
}
else
{
148
off +=
ret
;
149
size -=
ret
;
150
rt->
nb_bytes_read
+=
ret
;
151
}
152
}
while
(off <= 0);
153
154
return
off;
155
}
156
157
static
int
rtmp_http_close
(
URLContext
*h)
158
{
159
RTMP_HTTPContext
*rt = h->
priv_data
;
160
uint8_t
tmp_buf[2048];
161
int
ret
= 0;
162
163
if
(rt->
initialized
) {
164
/* client wants to close the connection */
165
rt->
finishing
= 1;
166
167
do
{
168
ret =
rtmp_http_read
(h, tmp_buf,
sizeof
(tmp_buf));
169
}
while
(ret > 0);
170
171
/* re-init output buffer before sending the close command */
172
rt->
out_size
= 0;
173
174
if
((ret =
rtmp_http_write
(h,
""
, 1)) == 1)
175
ret =
rtmp_http_send_cmd
(h,
"close"
);
176
}
177
178
av_freep
(&rt->
out_data
);
179
ffurl_close
(rt->
stream
);
180
181
return
ret
;
182
}
183
184
static
int
rtmp_http_open
(
URLContext
*h,
const
char
*uri,
int
flags
)
185
{
186
RTMP_HTTPContext
*rt = h->
priv_data
;
187
char
headers[1024], url[1024];
188
int
ret
, off = 0;
189
190
av_url_split
(NULL, 0, NULL, 0, rt->
host
,
sizeof
(rt->
host
), &rt->
port
,
191
NULL, 0, uri);
192
193
/* This is the first request that is sent to the server in order to
194
* register a client on the server and start a new session. The server
195
* replies with a unique id (usually a number) that is used by the client
196
* for all future requests.
197
* Note: the reply doesn't contain a value for the polling interval.
198
* A successful connect resets the consecutive index that is used
199
* in the URLs. */
200
if
(rt->
tls
) {
201
if
(rt->
port
< 0)
202
rt->
port
=
RTMPTS_DEFAULT_PORT
;
203
ff_url_join
(url,
sizeof
(url),
"https"
, NULL, rt->
host
, rt->
port
,
"/open/1"
);
204
}
else
{
205
if
(rt->
port
< 0)
206
rt->
port
=
RTMPT_DEFAULT_PORT
;
207
ff_url_join
(url,
sizeof
(url),
"http"
, NULL, rt->
host
, rt->
port
,
"/open/1"
);
208
}
209
210
/* alloc the http context */
211
if
((ret =
ffurl_alloc
(&rt->
stream
, url,
AVIO_FLAG_READ_WRITE
, NULL)) < 0)
212
goto
fail;
213
214
/* set options */
215
snprintf
(headers,
sizeof
(headers),
216
"Cache-Control: no-cache\r\n"
217
"Content-type: application/x-fcs\r\n"
218
"User-Agent: Shockwave Flash\r\n"
);
219
av_opt_set
(rt->
stream
->
priv_data
,
"headers"
, headers, 0);
220
av_opt_set
(rt->
stream
->
priv_data
,
"multiple_requests"
,
"1"
, 0);
221
av_opt_set_bin
(rt->
stream
->
priv_data
,
"post_data"
,
""
, 1, 0);
222
223
/* open the http context */
224
if
((ret =
ffurl_connect
(rt->
stream
, NULL)) < 0)
225
goto
fail;
226
227
/* read the server reply which contains a unique ID */
228
for
(;;) {
229
ret =
ffurl_read
(rt->
stream
, rt->
client_id
+ off,
sizeof
(rt->
client_id
) - off);
230
if
(!ret || ret ==
AVERROR_EOF
)
231
break
;
232
if
(ret < 0)
233
goto
fail;
234
off +=
ret
;
235
if
(off ==
sizeof
(rt->
client_id
)) {
236
ret =
AVERROR
(EIO);
237
goto
fail;
238
}
239
}
240
while
(off > 0 &&
av_isspace
(rt->
client_id
[off - 1]))
241
off--;
242
rt->
client_id
[off] =
'\0'
;
243
244
/* http context is now initialized */
245
rt->
initialized
= 1;
246
return
0;
247
248
fail:
249
rtmp_http_close
(h);
250
return
ret
;
251
}
252
253
#define OFFSET(x) offsetof(RTMP_HTTPContext, x)
254
#define DEC AV_OPT_FLAG_DECODING_PARAM
255
256
static
const
AVOption
ffrtmphttp_options
[] = {
257
{
"ffrtmphttp_tls"
,
"Use a HTTPS tunneling connection (RTMPTS)."
,
OFFSET
(tls),
AV_OPT_TYPE_INT
, {.i64 = 0}, 0, 1,
DEC
},
258
{ NULL },
259
};
260
261
static
const
AVClass
ffrtmphttp_class
= {
262
.
class_name
=
"ffrtmphttp"
,
263
.item_name =
av_default_item_name
,
264
.option =
ffrtmphttp_options
,
265
.version =
LIBAVUTIL_VERSION_INT
,
266
};
267
268
URLProtocol
ff_ffrtmphttp_protocol
= {
269
.
name
=
"ffrtmphttp"
,
270
.url_open =
rtmp_http_open
,
271
.url_read =
rtmp_http_read
,
272
.url_write =
rtmp_http_write
,
273
.url_close =
rtmp_http_close
,
274
.priv_data_size =
sizeof
(
RTMP_HTTPContext
),
275
.
flags
=
URL_PROTOCOL_FLAG_NETWORK
,
276
.priv_data_class= &ffrtmphttp_class,
277
};
Generated on Sun Sep 14 2014 18:56:14 for FFmpeg by
1.8.2