rtsp: Support mpegts in raw udp packets
[libav.git] / libavformat / rtmpproto.c
CommitLineData
9fd6b843
KS
1/*
2 * RTMP network protocol
3 * Copyright (c) 2009 Kostya Shishkov
4 *
2912e87a 5 * This file is part of Libav.
9fd6b843 6 *
2912e87a 7 * Libav is free software; you can redistribute it and/or
9fd6b843
KS
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 *
2912e87a 12 * Libav is distributed in the hope that it will be useful,
9fd6b843
KS
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
2912e87a 18 * License along with Libav; if not, write to the Free Software
9fd6b843
KS
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
ba87f080 23 * @file
9fd6b843
KS
24 * RTMP protocol
25 */
26
27#include "libavcodec/bytestream.h"
28#include "libavutil/avstring.h"
3383a53e 29#include "libavutil/intfloat.h"
9fd6b843 30#include "libavutil/lfg.h"
6465562e 31#include "libavutil/opt.h"
9fd6b843
KS
32#include "libavutil/sha.h"
33#include "avformat.h"
e4a9e3cc 34#include "internal.h"
9fd6b843
KS
35
36#include "network.h"
37
38#include "flv.h"
39#include "rtmp.h"
acd554c1 40#include "rtmpcrypt.h"
9fd6b843 41#include "rtmppkt.h"
0589da0a 42#include "url.h"
9fd6b843 43
cfac91fe
KS
44//#define DEBUG
45
6465562e 46#define APP_MAX_LENGTH 128
b3b17512 47#define PLAYPATH_MAX_LENGTH 256
55c9320e 48#define TCURL_MAX_LENGTH 512
e64673e4 49#define FLASHVER_MAX_LENGTH 64
6465562e 50
9fd6b843
KS
51/** RTMP protocol handler state */
52typedef enum {
53 STATE_START, ///< client has not done anything yet
54 STATE_HANDSHAKED, ///< client has performed handshake
6bf22e18
S
55 STATE_RELEASING, ///< client releasing stream before publish it (for output)
56 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
9fd6b843
KS
57 STATE_CONNECTING, ///< client connected to server successfully
58 STATE_READY, ///< client has sent all needed commands and waits for server reply
59 STATE_PLAYING, ///< client has started receiving multimedia data from server
6bf22e18 60 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
72b870b9 61 STATE_STOPPED, ///< the broadcast has been stopped
9fd6b843
KS
62} ClientState;
63
64/** protocol handler context */
65typedef struct RTMPContext {
6465562e 66 const AVClass *class;
9fd6b843
KS
67 URLContext* stream; ///< TCP stream used in interactions with RTMP server
68 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
69 int chunk_size; ///< size of the chunks RTMP packets are divided into
b316991b 70 int is_input; ///< input/output flag
b3b17512 71 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
b2e495af 72 int live; ///< 0: recorded, -1: live, -2: both
6465562e 73 char *app; ///< name of application
8ee3e187 74 char *conn; ///< append arbitrary AMF data to the Connect message
9fd6b843
KS
75 ClientState state; ///< current state
76 int main_channel_id; ///< an additional channel ID which is used for some invocations
77 uint8_t* flv_data; ///< buffer with data for demuxer
78 int flv_size; ///< current buffer size
79 int flv_off; ///< number of bytes read from current buffer
46743a85 80 int flv_nb_packets; ///< number of flv packets published
6bf22e18 81 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
bf7c1719
KS
82 uint32_t client_report_size; ///< number of bytes after which client should report to server
83 uint32_t bytes_read; ///< number of bytes read from server
84 uint32_t last_bytes_read; ///< number of bytes read last reported to server
3ffe32eb 85 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
b14629e5
MS
86 uint8_t flv_header[11]; ///< partial incoming flv packet header
87 int flv_header_bytes; ///< number of initialized bytes in flv_header
704af3e2 88 int nb_invokes; ///< keeps track of invoke messages
1eef08f9 89 int create_stream_invoke; ///< invoke id for the create stream command
55c9320e 90 char* tcurl; ///< url of the target stream
e64673e4 91 char* flashver; ///< version of the flash plugin
05945db9 92 char* swfurl; ///< url of the swf player
758377a2 93 char* pageurl; ///< url of the web page
00cb52c6 94 char* subscribe; ///< name of live stream to subscribe
c2d38bea 95 int server_bw; ///< server bandwidth
9477c035 96 int client_buffer_time; ///< client buffer time in ms
46743a85 97 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
acd554c1 98 int encrypted; ///< use an encrypted connection (RTMPE only)
9fd6b843
KS
99} RTMPContext;
100
101#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
102/** Client key used for digest signing */
103static const uint8_t rtmp_player_key[] = {
104 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
105 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
106
107 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
108 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
109 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
110};
111
112#define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
113/** Key used for RTMP server digest signing */
114static const uint8_t rtmp_server_key[] = {
115 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
116 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
117 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
118
119 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
120 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
121 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
122};
123
8ee3e187
SP
124static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
125{
05338686 126 char *field, *value;
8ee3e187
SP
127 char type;
128
129 /* The type must be B for Boolean, N for number, S for string, O for
130 * object, or Z for null. For Booleans the data must be either 0 or 1 for
131 * FALSE or TRUE, respectively. Likewise for Objects the data must be
132 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
133 * may be named, by prefixing the type with 'N' and specifying the name
134 * before the value (ie. NB:myFlag:1). This option may be used multiple times
135 * to construct arbitrary AMF sequences. */
136 if (param[0] && param[1] == ':') {
137 type = param[0];
138 value = param + 2;
139 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
140 type = param[1];
05338686
MS
141 field = param + 3;
142 value = strchr(field, ':');
143 if (!value)
144 goto fail;
145 *value = '\0';
146 value++;
8ee3e187
SP
147
148 if (!field || !value)
149 goto fail;
150
151 ff_amf_write_field_name(p, field);
152 } else {
153 goto fail;
154 }
155
156 switch (type) {
157 case 'B':
158 ff_amf_write_bool(p, value[0] != '0');
159 break;
160 case 'S':
161 ff_amf_write_string(p, value);
162 break;
163 case 'N':
164 ff_amf_write_number(p, strtod(value, NULL));
165 break;
166 case 'Z':
167 ff_amf_write_null(p);
168 break;
169 case 'O':
170 if (value[0] != '0')
171 ff_amf_write_object_start(p);
172 else
173 ff_amf_write_object_end(p);
174 break;
175 default:
176 goto fail;
177 break;
178 }
179
180 return 0;
181
182fail:
183 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
184 return AVERROR(EINVAL);
185}
186
9fd6b843 187/**
49bd8e4b 188 * Generate 'connect' call and send it to the server.
9fd6b843 189 */
f645f1d6 190static int gen_connect(URLContext *s, RTMPContext *rt)
9fd6b843
KS
191{
192 RTMPPacket pkt;
e64673e4 193 uint8_t *p;
f645f1d6
SP
194 int ret;
195
196 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
197 0, 4096)) < 0)
198 return ret;
9fd6b843 199
9fd6b843
KS
200 p = pkt.data;
201
9fd6b843 202 ff_amf_write_string(&p, "connect");
1eef08f9 203 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843
KS
204 ff_amf_write_object_start(&p);
205 ff_amf_write_field_name(&p, "app");
5e9ad759 206 ff_amf_write_string(&p, rt->app);
9fd6b843 207
e64673e4 208 if (!rt->is_input) {
6bf22e18
S
209 ff_amf_write_field_name(&p, "type");
210 ff_amf_write_string(&p, "nonprivate");
211 }
9fd6b843 212 ff_amf_write_field_name(&p, "flashVer");
e64673e4 213 ff_amf_write_string(&p, rt->flashver);
05945db9
SP
214
215 if (rt->swfurl) {
216 ff_amf_write_field_name(&p, "swfUrl");
217 ff_amf_write_string(&p, rt->swfurl);
218 }
219
9fd6b843 220 ff_amf_write_field_name(&p, "tcUrl");
55c9320e 221 ff_amf_write_string(&p, rt->tcurl);
6bf22e18 222 if (rt->is_input) {
c7240611
KS
223 ff_amf_write_field_name(&p, "fpad");
224 ff_amf_write_bool(&p, 0);
225 ff_amf_write_field_name(&p, "capabilities");
226 ff_amf_write_number(&p, 15.0);
faba4a9b
SP
227
228 /* Tell the server we support all the audio codecs except
229 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
230 * which are unused in the RTMP protocol implementation. */
c7240611 231 ff_amf_write_field_name(&p, "audioCodecs");
faba4a9b 232 ff_amf_write_number(&p, 4071.0);
c7240611
KS
233 ff_amf_write_field_name(&p, "videoCodecs");
234 ff_amf_write_number(&p, 252.0);
235 ff_amf_write_field_name(&p, "videoFunction");
236 ff_amf_write_number(&p, 1.0);
758377a2
SP
237
238 if (rt->pageurl) {
239 ff_amf_write_field_name(&p, "pageUrl");
240 ff_amf_write_string(&p, rt->pageurl);
241 }
6bf22e18 242 }
9fd6b843
KS
243 ff_amf_write_object_end(&p);
244
8ee3e187 245 if (rt->conn) {
05338686 246 char *param = rt->conn;
8ee3e187
SP
247
248 // Write arbitrary AMF data to the Connect message.
8ee3e187 249 while (param != NULL) {
05338686
MS
250 char *sep;
251 param += strspn(param, " ");
252 if (!*param)
253 break;
254 sep = strchr(param, ' ');
255 if (sep)
256 *sep = '\0';
8ee3e187
SP
257 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
258 // Invalid AMF parameter.
259 ff_rtmp_packet_destroy(&pkt);
260 return ret;
261 }
262
05338686
MS
263 if (sep)
264 param = sep + 1;
265 else
266 break;
8ee3e187
SP
267 }
268 }
269
9fd6b843
KS
270 pkt.data_size = p - pkt.data;
271
bba287fd
SP
272 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
273 rt->prev_pkt[1]);
f8caa544 274 ff_rtmp_packet_destroy(&pkt);
f645f1d6 275
bba287fd 276 return ret;
9fd6b843
KS
277}
278
279/**
49bd8e4b 280 * Generate 'releaseStream' call and send it to the server. It should make
6bf22e18
S
281 * the server release some channel for media streams.
282 */
f645f1d6 283static int gen_release_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
284{
285 RTMPPacket pkt;
286 uint8_t *p;
f645f1d6 287 int ret;
6bf22e18 288
f645f1d6
SP
289 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
290 0, 29 + strlen(rt->playpath))) < 0)
291 return ret;
6bf22e18 292
7f804085 293 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
6bf22e18
S
294 p = pkt.data;
295 ff_amf_write_string(&p, "releaseStream");
704af3e2 296 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
297 ff_amf_write_null(&p);
298 ff_amf_write_string(&p, rt->playpath);
299
bba287fd
SP
300 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
301 rt->prev_pkt[1]);
6bf22e18 302 ff_rtmp_packet_destroy(&pkt);
f645f1d6 303
bba287fd 304 return ret;
6bf22e18
S
305}
306
307/**
49bd8e4b 308 * Generate 'FCPublish' call and send it to the server. It should make
6bf22e18
S
309 * the server preapare for receiving media streams.
310 */
f645f1d6 311static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
312{
313 RTMPPacket pkt;
314 uint8_t *p;
f645f1d6 315 int ret;
6bf22e18 316
f645f1d6
SP
317 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
318 0, 25 + strlen(rt->playpath))) < 0)
319 return ret;
6bf22e18 320
7f804085 321 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
6bf22e18
S
322 p = pkt.data;
323 ff_amf_write_string(&p, "FCPublish");
704af3e2 324 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
325 ff_amf_write_null(&p);
326 ff_amf_write_string(&p, rt->playpath);
327
bba287fd
SP
328 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
329 rt->prev_pkt[1]);
6bf22e18 330 ff_rtmp_packet_destroy(&pkt);
f645f1d6 331
bba287fd 332 return ret;
6bf22e18
S
333}
334
335/**
49bd8e4b 336 * Generate 'FCUnpublish' call and send it to the server. It should make
6bf22e18
S
337 * the server destroy stream.
338 */
f645f1d6 339static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
340{
341 RTMPPacket pkt;
342 uint8_t *p;
f645f1d6 343 int ret;
6bf22e18 344
f645f1d6
SP
345 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
346 0, 27 + strlen(rt->playpath))) < 0)
347 return ret;
6bf22e18 348
7f804085 349 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
6bf22e18
S
350 p = pkt.data;
351 ff_amf_write_string(&p, "FCUnpublish");
704af3e2 352 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
353 ff_amf_write_null(&p);
354 ff_amf_write_string(&p, rt->playpath);
355
bba287fd
SP
356 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
357 rt->prev_pkt[1]);
6bf22e18 358 ff_rtmp_packet_destroy(&pkt);
f645f1d6 359
bba287fd 360 return ret;
6bf22e18
S
361}
362
363/**
49bd8e4b 364 * Generate 'createStream' call and send it to the server. It should make
9fd6b843
KS
365 * the server allocate some channel for media streams.
366 */
f645f1d6 367static int gen_create_stream(URLContext *s, RTMPContext *rt)
9fd6b843
KS
368{
369 RTMPPacket pkt;
370 uint8_t *p;
f645f1d6 371 int ret;
9fd6b843 372
7f804085 373 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
f645f1d6
SP
374
375 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
376 0, 25)) < 0)
377 return ret;
9fd6b843
KS
378
379 p = pkt.data;
380 ff_amf_write_string(&p, "createStream");
704af3e2 381 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18 382 ff_amf_write_null(&p);
1eef08f9 383 rt->create_stream_invoke = rt->nb_invokes;
6bf22e18 384
bba287fd
SP
385 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
386 rt->prev_pkt[1]);
6bf22e18 387 ff_rtmp_packet_destroy(&pkt);
f645f1d6 388
bba287fd 389 return ret;
6bf22e18
S
390}
391
392
393/**
49bd8e4b 394 * Generate 'deleteStream' call and send it to the server. It should make
6bf22e18
S
395 * the server remove some channel for media streams.
396 */
f645f1d6 397static int gen_delete_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
398{
399 RTMPPacket pkt;
400 uint8_t *p;
f645f1d6 401 int ret;
6bf22e18 402
7f804085 403 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
f645f1d6
SP
404
405 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
406 0, 34)) < 0)
407 return ret;
6bf22e18
S
408
409 p = pkt.data;
410 ff_amf_write_string(&p, "deleteStream");
1eef08f9 411 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843 412 ff_amf_write_null(&p);
6bf22e18 413 ff_amf_write_number(&p, rt->main_channel_id);
9fd6b843 414
bba287fd
SP
415 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
416 rt->prev_pkt[1]);
9fd6b843 417 ff_rtmp_packet_destroy(&pkt);
f645f1d6 418
bba287fd 419 return ret;
9fd6b843
KS
420}
421
422/**
9477c035
SP
423 * Generate client buffer time and send it to the server.
424 */
425static int gen_buffer_time(URLContext *s, RTMPContext *rt)
426{
427 RTMPPacket pkt;
428 uint8_t *p;
429 int ret;
430
431 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
432 1, 10)) < 0)
433 return ret;
434
435 p = pkt.data;
436 bytestream_put_be16(&p, 3);
437 bytestream_put_be32(&p, rt->main_channel_id);
438 bytestream_put_be32(&p, rt->client_buffer_time);
439
440 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
441 rt->prev_pkt[1]);
442 ff_rtmp_packet_destroy(&pkt);
443
444 return ret;
445}
446
447/**
49bd8e4b 448 * Generate 'play' call and send it to the server, then ping the server
9fd6b843
KS
449 * to start actual playing.
450 */
f645f1d6 451static int gen_play(URLContext *s, RTMPContext *rt)
9fd6b843
KS
452{
453 RTMPPacket pkt;
454 uint8_t *p;
f645f1d6 455 int ret;
9fd6b843 456
7f804085 457 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
f645f1d6
SP
458
459 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
460 0, 29 + strlen(rt->playpath))) < 0)
461 return ret;
462
9fd6b843
KS
463 pkt.extra = rt->main_channel_id;
464
465 p = pkt.data;
466 ff_amf_write_string(&p, "play");
1eef08f9 467 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843
KS
468 ff_amf_write_null(&p);
469 ff_amf_write_string(&p, rt->playpath);
b2e495af 470 ff_amf_write_number(&p, rt->live);
9fd6b843 471
bba287fd
SP
472 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
473 rt->prev_pkt[1]);
9fd6b843
KS
474 ff_rtmp_packet_destroy(&pkt);
475
bba287fd 476 return ret;
9fd6b843
KS
477}
478
479/**
49bd8e4b 480 * Generate 'publish' call and send it to the server.
6bf22e18 481 */
f645f1d6 482static int gen_publish(URLContext *s, RTMPContext *rt)
6bf22e18
S
483{
484 RTMPPacket pkt;
485 uint8_t *p;
f645f1d6 486 int ret;
6bf22e18 487
7f804085 488 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
f645f1d6
SP
489
490 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
491 0, 30 + strlen(rt->playpath))) < 0)
492 return ret;
493
6bf22e18
S
494 pkt.extra = rt->main_channel_id;
495
496 p = pkt.data;
497 ff_amf_write_string(&p, "publish");
1eef08f9 498 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
499 ff_amf_write_null(&p);
500 ff_amf_write_string(&p, rt->playpath);
501 ff_amf_write_string(&p, "live");
502
bba287fd
SP
503 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
504 rt->prev_pkt[1]);
6bf22e18 505 ff_rtmp_packet_destroy(&pkt);
f645f1d6
SP
506
507 return ret;
6bf22e18
S
508}
509
510/**
49bd8e4b 511 * Generate ping reply and send it to the server.
9fd6b843 512 */
f645f1d6 513static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
9fd6b843
KS
514{
515 RTMPPacket pkt;
516 uint8_t *p;
f645f1d6
SP
517 int ret;
518
8ea1459b
SP
519 if (ppkt->data_size < 6) {
520 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
521 ppkt->data_size);
522 return AVERROR_INVALIDDATA;
523 }
524
f645f1d6
SP
525 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
526 ppkt->timestamp + 1, 6)) < 0)
527 return ret;
9fd6b843 528
9fd6b843
KS
529 p = pkt.data;
530 bytestream_put_be16(&p, 7);
4aaebf78 531 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
bba287fd
SP
532 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
533 rt->prev_pkt[1]);
9fd6b843 534 ff_rtmp_packet_destroy(&pkt);
f645f1d6 535
bba287fd 536 return ret;
9fd6b843
KS
537}
538
bf7c1719 539/**
34d908c0
RS
540 * Generate server bandwidth message and send it to the server.
541 */
f645f1d6 542static int gen_server_bw(URLContext *s, RTMPContext *rt)
34d908c0
RS
543{
544 RTMPPacket pkt;
545 uint8_t *p;
f645f1d6
SP
546 int ret;
547
548 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
549 0, 4)) < 0)
550 return ret;
34d908c0 551
34d908c0 552 p = pkt.data;
c2d38bea 553 bytestream_put_be32(&p, rt->server_bw);
bba287fd
SP
554 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
555 rt->prev_pkt[1]);
34d908c0 556 ff_rtmp_packet_destroy(&pkt);
f645f1d6 557
bba287fd 558 return ret;
34d908c0
RS
559}
560
561/**
d55961fa
SP
562 * Generate check bandwidth message and send it to the server.
563 */
f645f1d6 564static int gen_check_bw(URLContext *s, RTMPContext *rt)
d55961fa
SP
565{
566 RTMPPacket pkt;
567 uint8_t *p;
f645f1d6 568 int ret;
d55961fa 569
f645f1d6
SP
570 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
571 0, 21)) < 0)
572 return ret;
d55961fa
SP
573
574 p = pkt.data;
575 ff_amf_write_string(&p, "_checkbw");
82613564 576 ff_amf_write_number(&p, RTMP_NOTIFICATION);
d55961fa
SP
577 ff_amf_write_null(&p);
578
bba287fd
SP
579 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
580 rt->prev_pkt[1]);
d55961fa 581 ff_rtmp_packet_destroy(&pkt);
f645f1d6
SP
582
583 return ret;
d55961fa
SP
584}
585
586/**
49bd8e4b 587 * Generate report on bytes read so far and send it to the server.
bf7c1719 588 */
f645f1d6 589static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
bf7c1719
KS
590{
591 RTMPPacket pkt;
592 uint8_t *p;
f645f1d6
SP
593 int ret;
594
595 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
596 ts, 4)) < 0)
597 return ret;
bf7c1719 598
bf7c1719
KS
599 p = pkt.data;
600 bytestream_put_be32(&p, rt->bytes_read);
bba287fd
SP
601 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
602 rt->prev_pkt[1]);
bf7c1719 603 ff_rtmp_packet_destroy(&pkt);
f645f1d6 604
bba287fd 605 return ret;
bf7c1719
KS
606}
607
00cb52c6
SP
608static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
609 const char *subscribe)
f9e77c17
SP
610{
611 RTMPPacket pkt;
612 uint8_t *p;
613 int ret;
614
615 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
00cb52c6 616 0, 27 + strlen(subscribe))) < 0)
f9e77c17
SP
617 return ret;
618
619 p = pkt.data;
620 ff_amf_write_string(&p, "FCSubscribe");
621 ff_amf_write_number(&p, ++rt->nb_invokes);
622 ff_amf_write_null(&p);
00cb52c6 623 ff_amf_write_string(&p, subscribe);
f9e77c17
SP
624
625 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
626 rt->prev_pkt[1]);
627 ff_rtmp_packet_destroy(&pkt);
628
629 return ret;
630}
631
3505d557
SP
632int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
633 const uint8_t *key, int keylen, uint8_t *dst)
9fd6b843
KS
634{
635 struct AVSHA *sha;
636 uint8_t hmac_buf[64+32] = {0};
637 int i;
638
639 sha = av_mallocz(av_sha_size);
08e93f5b
SP
640 if (!sha)
641 return AVERROR(ENOMEM);
9fd6b843
KS
642
643 if (keylen < 64) {
644 memcpy(hmac_buf, key, keylen);
645 } else {
646 av_sha_init(sha, 256);
647 av_sha_update(sha,key, keylen);
648 av_sha_final(sha, hmac_buf);
649 }
650 for (i = 0; i < 64; i++)
651 hmac_buf[i] ^= HMAC_IPAD_VAL;
652
653 av_sha_init(sha, 256);
654 av_sha_update(sha, hmac_buf, 64);
655 if (gap <= 0) {
656 av_sha_update(sha, src, len);
657 } else { //skip 32 bytes used for storing digest
658 av_sha_update(sha, src, gap);
659 av_sha_update(sha, src + gap + 32, len - gap - 32);
660 }
661 av_sha_final(sha, hmac_buf + 64);
662
663 for (i = 0; i < 64; i++)
664 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
665 av_sha_init(sha, 256);
666 av_sha_update(sha, hmac_buf, 64+32);
667 av_sha_final(sha, dst);
668
669 av_free(sha);
08e93f5b
SP
670
671 return 0;
9fd6b843
KS
672}
673
0e31088b
SP
674int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
675 int add_val)
676{
677 int i, digest_pos = 0;
678
679 for (i = 0; i < 4; i++)
680 digest_pos += buf[i + off];
681 digest_pos = digest_pos % mod_val + add_val;
682
683 return digest_pos;
684}
685
9fd6b843 686/**
49bd8e4b 687 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
9fd6b843
KS
688 * will be stored) into that packet.
689 *
690 * @param buf handshake data (1536 bytes)
acd554c1 691 * @param encrypted use an encrypted connection (RTMPE)
9fd6b843
KS
692 * @return offset to the digest inside input data
693 */
acd554c1 694static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
9fd6b843 695{
0e31088b 696 int ret, digest_pos;
9fd6b843 697
acd554c1
SP
698 if (encrypted)
699 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
700 else
701 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
9fd6b843 702
3505d557
SP
703 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
704 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
705 buf + digest_pos);
08e93f5b
SP
706 if (ret < 0)
707 return ret;
708
9fd6b843
KS
709 return digest_pos;
710}
711
712/**
49bd8e4b 713 * Verify that the received server response has the expected digest value.
9fd6b843
KS
714 *
715 * @param buf handshake data received from the server (1536 bytes)
716 * @param off position to search digest offset from
717 * @return 0 if digest is valid, digest position otherwise
718 */
719static int rtmp_validate_digest(uint8_t *buf, int off)
720{
9fd6b843 721 uint8_t digest[32];
0e31088b 722 int ret, digest_pos;
9fd6b843 723
0e31088b 724 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
9fd6b843 725
3505d557
SP
726 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
727 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
728 digest);
08e93f5b
SP
729 if (ret < 0)
730 return ret;
731
9fd6b843
KS
732 if (!memcmp(digest, buf + digest_pos, 32))
733 return digest_pos;
734 return 0;
735}
736
737/**
49bd8e4b 738 * Perform handshake with the server by means of exchanging pseudorandom data
9fd6b843
KS
739 * signed with HMAC-SHA2 digest.
740 *
741 * @return 0 if handshake succeeds, negative value otherwise
742 */
743static int rtmp_handshake(URLContext *s, RTMPContext *rt)
744{
745 AVLFG rnd;
746 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
747 3, // unencrypted data
748 0, 0, 0, 0, // client uptime
749 RTMP_CLIENT_VER1,
750 RTMP_CLIENT_VER2,
751 RTMP_CLIENT_VER3,
752 RTMP_CLIENT_VER4,
753 };
754 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
755 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
756 int i;
757 int server_pos, client_pos;
acd554c1 758 uint8_t digest[32], signature[32];
acd554c1 759 int ret, type = 0;
9fd6b843 760
7f804085 761 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
9fd6b843
KS
762
763 av_lfg_init(&rnd, 0xDEADC0DE);
764 // generate handshake packet - 1536 bytes of pseudorandom data
765 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
766 tosend[i] = av_lfg_get(&rnd) >> 24;
acd554c1 767
f7bfb126 768 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
769 /* When the client wants to use RTMPE, we have to change the command
770 * byte to 0x06 which means to use encrypted data and we have to set
771 * the flash version to at least 9.0.115.0. */
772 tosend[0] = 6;
773 tosend[5] = 128;
774 tosend[6] = 0;
775 tosend[7] = 3;
776 tosend[8] = 2;
777
778 /* Initialize the Diffie-Hellmann context and generate the public key
779 * to send to the server. */
780 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
781 return ret;
782 }
783
f7bfb126 784 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
08e93f5b
SP
785 if (client_pos < 0)
786 return client_pos;
9fd6b843 787
bba287fd
SP
788 if ((ret = ffurl_write(rt->stream, tosend,
789 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
790 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
791 return ret;
792 }
793
177bcc95
SP
794 if ((ret = ffurl_read_complete(rt->stream, serverdata,
795 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
7f804085 796 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
177bcc95 797 return ret;
9fd6b843 798 }
177bcc95
SP
799
800 if ((ret = ffurl_read_complete(rt->stream, clientdata,
801 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
7f804085 802 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
177bcc95 803 return ret;
9fd6b843
KS
804 }
805
acd554c1 806 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
7f804085 807 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
9fd6b843
KS
808 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
809
e2ee11e8 810 if (rt->is_input && serverdata[5] >= 3) {
c7240611 811 server_pos = rtmp_validate_digest(serverdata + 1, 772);
08e93f5b
SP
812 if (server_pos < 0)
813 return server_pos;
814
9fd6b843 815 if (!server_pos) {
acd554c1 816 type = 1;
c7240611 817 server_pos = rtmp_validate_digest(serverdata + 1, 8);
08e93f5b
SP
818 if (server_pos < 0)
819 return server_pos;
820
c7240611 821 if (!server_pos) {
7f804085 822 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
a4d3f358 823 return AVERROR(EIO);
c7240611 824 }
9fd6b843 825 }
9fd6b843 826
3505d557
SP
827 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
828 rtmp_server_key, sizeof(rtmp_server_key),
829 digest);
08e93f5b
SP
830 if (ret < 0)
831 return ret;
832
3505d557 833 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
acd554c1 834 0, digest, 32, signature);
08e93f5b
SP
835 if (ret < 0)
836 return ret;
837
f7bfb126 838 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
839 /* Compute the shared secret key sent by the server and initialize
840 * the RC4 encryption. */
841 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
842 tosend + 1, type)) < 0)
843 return ret;
844
845 /* Encrypt the signature received by the server. */
846 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
847 }
848
849 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
7f804085 850 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
a4d3f358 851 return AVERROR(EIO);
c7240611 852 }
9fd6b843 853
c7240611
KS
854 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
855 tosend[i] = av_lfg_get(&rnd) >> 24;
3505d557
SP
856 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
857 rtmp_player_key, sizeof(rtmp_player_key),
858 digest);
08e93f5b
SP
859 if (ret < 0)
860 return ret;
861
3505d557
SP
862 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
863 digest, 32,
864 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
08e93f5b
SP
865 if (ret < 0)
866 return ret;
c7240611 867
f7bfb126 868 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
869 /* Encrypt the signature to be send to the server. */
870 ff_rtmpe_encrypt_sig(rt->stream, tosend +
871 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
872 serverdata[0]);
873 }
874
c7240611 875 // write reply back to the server
bba287fd
SP
876 if ((ret = ffurl_write(rt->stream, tosend,
877 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
878 return ret;
acd554c1 879
f7bfb126 880 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
881 /* Set RC4 keys for encryption and update the keystreams. */
882 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
883 return ret;
884 }
6bf22e18 885 } else {
f7bfb126 886 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
887 /* Compute the shared secret key sent by the server and initialize
888 * the RC4 encryption. */
889 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
890 tosend + 1, 1)) < 0)
891 return ret;
892
893 if (serverdata[0] == 9) {
894 /* Encrypt the signature received by the server. */
895 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
896 serverdata[0]);
897 }
898 }
899
bba287fd
SP
900 if ((ret = ffurl_write(rt->stream, serverdata + 1,
901 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
902 return ret;
acd554c1 903
f7bfb126 904 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
905 /* Set RC4 keys for encryption and update the keystreams. */
906 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
907 return ret;
908 }
6bf22e18
S
909 }
910
9fd6b843
KS
911 return 0;
912}
913
7be2a7d8
SP
914static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
915{
916 RTMPContext *rt = s->priv_data;
917 int ret;
918
e49e6b64 919 if (pkt->data_size < 4) {
7be2a7d8 920 av_log(s, AV_LOG_ERROR,
e49e6b64 921 "Too short chunk size change packet (%d)\n",
7be2a7d8 922 pkt->data_size);
e7ea6883 923 return AVERROR_INVALIDDATA;
7be2a7d8
SP
924 }
925
926 if (!rt->is_input) {
927 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
928 rt->prev_pkt[1])) < 0)
929 return ret;
930 }
931
932 rt->chunk_size = AV_RB32(pkt->data);
933 if (rt->chunk_size <= 0) {
934 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
e7ea6883 935 return AVERROR_INVALIDDATA;
7be2a7d8
SP
936 }
937 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
938
939 return 0;
940}
941
0ffd5161
SP
942static int handle_ping(URLContext *s, RTMPPacket *pkt)
943{
944 RTMPContext *rt = s->priv_data;
945 int t, ret;
946
8ea1459b
SP
947 if (pkt->data_size < 2) {
948 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
949 pkt->data_size);
950 return AVERROR_INVALIDDATA;
951 }
952
0ffd5161
SP
953 t = AV_RB16(pkt->data);
954 if (t == 6) {
955 if ((ret = gen_pong(s, rt, pkt)) < 0)
956 return ret;
957 }
958
959 return 0;
960}
961
912ecc9a
SP
962static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
963{
964 RTMPContext *rt = s->priv_data;
965
966 if (pkt->data_size < 4) {
967 av_log(s, AV_LOG_ERROR,
968 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
969 pkt->data_size);
088a82bb 970 return AVERROR_INVALIDDATA;
912ecc9a 971 }
abf77a24
SP
972
973 rt->client_report_size = AV_RB32(pkt->data);
974 if (rt->client_report_size <= 0) {
975 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
976 rt->client_report_size);
977 return AVERROR_INVALIDDATA;
978
979 }
980 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
981 rt->client_report_size >>= 1;
912ecc9a
SP
982
983 return 0;
984}
985
9b498148
SP
986static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
987{
988 RTMPContext *rt = s->priv_data;
989
2357f606
SP
990 if (pkt->data_size < 4) {
991 av_log(s, AV_LOG_ERROR,
992 "Too short server bandwidth report packet (%d)\n",
993 pkt->data_size);
994 return AVERROR_INVALIDDATA;
995 }
996
9b498148
SP
997 rt->server_bw = AV_RB32(pkt->data);
998 if (rt->server_bw <= 0) {
999 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1000 rt->server_bw);
be8f9492 1001 return AVERROR_INVALIDDATA;
9b498148
SP
1002 }
1003 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1004
1005 return 0;
1006}
1007
6d1c9945 1008static int handle_invoke(URLContext *s, RTMPPacket *pkt)
9fd6b843 1009{
6d1c9945 1010 RTMPContext *rt = s->priv_data;
9fd6b843
KS
1011 int i, t;
1012 const uint8_t *data_end = pkt->data + pkt->data_size;
f645f1d6 1013 int ret;
9fd6b843 1014
6d1c9945
SP
1015 //TODO: check for the messages sent for wrong state?
1016 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
1017 uint8_t tmpstr[256];
cfac91fe 1018
6d1c9945
SP
1019 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1020 "description", tmpstr, sizeof(tmpstr)))
1021 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
1022 return -1;
1023 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
1024 switch (rt->state) {
9fd6b843 1025 case STATE_HANDSHAKED:
6bf22e18 1026 if (!rt->is_input) {
f645f1d6
SP
1027 if ((ret = gen_release_stream(s, rt)) < 0)
1028 return ret;
1029 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1030 return ret;
6bf22e18
S
1031 rt->state = STATE_RELEASING;
1032 } else {
f645f1d6
SP
1033 if ((ret = gen_server_bw(s, rt)) < 0)
1034 return ret;
6bf22e18
S
1035 rt->state = STATE_CONNECTING;
1036 }
f645f1d6
SP
1037 if ((ret = gen_create_stream(s, rt)) < 0)
1038 return ret;
f9e77c17
SP
1039
1040 if (rt->is_input) {
00cb52c6
SP
1041 /* Send the FCSubscribe command when the name of live
1042 * stream is defined by the user or if it's a live stream. */
1043 if (rt->subscribe) {
1044 if ((ret = gen_fcsubscribe_stream(s, rt,
1045 rt->subscribe)) < 0)
1046 return ret;
1047 } else if (rt->live == -1) {
1048 if ((ret = gen_fcsubscribe_stream(s, rt,
1049 rt->playpath)) < 0)
f9e77c17
SP
1050 return ret;
1051 }
1052 }
6bf22e18
S
1053 break;
1054 case STATE_FCPUBLISH:
9fd6b843
KS
1055 rt->state = STATE_CONNECTING;
1056 break;
6bf22e18
S
1057 case STATE_RELEASING:
1058 rt->state = STATE_FCPUBLISH;
1059 /* hack for Wowza Media Server, it does not send result for
1060 * releaseStream and FCPublish calls */
1061 if (!pkt->data[10]) {
3383a53e 1062 int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
1eef08f9 1063 if (pkt_id == rt->create_stream_invoke)
6bf22e18
S
1064 rt->state = STATE_CONNECTING;
1065 }
e07c92e4 1066 if (rt->state != STATE_CONNECTING)
6bf22e18 1067 break;
9fd6b843
KS
1068 case STATE_CONNECTING:
1069 //extract a number from the result
1070 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
7f804085 1071 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
9fd6b843 1072 } else {
3383a53e 1073 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
9fd6b843 1074 }
6bf22e18 1075 if (rt->is_input) {
f645f1d6
SP
1076 if ((ret = gen_play(s, rt)) < 0)
1077 return ret;
9477c035
SP
1078 if ((ret = gen_buffer_time(s, rt)) < 0)
1079 return ret;
6bf22e18 1080 } else {
f645f1d6
SP
1081 if ((ret = gen_publish(s, rt)) < 0)
1082 return ret;
6bf22e18 1083 }
9fd6b843
KS
1084 rt->state = STATE_READY;
1085 break;
9fd6b843 1086 }
6d1c9945
SP
1087 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
1088 const uint8_t* ptr = pkt->data + 11;
1089 uint8_t tmpstr[256];
1090
1091 for (i = 0; i < 2; i++) {
1092 t = ff_amf_tag_size(ptr, data_end);
1093 if (t < 0)
1094 return 1;
1095 ptr += t;
1096 }
1097 t = ff_amf_get_field_value(ptr, data_end,
1098 "level", tmpstr, sizeof(tmpstr));
1099 if (!t && !strcmp(tmpstr, "error")) {
1100 if (!ff_amf_get_field_value(ptr, data_end,
1101 "description", tmpstr, sizeof(tmpstr)))
1102 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
1103 return -1;
1104 }
1105 t = ff_amf_get_field_value(ptr, data_end,
1106 "code", tmpstr, sizeof(tmpstr));
1107 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1108 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1109 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1110 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1111 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1112 if ((ret = gen_check_bw(s, rt)) < 0)
1113 return ret;
1114 }
1115
1116 return 0;
1117}
1118
1119/**
1120 * Parse received packet and possibly perform some action depending on
1121 * the packet contents.
1122 * @return 0 for no errors, negative values for serious errors which prevent
1123 * further communications, positive values for uncritical errors
1124 */
1125static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
1126{
1127 int ret;
1128
1129#ifdef DEBUG
1130 ff_rtmp_packet_dump(s, pkt);
1131#endif
1132
1133 switch (pkt->type) {
1134 case RTMP_PT_CHUNK_SIZE:
1135 if ((ret = handle_chunk_size(s, pkt)) < 0)
1136 return ret;
1137 break;
1138 case RTMP_PT_PING:
1139 if ((ret = handle_ping(s, pkt)) < 0)
1140 return ret;
1141 break;
1142 case RTMP_PT_CLIENT_BW:
1143 if ((ret = handle_client_bw(s, pkt)) < 0)
1144 return ret;
1145 break;
1146 case RTMP_PT_SERVER_BW:
1147 if ((ret = handle_server_bw(s, pkt)) < 0)
1148 return ret;
1149 break;
1150 case RTMP_PT_INVOKE:
1151 if ((ret = handle_invoke(s, pkt)) < 0)
1152 return ret;
9fd6b843 1153 break;
08e087cc
JO
1154 case RTMP_PT_VIDEO:
1155 case RTMP_PT_AUDIO:
9c9c21ea
SP
1156 case RTMP_PT_METADATA:
1157 /* Audio, Video and Metadata packets are parsed in get_packet() */
08e087cc 1158 break;
9ff930aa
SP
1159 default:
1160 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
1161 break;
9fd6b843
KS
1162 }
1163 return 0;
1164}
1165
1166/**
49bd8e4b 1167 * Interact with the server by receiving and sending RTMP packets until
9fd6b843
KS
1168 * there is some significant data (media data or expected status notification).
1169 *
1170 * @param s reading context
1d8041b3
SS
1171 * @param for_header non-zero value tells function to work until it
1172 * gets notification from the server that playing has been started,
1173 * otherwise function will work until some media data is received (or
1174 * an error happens)
9fd6b843
KS
1175 * @return 0 for successful operation, negative value in case of error
1176 */
1177static int get_packet(URLContext *s, int for_header)
1178{
1179 RTMPContext *rt = s->priv_data;
1180 int ret;
56e29bf2
S
1181 uint8_t *p;
1182 const uint8_t *next;
1183 uint32_t data_size;
1184 uint32_t ts, cts, pts=0;
9fd6b843 1185
72b870b9
MS
1186 if (rt->state == STATE_STOPPED)
1187 return AVERROR_EOF;
1188
e07c92e4 1189 for (;;) {
271c869c 1190 RTMPPacket rpkt = { 0 };
9fd6b843 1191 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
adb54961 1192 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
b381a823 1193 if (ret == 0) {
9fd6b843
KS
1194 return AVERROR(EAGAIN);
1195 } else {
1196 return AVERROR(EIO);
1197 }
1198 }
bf7c1719
KS
1199 rt->bytes_read += ret;
1200 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
7f804085 1201 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
f645f1d6
SP
1202 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1203 return ret;
bf7c1719
KS
1204 rt->last_bytes_read = rt->bytes_read;
1205 }
9fd6b843
KS
1206
1207 ret = rtmp_parse_result(s, rt, &rpkt);
1208 if (ret < 0) {//serious error in current packet
1209 ff_rtmp_packet_destroy(&rpkt);
f645f1d6 1210 return ret;
9fd6b843 1211 }
72b870b9
MS
1212 if (rt->state == STATE_STOPPED) {
1213 ff_rtmp_packet_destroy(&rpkt);
1214 return AVERROR_EOF;
1215 }
6bf22e18 1216 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
9fd6b843
KS
1217 ff_rtmp_packet_destroy(&rpkt);
1218 return 0;
1219 }
6bf22e18 1220 if (!rpkt.data_size || !rt->is_input) {
9fd6b843
KS
1221 ff_rtmp_packet_destroy(&rpkt);
1222 continue;
1223 }
1224 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
afbacb93 1225 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
56e29bf2 1226 ts = rpkt.timestamp;
9fd6b843 1227
9fd6b843
KS
1228 // generate packet header and put data into buffer for FLV demuxer
1229 rt->flv_off = 0;
1230 rt->flv_size = rpkt.data_size + 15;
1231 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1232 bytestream_put_byte(&p, rpkt.type);
1233 bytestream_put_be24(&p, rpkt.data_size);
1234 bytestream_put_be24(&p, ts);
1235 bytestream_put_byte(&p, ts >> 24);
1236 bytestream_put_be24(&p, 0);
1237 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1238 bytestream_put_be32(&p, 0);
1239 ff_rtmp_packet_destroy(&rpkt);
1240 return 0;
1241 } else if (rpkt.type == RTMP_PT_METADATA) {
1242 // we got raw FLV data, make it available for FLV demuxer
1243 rt->flv_off = 0;
1244 rt->flv_size = rpkt.data_size;
1245 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
56e29bf2
S
1246 /* rewrite timestamps */
1247 next = rpkt.data;
1248 ts = rpkt.timestamp;
1249 while (next - rpkt.data < rpkt.data_size - 11) {
1250 next++;
1251 data_size = bytestream_get_be24(&next);
1252 p=next;
1253 cts = bytestream_get_be24(&next);
aae9a093 1254 cts |= bytestream_get_byte(&next) << 24;
56e29bf2
S
1255 if (pts==0)
1256 pts=cts;
1257 ts += cts - pts;
1258 pts = cts;
1259 bytestream_put_be24(&p, ts);
1260 bytestream_put_byte(&p, ts >> 24);
1261 next += data_size + 3 + 4;
1262 }
9fd6b843
KS
1263 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1264 ff_rtmp_packet_destroy(&rpkt);
1265 return 0;
1266 }
1267 ff_rtmp_packet_destroy(&rpkt);
1268 }
9fd6b843
KS
1269}
1270
1271static int rtmp_close(URLContext *h)
1272{
1273 RTMPContext *rt = h->priv_data;
f645f1d6 1274 int ret = 0;
9fd6b843 1275
e07c92e4 1276 if (!rt->is_input) {
6bf22e18
S
1277 rt->flv_data = NULL;
1278 if (rt->out_pkt.data_size)
1279 ff_rtmp_packet_destroy(&rt->out_pkt);
615c2879 1280 if (rt->state > STATE_FCPUBLISH)
f645f1d6 1281 ret = gen_fcunpublish_stream(h, rt);
6bf22e18 1282 }
615c2879 1283 if (rt->state > STATE_HANDSHAKED)
f645f1d6 1284 ret = gen_delete_stream(h, rt);
6bf22e18 1285
9fd6b843 1286 av_freep(&rt->flv_data);
e52a9145 1287 ffurl_close(rt->stream);
f645f1d6 1288 return ret;
9fd6b843
KS
1289}
1290
1291/**
49bd8e4b 1292 * Open RTMP connection and verify that the stream can be played.
9fd6b843
KS
1293 *
1294 * URL syntax: rtmp://server[:port][/app][/playpath]
1295 * where 'app' is first one or two directories in the path
1296 * (e.g. /ondemand/, /flash/live/, etc.)
1297 * and 'playpath' is a file name (the rest of the path,
1298 * may be prefixed with "mp4:")
1299 */
1300static int rtmp_open(URLContext *s, const char *uri, int flags)
1301{
7e580505 1302 RTMPContext *rt = s->priv_data;
5e9ad759 1303 char proto[8], hostname[256], path[1024], *fname;
6465562e 1304 char *old_app;
9fd6b843 1305 uint8_t buf[2048];
b316991b 1306 int port;
86991ce2 1307 AVDictionary *opts = NULL;
9fd6b843
KS
1308 int ret;
1309
59d96941 1310 rt->is_input = !(flags & AVIO_FLAG_WRITE);
9fd6b843 1311
f3bfe388 1312 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
f984dcf6 1313 path, sizeof(path), s->filename);
9fd6b843 1314
86991ce2
SP
1315 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
1316 if (!strcmp(proto, "rtmpts"))
1317 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
1318
8e50c57d 1319 /* open the http tunneling connection */
775c4d36 1320 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
6aedabc9
SP
1321 } else if (!strcmp(proto, "rtmps")) {
1322 /* open the tls connection */
1323 if (port < 0)
1324 port = RTMPS_DEFAULT_PORT;
1325 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
08cd95e8
SP
1326 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
1327 if (!strcmp(proto, "rtmpte"))
1328 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
1329
acd554c1
SP
1330 /* open the encrypted connection */
1331 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
1332 rt->encrypted = 1;
8e50c57d
SP
1333 } else {
1334 /* open the tcp connection */
1335 if (port < 0)
1336 port = RTMP_DEFAULT_PORT;
1337 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1338 }
9fd6b843 1339
f645f1d6 1340 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
86991ce2 1341 &s->interrupt_callback, &opts)) < 0) {
59d96941 1342 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
9fd6b843 1343 goto fail;
fe523958 1344 }
9fd6b843 1345
c7240611 1346 rt->state = STATE_START;
f645f1d6 1347 if ((ret = rtmp_handshake(s, rt)) < 0)
02490bf3 1348 goto fail;
9fd6b843 1349
c7240611
KS
1350 rt->chunk_size = 128;
1351 rt->state = STATE_HANDSHAKED;
6465562e
SP
1352
1353 // Keep the application name when it has been defined by the user.
1354 old_app = rt->app;
1355
1356 rt->app = av_malloc(APP_MAX_LENGTH);
1357 if (!rt->app) {
f645f1d6
SP
1358 ret = AVERROR(ENOMEM);
1359 goto fail;
6465562e
SP
1360 }
1361
c7240611
KS
1362 //extract "app" part from path
1363 if (!strncmp(path, "/ondemand/", 10)) {
1364 fname = path + 10;
1365 memcpy(rt->app, "ondemand", 9);
1366 } else {
4b7304e8
MS
1367 char *next = *path ? path + 1 : path;
1368 char *p = strchr(next, '/');
c7240611 1369 if (!p) {
4b7304e8 1370 fname = next;
c7240611 1371 rt->app[0] = '\0';
9fd6b843 1372 } else {
c6eeb9b7 1373 // make sure we do not mismatch a playpath for an application instance
c7240611
KS
1374 char *c = strchr(p + 1, ':');
1375 fname = strchr(p + 1, '/');
c6eeb9b7 1376 if (!fname || (c && c < fname)) {
c7240611
KS
1377 fname = p + 1;
1378 av_strlcpy(rt->app, path + 1, p - path);
9fd6b843 1379 } else {
c7240611
KS
1380 fname++;
1381 av_strlcpy(rt->app, path + 1, fname - path - 1);
9fd6b843
KS
1382 }
1383 }
c7240611 1384 }
6465562e
SP
1385
1386 if (old_app) {
1387 // The name of application has been defined by the user, override it.
1388 av_free(rt->app);
1389 rt->app = old_app;
1390 }
1391
b3b17512 1392 if (!rt->playpath) {
f862537d
SP
1393 int len = strlen(fname);
1394
b3b17512
SP
1395 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1396 if (!rt->playpath) {
f645f1d6
SP
1397 ret = AVERROR(ENOMEM);
1398 goto fail;
b3b17512
SP
1399 }
1400
0a9a2257 1401 if (!strchr(fname, ':') && len >= 4 &&
f862537d
SP
1402 (!strcmp(fname + len - 4, ".f4v") ||
1403 !strcmp(fname + len - 4, ".mp4"))) {
b3b17512 1404 memcpy(rt->playpath, "mp4:", 5);
0a9a2257 1405 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
f862537d 1406 fname[len - 4] = '\0';
b3b17512
SP
1407 } else {
1408 rt->playpath[0] = 0;
1409 }
1410 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
c7240611 1411 }
9fd6b843 1412
55c9320e
SP
1413 if (!rt->tcurl) {
1414 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
08e93f5b
SP
1415 if (!rt->tcurl) {
1416 ret = AVERROR(ENOMEM);
1417 goto fail;
1418 }
55c9320e
SP
1419 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1420 port, "/%s", rt->app);
1421 }
1422
e64673e4
SP
1423 if (!rt->flashver) {
1424 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
08e93f5b
SP
1425 if (!rt->flashver) {
1426 ret = AVERROR(ENOMEM);
1427 goto fail;
1428 }
e64673e4
SP
1429 if (rt->is_input) {
1430 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1431 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1432 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1433 } else {
1434 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1435 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1436 }
1437 }
1438
bf7c1719
KS
1439 rt->client_report_size = 1048576;
1440 rt->bytes_read = 0;
1441 rt->last_bytes_read = 0;
c2d38bea 1442 rt->server_bw = 2500000;
bf7c1719 1443
7f804085 1444 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
c7240611 1445 proto, path, rt->app, rt->playpath);
f645f1d6
SP
1446 if ((ret = gen_connect(s, rt)) < 0)
1447 goto fail;
9fd6b843 1448
c7240611
KS
1449 do {
1450 ret = get_packet(s, 1);
1451 } while (ret == EAGAIN);
1452 if (ret < 0)
1453 goto fail;
6bf22e18
S
1454
1455 if (rt->is_input) {
9fd6b843
KS
1456 // generate FLV header for demuxer
1457 rt->flv_size = 13;
1458 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1459 rt->flv_off = 0;
1460 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
6bf22e18
S
1461 } else {
1462 rt->flv_size = 0;
1463 rt->flv_data = NULL;
1464 rt->flv_off = 0;
b14629e5 1465 rt->skip_bytes = 13;
9fd6b843
KS
1466 }
1467
5958df34 1468 s->max_packet_size = rt->stream->max_packet_size;
9fd6b843
KS
1469 s->is_streamed = 1;
1470 return 0;
1471
1472fail:
86991ce2 1473 av_dict_free(&opts);
9fd6b843 1474 rtmp_close(s);
f645f1d6 1475 return ret;
9fd6b843
KS
1476}
1477
1478static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1479{
1480 RTMPContext *rt = s->priv_data;
1481 int orig_size = size;
1482 int ret;
1483
1484 while (size > 0) {
1485 int data_left = rt->flv_size - rt->flv_off;
1486
1487 if (data_left >= size) {
1488 memcpy(buf, rt->flv_data + rt->flv_off, size);
1489 rt->flv_off += size;
1490 return orig_size;
1491 }
1492 if (data_left > 0) {
1493 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1494 buf += data_left;
1495 size -= data_left;
1496 rt->flv_off = rt->flv_size;
e8ccf245 1497 return data_left;
9fd6b843
KS
1498 }
1499 if ((ret = get_packet(s, 0)) < 0)
1500 return ret;
1501 }
1502 return orig_size;
1503}
1504
9ad4c65f 1505static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
9fd6b843 1506{
9ad4c65f 1507 RTMPContext *rt = s->priv_data;
6bf22e18
S
1508 int size_temp = size;
1509 int pktsize, pkttype;
1510 uint32_t ts;
1511 const uint8_t *buf_temp = buf;
7dc747f5 1512 uint8_t c;
f645f1d6 1513 int ret;
6bf22e18 1514
6bf22e18 1515 do {
b14629e5
MS
1516 if (rt->skip_bytes) {
1517 int skip = FFMIN(rt->skip_bytes, size_temp);
1518 buf_temp += skip;
1519 size_temp -= skip;
1520 rt->skip_bytes -= skip;
1521 continue;
1522 }
1523
1524 if (rt->flv_header_bytes < 11) {
1525 const uint8_t *header = rt->flv_header;
1526 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1527 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1528 rt->flv_header_bytes += copy;
1529 size_temp -= copy;
1530 if (rt->flv_header_bytes < 11)
1531 break;
6bf22e18 1532
b14629e5
MS
1533 pkttype = bytestream_get_byte(&header);
1534 pktsize = bytestream_get_be24(&header);
1535 ts = bytestream_get_be24(&header);
1536 ts |= bytestream_get_byte(&header) << 24;
1537 bytestream_get_be24(&header);
6bf22e18
S
1538 rt->flv_size = pktsize;
1539
1540 //force 12bytes header
1541 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1542 pkttype == RTMP_PT_NOTIFY) {
1543 if (pkttype == RTMP_PT_NOTIFY)
1544 pktsize += 16;
1545 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1546 }
1547
1548 //this can be a big packet, it's better to send it right here
f645f1d6
SP
1549 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1550 pkttype, ts, pktsize)) < 0)
1551 return ret;
1552
6bf22e18
S
1553 rt->out_pkt.extra = rt->main_channel_id;
1554 rt->flv_data = rt->out_pkt.data;
1555
1556 if (pkttype == RTMP_PT_NOTIFY)
1557 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1558 }
1559
1560 if (rt->flv_size - rt->flv_off > size_temp) {
1561 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1562 rt->flv_off += size_temp;
a14c7842 1563 size_temp = 0;
6bf22e18
S
1564 } else {
1565 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
a14c7842 1566 size_temp -= rt->flv_size - rt->flv_off;
6bf22e18
S
1567 rt->flv_off += rt->flv_size - rt->flv_off;
1568 }
1569
1570 if (rt->flv_off == rt->flv_size) {
b14629e5
MS
1571 rt->skip_bytes = 4;
1572
bba287fd
SP
1573 if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
1574 rt->chunk_size, rt->prev_pkt[1])) < 0)
1575 return ret;
6bf22e18
S
1576 ff_rtmp_packet_destroy(&rt->out_pkt);
1577 rt->flv_size = 0;
1578 rt->flv_off = 0;
b14629e5 1579 rt->flv_header_bytes = 0;
46743a85 1580 rt->flv_nb_packets++;
6bf22e18 1581 }
a14c7842 1582 } while (buf_temp - buf < size);
7dc747f5 1583
46743a85
SP
1584 if (rt->flv_nb_packets < rt->flush_interval)
1585 return size;
1586 rt->flv_nb_packets = 0;
1587
7dc747f5
SP
1588 /* set stream into nonblocking mode */
1589 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
1590
1591 /* try to read one byte from the stream */
1592 ret = ffurl_read(rt->stream, &c, 1);
1593
1594 /* switch the stream back into blocking mode */
1595 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
1596
1597 if (ret == AVERROR(EAGAIN)) {
1598 /* no incoming data to handle */
1599 return size;
1600 } else if (ret < 0) {
1601 return ret;
1602 } else if (ret == 1) {
1603 RTMPPacket rpkt = { 0 };
1604
1605 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
1606 rt->chunk_size,
1607 rt->prev_pkt[0], c)) <= 0)
1608 return ret;
1609
1610 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
1611 return ret;
1612
1613 ff_rtmp_packet_destroy(&rpkt);
1614 }
1615
6bf22e18 1616 return size;
9fd6b843
KS
1617}
1618
6465562e
SP
1619#define OFFSET(x) offsetof(RTMPContext, x)
1620#define DEC AV_OPT_FLAG_DECODING_PARAM
1621#define ENC AV_OPT_FLAG_ENCODING_PARAM
1622
1623static const AVOption rtmp_options[] = {
1624 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
8517e9c4 1625 {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {3000}, 0, INT_MAX, DEC|ENC},
8ee3e187 1626 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e64673e4 1627 {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
46743a85 1628 {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {10}, 0, INT_MAX, ENC},
b2e495af
SP
1629 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1630 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1631 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1632 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
758377a2 1633 {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
b3b17512 1634 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
00cb52c6 1635 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
05945db9 1636 {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
63ffa154 1637 {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
6465562e
SP
1638 { NULL },
1639};
1640
12127b65
SP
1641#define RTMP_PROTOCOL(flavor) \
1642static const AVClass flavor##_class = { \
1643 .class_name = #flavor, \
1644 .item_name = av_default_item_name, \
1645 .option = rtmp_options, \
1646 .version = LIBAVUTIL_VERSION_INT, \
1647}; \
1648 \
1649URLProtocol ff_##flavor##_protocol = { \
1650 .name = #flavor, \
1651 .url_open = rtmp_open, \
1652 .url_read = rtmp_read, \
1653 .url_write = rtmp_write, \
1654 .url_close = rtmp_close, \
1655 .priv_data_size = sizeof(RTMPContext), \
1656 .flags = URL_PROTOCOL_FLAG_NETWORK, \
1657 .priv_data_class= &flavor##_class, \
6465562e
SP
1658};
1659
08cd95e8 1660
12127b65
SP
1661RTMP_PROTOCOL(rtmp)
1662RTMP_PROTOCOL(rtmpe)
1663RTMP_PROTOCOL(rtmps)
1664RTMP_PROTOCOL(rtmpt)
1665RTMP_PROTOCOL(rtmpte)
1666RTMP_PROTOCOL(rtmpts)