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