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 Mar 8 2015 02:35:11 for FFmpeg by
1.8.2