FFmpeg
Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
All
Data Structures
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
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
156
static
int
rtmp_http_close
(
URLContext
*h)
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)
201
rt->
port
=
RTMPTS_DEFAULT_PORT
;
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 && 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
267
URLProtocol
ff_ffrtmphttp_protocol
= {
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
),
274
.
flags
=
URL_PROTOCOL_FLAG_NETWORK
,
275
.priv_data_class= &ffrtmphttp_class,
276
};
Generated on Sat May 25 2013 03:58:48 for FFmpeg by
1.8.2