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