rtmp: Add a function for writing AMF strings based on two substrings
[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"
e5f2731c 32#include "libavutil/random_seed.h"
9fd6b843
KS
33#include "libavutil/sha.h"
34#include "avformat.h"
e4a9e3cc 35#include "internal.h"
9fd6b843
KS
36
37#include "network.h"
38
39#include "flv.h"
40#include "rtmp.h"
acd554c1 41#include "rtmpcrypt.h"
9fd6b843 42#include "rtmppkt.h"
0589da0a 43#include "url.h"
9fd6b843 44
93f257db
SP
45#if CONFIG_ZLIB
46#include <zlib.h>
47#endif
48
cfac91fe
KS
49//#define DEBUG
50
6465562e 51#define APP_MAX_LENGTH 128
b3b17512 52#define PLAYPATH_MAX_LENGTH 256
55c9320e 53#define TCURL_MAX_LENGTH 512
e64673e4 54#define FLASHVER_MAX_LENGTH 64
e5f2731c 55#define RTMP_PKTDATA_DEFAULT_SIZE 4096
6465562e 56
9fd6b843
KS
57/** RTMP protocol handler state */
58typedef enum {
59 STATE_START, ///< client has not done anything yet
60 STATE_HANDSHAKED, ///< client has performed handshake
6bf22e18 61 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
9fd6b843 62 STATE_PLAYING, ///< client has started receiving multimedia data from server
6bf22e18 63 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
e5f2731c 64 STATE_RECEIVING, ///< received a publish command (for input)
72b870b9 65 STATE_STOPPED, ///< the broadcast has been stopped
9fd6b843
KS
66} ClientState;
67
f89584ca
SP
68typedef struct TrackedMethod {
69 char *name;
70 int id;
71} TrackedMethod;
72
9fd6b843
KS
73/** protocol handler context */
74typedef struct RTMPContext {
6465562e 75 const AVClass *class;
9fd6b843
KS
76 URLContext* stream; ///< TCP stream used in interactions with RTMP server
77 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
f5ce90f2
JO
78 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
79 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
b316991b 80 int is_input; ///< input/output flag
b3b17512 81 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
b2e495af 82 int live; ///< 0: recorded, -1: live, -2: both
6465562e 83 char *app; ///< name of application
8ee3e187 84 char *conn; ///< append arbitrary AMF data to the Connect message
9fd6b843
KS
85 ClientState state; ///< current state
86 int main_channel_id; ///< an additional channel ID which is used for some invocations
87 uint8_t* flv_data; ///< buffer with data for demuxer
88 int flv_size; ///< current buffer size
89 int flv_off; ///< number of bytes read from current buffer
46743a85 90 int flv_nb_packets; ///< number of flv packets published
6bf22e18 91 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
bf7c1719
KS
92 uint32_t client_report_size; ///< number of bytes after which client should report to server
93 uint32_t bytes_read; ///< number of bytes read from server
94 uint32_t last_bytes_read; ///< number of bytes read last reported to server
3ffe32eb 95 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
b14629e5
MS
96 uint8_t flv_header[11]; ///< partial incoming flv packet header
97 int flv_header_bytes; ///< number of initialized bytes in flv_header
704af3e2 98 int nb_invokes; ///< keeps track of invoke messages
55c9320e 99 char* tcurl; ///< url of the target stream
e64673e4 100 char* flashver; ///< version of the flash plugin
635ac8e1
SP
101 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
102 int swfhash_len; ///< length of the SHA256 hash
103 int swfsize; ///< size of the decompressed SWF file
05945db9 104 char* swfurl; ///< url of the swf player
93f257db 105 char* swfverify; ///< URL to player swf file, compute hash/size automatically
635ac8e1 106 char swfverification[42]; ///< hash of the SWF verification
758377a2 107 char* pageurl; ///< url of the web page
00cb52c6 108 char* subscribe; ///< name of live stream to subscribe
c2d38bea 109 int server_bw; ///< server bandwidth
9477c035 110 int client_buffer_time; ///< client buffer time in ms
46743a85 111 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
acd554c1 112 int encrypted; ///< use an encrypted connection (RTMPE only)
f89584ca
SP
113 TrackedMethod*tracked_methods; ///< tracked methods buffer
114 int nb_tracked_methods; ///< number of tracked methods
115 int tracked_methods_size; ///< size of the tracked methods buffer
e5f2731c
JO
116 int listen; ///< listen mode flag
117 int listen_timeout; ///< listen timeout to wait for new connections
118 int nb_streamid; ///< The next stream id to return on createStream calls
9fd6b843
KS
119} RTMPContext;
120
121#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
122/** Client key used for digest signing */
123static const uint8_t rtmp_player_key[] = {
124 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
125 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
126
127 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
128 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
129 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
130};
131
132#define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
133/** Key used for RTMP server digest signing */
134static const uint8_t rtmp_server_key[] = {
135 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
136 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
137 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
138
139 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
140 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
141 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
142};
143
f89584ca
SP
144static int add_tracked_method(RTMPContext *rt, const char *name, int id)
145{
146 void *ptr;
147
148 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
149 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
150 ptr = av_realloc(rt->tracked_methods,
151 rt->tracked_methods_size * sizeof(*rt->tracked_methods));
152 if (!ptr)
153 return AVERROR(ENOMEM);
154 rt->tracked_methods = ptr;
155 }
156
157 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
158 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
159 return AVERROR(ENOMEM);
160 rt->tracked_methods[rt->nb_tracked_methods].id = id;
161 rt->nb_tracked_methods++;
162
163 return 0;
164}
165
166static void del_tracked_method(RTMPContext *rt, int index)
167{
168 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
169 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
170 rt->nb_tracked_methods--;
171}
172
a8103503
SP
173static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
174 char **tracked_method)
175{
176 RTMPContext *rt = s->priv_data;
177 GetByteContext gbc;
178 double pkt_id;
179 int ret;
180 int i;
181
182 bytestream2_init(&gbc, pkt->data + offset, pkt->data_size - offset);
183 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
184 return ret;
185
186 for (i = 0; i < rt->nb_tracked_methods; i++) {
187 if (rt->tracked_methods[i].id != pkt_id)
188 continue;
189
190 *tracked_method = rt->tracked_methods[i].name;
191 del_tracked_method(rt, i);
192 break;
193 }
194
195 return 0;
196}
197
f89584ca
SP
198static void free_tracked_methods(RTMPContext *rt)
199{
200 int i;
201
202 for (i = 0; i < rt->nb_tracked_methods; i ++)
203 av_free(rt->tracked_methods[i].name);
204 av_free(rt->tracked_methods);
205}
206
207static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
208{
209 int ret;
210
211 if (pkt->type == RTMP_PT_INVOKE && track) {
212 GetByteContext gbc;
213 char name[128];
214 double pkt_id;
215 int len;
216
217 bytestream2_init(&gbc, pkt->data, pkt->data_size);
218 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
219 goto fail;
220
221 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
222 goto fail;
223
224 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
225 goto fail;
226 }
227
f5ce90f2 228 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
f89584ca
SP
229 rt->prev_pkt[1]);
230fail:
231 ff_rtmp_packet_destroy(pkt);
232 return ret;
233}
234
8ee3e187
SP
235static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
236{
05338686 237 char *field, *value;
8ee3e187
SP
238 char type;
239
240 /* The type must be B for Boolean, N for number, S for string, O for
241 * object, or Z for null. For Booleans the data must be either 0 or 1 for
242 * FALSE or TRUE, respectively. Likewise for Objects the data must be
243 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
244 * may be named, by prefixing the type with 'N' and specifying the name
245 * before the value (ie. NB:myFlag:1). This option may be used multiple times
246 * to construct arbitrary AMF sequences. */
247 if (param[0] && param[1] == ':') {
248 type = param[0];
249 value = param + 2;
250 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
251 type = param[1];
05338686
MS
252 field = param + 3;
253 value = strchr(field, ':');
254 if (!value)
255 goto fail;
256 *value = '\0';
257 value++;
8ee3e187
SP
258
259 if (!field || !value)
260 goto fail;
261
262 ff_amf_write_field_name(p, field);
263 } else {
264 goto fail;
265 }
266
267 switch (type) {
268 case 'B':
269 ff_amf_write_bool(p, value[0] != '0');
270 break;
271 case 'S':
272 ff_amf_write_string(p, value);
273 break;
274 case 'N':
275 ff_amf_write_number(p, strtod(value, NULL));
276 break;
277 case 'Z':
278 ff_amf_write_null(p);
279 break;
280 case 'O':
281 if (value[0] != '0')
282 ff_amf_write_object_start(p);
283 else
284 ff_amf_write_object_end(p);
285 break;
286 default:
287 goto fail;
288 break;
289 }
290
291 return 0;
292
293fail:
294 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
295 return AVERROR(EINVAL);
296}
297
9fd6b843 298/**
49bd8e4b 299 * Generate 'connect' call and send it to the server.
9fd6b843 300 */
f645f1d6 301static int gen_connect(URLContext *s, RTMPContext *rt)
9fd6b843
KS
302{
303 RTMPPacket pkt;
e64673e4 304 uint8_t *p;
f645f1d6
SP
305 int ret;
306
307 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
308 0, 4096)) < 0)
309 return ret;
9fd6b843 310
9fd6b843
KS
311 p = pkt.data;
312
9fd6b843 313 ff_amf_write_string(&p, "connect");
1eef08f9 314 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843
KS
315 ff_amf_write_object_start(&p);
316 ff_amf_write_field_name(&p, "app");
5e9ad759 317 ff_amf_write_string(&p, rt->app);
9fd6b843 318
e64673e4 319 if (!rt->is_input) {
6bf22e18
S
320 ff_amf_write_field_name(&p, "type");
321 ff_amf_write_string(&p, "nonprivate");
322 }
9fd6b843 323 ff_amf_write_field_name(&p, "flashVer");
e64673e4 324 ff_amf_write_string(&p, rt->flashver);
05945db9
SP
325
326 if (rt->swfurl) {
327 ff_amf_write_field_name(&p, "swfUrl");
328 ff_amf_write_string(&p, rt->swfurl);
329 }
330
9fd6b843 331 ff_amf_write_field_name(&p, "tcUrl");
55c9320e 332 ff_amf_write_string(&p, rt->tcurl);
6bf22e18 333 if (rt->is_input) {
c7240611
KS
334 ff_amf_write_field_name(&p, "fpad");
335 ff_amf_write_bool(&p, 0);
336 ff_amf_write_field_name(&p, "capabilities");
337 ff_amf_write_number(&p, 15.0);
faba4a9b
SP
338
339 /* Tell the server we support all the audio codecs except
340 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
341 * which are unused in the RTMP protocol implementation. */
c7240611 342 ff_amf_write_field_name(&p, "audioCodecs");
faba4a9b 343 ff_amf_write_number(&p, 4071.0);
c7240611
KS
344 ff_amf_write_field_name(&p, "videoCodecs");
345 ff_amf_write_number(&p, 252.0);
346 ff_amf_write_field_name(&p, "videoFunction");
347 ff_amf_write_number(&p, 1.0);
758377a2
SP
348
349 if (rt->pageurl) {
350 ff_amf_write_field_name(&p, "pageUrl");
351 ff_amf_write_string(&p, rt->pageurl);
352 }
6bf22e18 353 }
9fd6b843
KS
354 ff_amf_write_object_end(&p);
355
8ee3e187 356 if (rt->conn) {
05338686 357 char *param = rt->conn;
8ee3e187
SP
358
359 // Write arbitrary AMF data to the Connect message.
8ee3e187 360 while (param != NULL) {
05338686
MS
361 char *sep;
362 param += strspn(param, " ");
363 if (!*param)
364 break;
365 sep = strchr(param, ' ');
366 if (sep)
367 *sep = '\0';
8ee3e187
SP
368 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
369 // Invalid AMF parameter.
370 ff_rtmp_packet_destroy(&pkt);
371 return ret;
372 }
373
05338686
MS
374 if (sep)
375 param = sep + 1;
376 else
377 break;
8ee3e187
SP
378 }
379 }
380
9fd6b843
KS
381 pkt.data_size = p - pkt.data;
382
f89584ca 383 return rtmp_send_packet(rt, &pkt, 1);
9fd6b843
KS
384}
385
e5f2731c
JO
386static int read_connect(URLContext *s, RTMPContext *rt)
387{
388 RTMPPacket pkt = { 0 };
389 uint8_t *p;
390 const uint8_t *cp;
391 int ret;
392 char command[64];
393 int stringlen;
394 double seqnum;
395 uint8_t tmpstr[256];
396 GetByteContext gbc;
397
398 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
399 rt->prev_pkt[1])) < 0)
400 return ret;
401 cp = pkt.data;
402 bytestream2_init(&gbc, cp, pkt.data_size);
403 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
404 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
405 ff_rtmp_packet_destroy(&pkt);
406 return AVERROR_INVALIDDATA;
407 }
408 if (strcmp(command, "connect")) {
409 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
410 ff_rtmp_packet_destroy(&pkt);
411 return AVERROR_INVALIDDATA;
412 }
413 ret = ff_amf_read_number(&gbc, &seqnum);
414 if (ret)
415 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
416 /* Here one could parse an AMF Object with data as flashVers and others. */
417 ret = ff_amf_get_field_value(gbc.buffer,
418 gbc.buffer + bytestream2_get_bytes_left(&gbc),
419 "app", tmpstr, sizeof(tmpstr));
420 if (ret)
421 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
422 if (!ret && strcmp(tmpstr, rt->app))
423 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
424 tmpstr, rt->app);
425 ff_rtmp_packet_destroy(&pkt);
426
427 // Send Window Acknowledgement Size (as defined in speficication)
428 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
429 RTMP_PT_SERVER_BW, 0, 4)) < 0)
430 return ret;
431 p = pkt.data;
432 bytestream_put_be32(&p, rt->server_bw);
433 pkt.data_size = p - pkt.data;
434 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
435 rt->prev_pkt[1]);
436 ff_rtmp_packet_destroy(&pkt);
437 if (ret < 0)
438 return ret;
439 // Send Peer Bandwidth
440 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
441 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
442 return ret;
443 p = pkt.data;
444 bytestream_put_be32(&p, rt->server_bw);
445 bytestream_put_byte(&p, 2); // dynamic
446 pkt.data_size = p - pkt.data;
447 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
448 rt->prev_pkt[1]);
449 ff_rtmp_packet_destroy(&pkt);
450 if (ret < 0)
451 return ret;
452
453 // Ping request
454 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
455 RTMP_PT_PING, 0, 6)) < 0)
456 return ret;
457
458 p = pkt.data;
459 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
460 bytestream_put_be32(&p, 0);
461 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
462 rt->prev_pkt[1]);
463 ff_rtmp_packet_destroy(&pkt);
464 if (ret < 0)
465 return ret;
466
467 // Chunk size
468 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
469 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
470 return ret;
471
472 p = pkt.data;
473 bytestream_put_be32(&p, rt->out_chunk_size);
474 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
475 rt->prev_pkt[1]);
476 ff_rtmp_packet_destroy(&pkt);
477 if (ret < 0)
478 return ret;
479
480 // Send result_ NetConnection.Connect.Success to connect
481 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
482 RTMP_PT_INVOKE, 0,
483 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
484 return ret;
485
486 p = pkt.data;
487 ff_amf_write_string(&p, "_result");
488 ff_amf_write_number(&p, seqnum);
489
490 ff_amf_write_object_start(&p);
491 ff_amf_write_field_name(&p, "fmsVer");
492 ff_amf_write_string(&p, "FMS/3,0,1,123");
493 ff_amf_write_field_name(&p, "capabilities");
494 ff_amf_write_number(&p, 31);
495 ff_amf_write_object_end(&p);
496
497 ff_amf_write_object_start(&p);
498 ff_amf_write_field_name(&p, "level");
499 ff_amf_write_string(&p, "status");
500 ff_amf_write_field_name(&p, "code");
501 ff_amf_write_string(&p, "NetConnection.Connect.Success");
502 ff_amf_write_field_name(&p, "description");
503 ff_amf_write_string(&p, "Connection succeeded.");
504 ff_amf_write_field_name(&p, "objectEncoding");
505 ff_amf_write_number(&p, 0);
506 ff_amf_write_object_end(&p);
507
508 pkt.data_size = p - pkt.data;
509 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
510 rt->prev_pkt[1]);
511 ff_rtmp_packet_destroy(&pkt);
512 if (ret < 0)
513 return ret;
514
515 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
516 RTMP_PT_INVOKE, 0, 30)) < 0)
517 return ret;
518 p = pkt.data;
519 ff_amf_write_string(&p, "onBWDone");
520 ff_amf_write_number(&p, 0);
521 ff_amf_write_null(&p);
522 ff_amf_write_number(&p, 8192);
523 pkt.data_size = p - pkt.data;
524 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
525 rt->prev_pkt[1]);
526 ff_rtmp_packet_destroy(&pkt);
527
528 return ret;
529}
530
9fd6b843 531/**
49bd8e4b 532 * Generate 'releaseStream' call and send it to the server. It should make
6bf22e18
S
533 * the server release some channel for media streams.
534 */
f645f1d6 535static int gen_release_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
536{
537 RTMPPacket pkt;
538 uint8_t *p;
f645f1d6 539 int ret;
6bf22e18 540
f645f1d6
SP
541 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
542 0, 29 + strlen(rt->playpath))) < 0)
543 return ret;
6bf22e18 544
7f804085 545 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
6bf22e18
S
546 p = pkt.data;
547 ff_amf_write_string(&p, "releaseStream");
704af3e2 548 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
549 ff_amf_write_null(&p);
550 ff_amf_write_string(&p, rt->playpath);
551
7011a42b 552 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
553}
554
555/**
49bd8e4b 556 * Generate 'FCPublish' call and send it to the server. It should make
6bf22e18
S
557 * the server preapare for receiving media streams.
558 */
f645f1d6 559static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
560{
561 RTMPPacket pkt;
562 uint8_t *p;
f645f1d6 563 int ret;
6bf22e18 564
f645f1d6
SP
565 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
566 0, 25 + strlen(rt->playpath))) < 0)
567 return ret;
6bf22e18 568
7f804085 569 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
6bf22e18
S
570 p = pkt.data;
571 ff_amf_write_string(&p, "FCPublish");
704af3e2 572 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
573 ff_amf_write_null(&p);
574 ff_amf_write_string(&p, rt->playpath);
575
7011a42b 576 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
577}
578
579/**
49bd8e4b 580 * Generate 'FCUnpublish' call and send it to the server. It should make
6bf22e18
S
581 * the server destroy stream.
582 */
f645f1d6 583static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
584{
585 RTMPPacket pkt;
586 uint8_t *p;
f645f1d6 587 int ret;
6bf22e18 588
f645f1d6
SP
589 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
590 0, 27 + strlen(rt->playpath))) < 0)
591 return ret;
6bf22e18 592
7f804085 593 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
6bf22e18
S
594 p = pkt.data;
595 ff_amf_write_string(&p, "FCUnpublish");
704af3e2 596 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
597 ff_amf_write_null(&p);
598 ff_amf_write_string(&p, rt->playpath);
599
f89584ca 600 return rtmp_send_packet(rt, &pkt, 0);
6bf22e18
S
601}
602
603/**
49bd8e4b 604 * Generate 'createStream' call and send it to the server. It should make
9fd6b843
KS
605 * the server allocate some channel for media streams.
606 */
f645f1d6 607static int gen_create_stream(URLContext *s, RTMPContext *rt)
9fd6b843
KS
608{
609 RTMPPacket pkt;
610 uint8_t *p;
f645f1d6 611 int ret;
9fd6b843 612
7f804085 613 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
f645f1d6
SP
614
615 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
616 0, 25)) < 0)
617 return ret;
9fd6b843
KS
618
619 p = pkt.data;
620 ff_amf_write_string(&p, "createStream");
704af3e2 621 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
622 ff_amf_write_null(&p);
623
f89584ca 624 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
625}
626
627
628/**
49bd8e4b 629 * Generate 'deleteStream' call and send it to the server. It should make
6bf22e18
S
630 * the server remove some channel for media streams.
631 */
f645f1d6 632static int gen_delete_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
633{
634 RTMPPacket pkt;
635 uint8_t *p;
f645f1d6 636 int ret;
6bf22e18 637
7f804085 638 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
f645f1d6
SP
639
640 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
641 0, 34)) < 0)
642 return ret;
6bf22e18
S
643
644 p = pkt.data;
645 ff_amf_write_string(&p, "deleteStream");
1eef08f9 646 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843 647 ff_amf_write_null(&p);
6bf22e18 648 ff_amf_write_number(&p, rt->main_channel_id);
9fd6b843 649
f89584ca 650 return rtmp_send_packet(rt, &pkt, 0);
9fd6b843
KS
651}
652
653/**
9477c035
SP
654 * Generate client buffer time and send it to the server.
655 */
656static int gen_buffer_time(URLContext *s, RTMPContext *rt)
657{
658 RTMPPacket pkt;
659 uint8_t *p;
660 int ret;
661
662 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
663 1, 10)) < 0)
664 return ret;
665
666 p = pkt.data;
667 bytestream_put_be16(&p, 3);
668 bytestream_put_be32(&p, rt->main_channel_id);
669 bytestream_put_be32(&p, rt->client_buffer_time);
670
f89584ca 671 return rtmp_send_packet(rt, &pkt, 0);
9477c035
SP
672}
673
674/**
49bd8e4b 675 * Generate 'play' call and send it to the server, then ping the server
9fd6b843
KS
676 * to start actual playing.
677 */
f645f1d6 678static int gen_play(URLContext *s, RTMPContext *rt)
9fd6b843
KS
679{
680 RTMPPacket pkt;
681 uint8_t *p;
f645f1d6 682 int ret;
9fd6b843 683
7f804085 684 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
f645f1d6
SP
685
686 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
687 0, 29 + strlen(rt->playpath))) < 0)
688 return ret;
689
9fd6b843
KS
690 pkt.extra = rt->main_channel_id;
691
692 p = pkt.data;
693 ff_amf_write_string(&p, "play");
1eef08f9 694 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843
KS
695 ff_amf_write_null(&p);
696 ff_amf_write_string(&p, rt->playpath);
b2e495af 697 ff_amf_write_number(&p, rt->live);
9fd6b843 698
f89584ca 699 return rtmp_send_packet(rt, &pkt, 1);
9fd6b843
KS
700}
701
702/**
49bd8e4b 703 * Generate 'publish' call and send it to the server.
6bf22e18 704 */
f645f1d6 705static int gen_publish(URLContext *s, RTMPContext *rt)
6bf22e18
S
706{
707 RTMPPacket pkt;
708 uint8_t *p;
f645f1d6 709 int ret;
6bf22e18 710
7f804085 711 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
f645f1d6
SP
712
713 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
714 0, 30 + strlen(rt->playpath))) < 0)
715 return ret;
716
6bf22e18
S
717 pkt.extra = rt->main_channel_id;
718
719 p = pkt.data;
720 ff_amf_write_string(&p, "publish");
1eef08f9 721 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
722 ff_amf_write_null(&p);
723 ff_amf_write_string(&p, rt->playpath);
724 ff_amf_write_string(&p, "live");
725
f89584ca 726 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
727}
728
729/**
49bd8e4b 730 * Generate ping reply and send it to the server.
9fd6b843 731 */
f645f1d6 732static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
9fd6b843
KS
733{
734 RTMPPacket pkt;
735 uint8_t *p;
f645f1d6
SP
736 int ret;
737
8ea1459b
SP
738 if (ppkt->data_size < 6) {
739 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
740 ppkt->data_size);
741 return AVERROR_INVALIDDATA;
742 }
743
f645f1d6
SP
744 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
745 ppkt->timestamp + 1, 6)) < 0)
746 return ret;
9fd6b843 747
9fd6b843
KS
748 p = pkt.data;
749 bytestream_put_be16(&p, 7);
4aaebf78 750 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
f645f1d6 751
f89584ca 752 return rtmp_send_packet(rt, &pkt, 0);
9fd6b843
KS
753}
754
bf7c1719 755/**
635ac8e1
SP
756 * Generate SWF verification message and send it to the server.
757 */
758static int gen_swf_verification(URLContext *s, RTMPContext *rt)
759{
760 RTMPPacket pkt;
761 uint8_t *p;
762 int ret;
763
764 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
765 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
766 0, 44)) < 0)
767 return ret;
768
769 p = pkt.data;
770 bytestream_put_be16(&p, 27);
771 memcpy(p, rt->swfverification, 42);
772
773 return rtmp_send_packet(rt, &pkt, 0);
774}
775
776/**
34d908c0
RS
777 * Generate server bandwidth message and send it to the server.
778 */
f645f1d6 779static int gen_server_bw(URLContext *s, RTMPContext *rt)
34d908c0
RS
780{
781 RTMPPacket pkt;
782 uint8_t *p;
f645f1d6
SP
783 int ret;
784
785 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
786 0, 4)) < 0)
787 return ret;
34d908c0 788
34d908c0 789 p = pkt.data;
c2d38bea 790 bytestream_put_be32(&p, rt->server_bw);
f645f1d6 791
f89584ca 792 return rtmp_send_packet(rt, &pkt, 0);
34d908c0
RS
793}
794
795/**
d55961fa
SP
796 * Generate check bandwidth message and send it to the server.
797 */
f645f1d6 798static int gen_check_bw(URLContext *s, RTMPContext *rt)
d55961fa
SP
799{
800 RTMPPacket pkt;
801 uint8_t *p;
f645f1d6 802 int ret;
d55961fa 803
f645f1d6
SP
804 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
805 0, 21)) < 0)
806 return ret;
d55961fa
SP
807
808 p = pkt.data;
809 ff_amf_write_string(&p, "_checkbw");
8b6a5a79 810 ff_amf_write_number(&p, ++rt->nb_invokes);
d55961fa
SP
811 ff_amf_write_null(&p);
812
fb7e7808 813 return rtmp_send_packet(rt, &pkt, 1);
d55961fa
SP
814}
815
816/**
49bd8e4b 817 * Generate report on bytes read so far and send it to the server.
bf7c1719 818 */
f645f1d6 819static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
bf7c1719
KS
820{
821 RTMPPacket pkt;
822 uint8_t *p;
f645f1d6
SP
823 int ret;
824
825 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
826 ts, 4)) < 0)
827 return ret;
bf7c1719 828
bf7c1719
KS
829 p = pkt.data;
830 bytestream_put_be32(&p, rt->bytes_read);
f645f1d6 831
f89584ca 832 return rtmp_send_packet(rt, &pkt, 0);
bf7c1719
KS
833}
834
00cb52c6
SP
835static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
836 const char *subscribe)
f9e77c17
SP
837{
838 RTMPPacket pkt;
839 uint8_t *p;
840 int ret;
841
842 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
00cb52c6 843 0, 27 + strlen(subscribe))) < 0)
f9e77c17
SP
844 return ret;
845
846 p = pkt.data;
847 ff_amf_write_string(&p, "FCSubscribe");
848 ff_amf_write_number(&p, ++rt->nb_invokes);
849 ff_amf_write_null(&p);
00cb52c6 850 ff_amf_write_string(&p, subscribe);
f9e77c17 851
f89584ca 852 return rtmp_send_packet(rt, &pkt, 1);
f9e77c17
SP
853}
854
3505d557
SP
855int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
856 const uint8_t *key, int keylen, uint8_t *dst)
9fd6b843
KS
857{
858 struct AVSHA *sha;
859 uint8_t hmac_buf[64+32] = {0};
860 int i;
861
e002e329 862 sha = av_sha_alloc();
08e93f5b
SP
863 if (!sha)
864 return AVERROR(ENOMEM);
9fd6b843
KS
865
866 if (keylen < 64) {
867 memcpy(hmac_buf, key, keylen);
868 } else {
869 av_sha_init(sha, 256);
870 av_sha_update(sha,key, keylen);
871 av_sha_final(sha, hmac_buf);
872 }
873 for (i = 0; i < 64; i++)
874 hmac_buf[i] ^= HMAC_IPAD_VAL;
875
876 av_sha_init(sha, 256);
877 av_sha_update(sha, hmac_buf, 64);
878 if (gap <= 0) {
879 av_sha_update(sha, src, len);
880 } else { //skip 32 bytes used for storing digest
881 av_sha_update(sha, src, gap);
882 av_sha_update(sha, src + gap + 32, len - gap - 32);
883 }
884 av_sha_final(sha, hmac_buf + 64);
885
886 for (i = 0; i < 64; i++)
887 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
888 av_sha_init(sha, 256);
889 av_sha_update(sha, hmac_buf, 64+32);
890 av_sha_final(sha, dst);
891
892 av_free(sha);
08e93f5b
SP
893
894 return 0;
9fd6b843
KS
895}
896
0e31088b
SP
897int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
898 int add_val)
899{
900 int i, digest_pos = 0;
901
902 for (i = 0; i < 4; i++)
903 digest_pos += buf[i + off];
904 digest_pos = digest_pos % mod_val + add_val;
905
906 return digest_pos;
907}
908
9fd6b843 909/**
49bd8e4b 910 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
9fd6b843
KS
911 * will be stored) into that packet.
912 *
913 * @param buf handshake data (1536 bytes)
acd554c1 914 * @param encrypted use an encrypted connection (RTMPE)
9fd6b843
KS
915 * @return offset to the digest inside input data
916 */
acd554c1 917static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
9fd6b843 918{
0e31088b 919 int ret, digest_pos;
9fd6b843 920
acd554c1
SP
921 if (encrypted)
922 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
923 else
924 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
9fd6b843 925
3505d557
SP
926 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
927 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
928 buf + digest_pos);
08e93f5b
SP
929 if (ret < 0)
930 return ret;
931
9fd6b843
KS
932 return digest_pos;
933}
934
935/**
49bd8e4b 936 * Verify that the received server response has the expected digest value.
9fd6b843
KS
937 *
938 * @param buf handshake data received from the server (1536 bytes)
939 * @param off position to search digest offset from
940 * @return 0 if digest is valid, digest position otherwise
941 */
942static int rtmp_validate_digest(uint8_t *buf, int off)
943{
9fd6b843 944 uint8_t digest[32];
0e31088b 945 int ret, digest_pos;
9fd6b843 946
0e31088b 947 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
9fd6b843 948
3505d557
SP
949 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
950 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
951 digest);
08e93f5b
SP
952 if (ret < 0)
953 return ret;
954
9fd6b843
KS
955 if (!memcmp(digest, buf + digest_pos, 32))
956 return digest_pos;
957 return 0;
958}
959
635ac8e1
SP
960static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
961 uint8_t *buf)
962{
963 uint8_t *p;
964 int ret;
965
966 if (rt->swfhash_len != 32) {
967 av_log(s, AV_LOG_ERROR,
968 "Hash of the decompressed SWF file is not 32 bytes long.\n");
969 return AVERROR(EINVAL);
970 }
971
972 p = &rt->swfverification[0];
973 bytestream_put_byte(&p, 1);
974 bytestream_put_byte(&p, 1);
975 bytestream_put_be32(&p, rt->swfsize);
976 bytestream_put_be32(&p, rt->swfsize);
977
978 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
979 return ret;
980
981 return 0;
982}
983
93f257db
SP
984#if CONFIG_ZLIB
985static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
986 uint8_t **out_data, int64_t *out_size)
987{
988 z_stream zs = { 0 };
989 void *ptr;
990 int size;
991 int ret = 0;
992
993 zs.avail_in = in_size;
994 zs.next_in = in_data;
995 ret = inflateInit(&zs);
996 if (ret != Z_OK)
997 return AVERROR_UNKNOWN;
998
999 do {
1000 uint8_t tmp_buf[16384];
1001
1002 zs.avail_out = sizeof(tmp_buf);
1003 zs.next_out = tmp_buf;
1004
1005 ret = inflate(&zs, Z_NO_FLUSH);
1006 if (ret != Z_OK && ret != Z_STREAM_END) {
1007 ret = AVERROR_UNKNOWN;
1008 goto fail;
1009 }
1010
1011 size = sizeof(tmp_buf) - zs.avail_out;
1012 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1013 ret = AVERROR(ENOMEM);
1014 goto fail;
1015 }
1016 *out_data = ptr;
1017
1018 memcpy(*out_data + *out_size, tmp_buf, size);
1019 *out_size += size;
1020 } while (zs.avail_out == 0);
1021
1022fail:
1023 inflateEnd(&zs);
1024 return ret;
1025}
1026#endif
1027
1028static int rtmp_calc_swfhash(URLContext *s)
1029{
1030 RTMPContext *rt = s->priv_data;
1031 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1032 int64_t in_size, out_size;
1033 URLContext *stream;
1034 char swfhash[32];
1035 int swfsize;
1036 int ret = 0;
1037
1038 /* Get the SWF player file. */
1039 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1040 &s->interrupt_callback, NULL)) < 0) {
1041 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1042 goto fail;
1043 }
1044
1045 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1046 ret = AVERROR(EIO);
1047 goto fail;
1048 }
1049
1050 if (!(in_data = av_malloc(in_size))) {
1051 ret = AVERROR(ENOMEM);
1052 goto fail;
1053 }
1054
1055 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1056 goto fail;
1057
1058 if (in_size < 3) {
1059 ret = AVERROR_INVALIDDATA;
1060 goto fail;
1061 }
1062
1063 if (!memcmp(in_data, "CWS", 3)) {
1064 /* Decompress the SWF player file using Zlib. */
1065 if (!(out_data = av_malloc(8))) {
1066 ret = AVERROR(ENOMEM);
1067 goto fail;
1068 }
1069 *in_data = 'F'; // magic stuff
1070 memcpy(out_data, in_data, 8);
1071 out_size = 8;
1072
1073#if CONFIG_ZLIB
1074 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1075 &out_data, &out_size)) < 0)
1076 goto fail;
1077#else
1078 av_log(s, AV_LOG_ERROR,
1079 "Zlib is required for decompressing the SWF player file.\n");
1080 ret = AVERROR(EINVAL);
1081 goto fail;
1082#endif
1083 swfsize = out_size;
1084 swfdata = out_data;
1085 } else {
1086 swfsize = in_size;
1087 swfdata = in_data;
1088 }
1089
1090 /* Compute the SHA256 hash of the SWF player file. */
1091 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1092 "Genuine Adobe Flash Player 001", 30,
1093 swfhash)) < 0)
1094 goto fail;
1095
1096 /* Set SWFVerification parameters. */
1097 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1098 rt->swfsize = swfsize;
1099
1100fail:
1101 av_freep(&in_data);
1102 av_freep(&out_data);
1103 ffurl_close(stream);
1104 return ret;
1105}
1106
9fd6b843 1107/**
49bd8e4b 1108 * Perform handshake with the server by means of exchanging pseudorandom data
9fd6b843
KS
1109 * signed with HMAC-SHA2 digest.
1110 *
1111 * @return 0 if handshake succeeds, negative value otherwise
1112 */
1113static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1114{
1115 AVLFG rnd;
1116 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1117 3, // unencrypted data
1118 0, 0, 0, 0, // client uptime
1119 RTMP_CLIENT_VER1,
1120 RTMP_CLIENT_VER2,
1121 RTMP_CLIENT_VER3,
1122 RTMP_CLIENT_VER4,
1123 };
1124 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1125 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1126 int i;
1127 int server_pos, client_pos;
acd554c1 1128 uint8_t digest[32], signature[32];
acd554c1 1129 int ret, type = 0;
9fd6b843 1130
7f804085 1131 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
9fd6b843
KS
1132
1133 av_lfg_init(&rnd, 0xDEADC0DE);
1134 // generate handshake packet - 1536 bytes of pseudorandom data
1135 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1136 tosend[i] = av_lfg_get(&rnd) >> 24;
acd554c1 1137
f7bfb126 1138 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1139 /* When the client wants to use RTMPE, we have to change the command
1140 * byte to 0x06 which means to use encrypted data and we have to set
1141 * the flash version to at least 9.0.115.0. */
1142 tosend[0] = 6;
1143 tosend[5] = 128;
1144 tosend[6] = 0;
1145 tosend[7] = 3;
1146 tosend[8] = 2;
1147
1148 /* Initialize the Diffie-Hellmann context and generate the public key
1149 * to send to the server. */
1150 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1151 return ret;
1152 }
1153
f7bfb126 1154 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
08e93f5b
SP
1155 if (client_pos < 0)
1156 return client_pos;
9fd6b843 1157
bba287fd
SP
1158 if ((ret = ffurl_write(rt->stream, tosend,
1159 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1160 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1161 return ret;
1162 }
1163
177bcc95
SP
1164 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1165 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
7f804085 1166 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
177bcc95 1167 return ret;
9fd6b843 1168 }
177bcc95
SP
1169
1170 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1171 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
7f804085 1172 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
177bcc95 1173 return ret;
9fd6b843
KS
1174 }
1175
acd554c1 1176 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
7f804085 1177 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
9fd6b843
KS
1178 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1179
e2ee11e8 1180 if (rt->is_input && serverdata[5] >= 3) {
c7240611 1181 server_pos = rtmp_validate_digest(serverdata + 1, 772);
08e93f5b
SP
1182 if (server_pos < 0)
1183 return server_pos;
1184
9fd6b843 1185 if (!server_pos) {
acd554c1 1186 type = 1;
c7240611 1187 server_pos = rtmp_validate_digest(serverdata + 1, 8);
08e93f5b
SP
1188 if (server_pos < 0)
1189 return server_pos;
1190
c7240611 1191 if (!server_pos) {
7f804085 1192 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
a4d3f358 1193 return AVERROR(EIO);
c7240611 1194 }
9fd6b843 1195 }
9fd6b843 1196
635ac8e1
SP
1197 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1198 * key are the last 32 bytes of the server handshake. */
1199 if (rt->swfsize) {
1200 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1201 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1202 return ret;
1203 }
1204
3505d557
SP
1205 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1206 rtmp_server_key, sizeof(rtmp_server_key),
1207 digest);
08e93f5b
SP
1208 if (ret < 0)
1209 return ret;
1210
3505d557 1211 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
acd554c1 1212 0, digest, 32, signature);
08e93f5b
SP
1213 if (ret < 0)
1214 return ret;
1215
f7bfb126 1216 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1217 /* Compute the shared secret key sent by the server and initialize
1218 * the RC4 encryption. */
1219 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1220 tosend + 1, type)) < 0)
1221 return ret;
1222
1223 /* Encrypt the signature received by the server. */
1224 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1225 }
1226
1227 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
7f804085 1228 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
a4d3f358 1229 return AVERROR(EIO);
c7240611 1230 }
9fd6b843 1231
c7240611
KS
1232 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1233 tosend[i] = av_lfg_get(&rnd) >> 24;
3505d557
SP
1234 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1235 rtmp_player_key, sizeof(rtmp_player_key),
1236 digest);
08e93f5b
SP
1237 if (ret < 0)
1238 return ret;
1239
3505d557
SP
1240 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1241 digest, 32,
1242 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
08e93f5b
SP
1243 if (ret < 0)
1244 return ret;
c7240611 1245
f7bfb126 1246 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1247 /* Encrypt the signature to be send to the server. */
1248 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1249 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1250 serverdata[0]);
1251 }
1252
c7240611 1253 // write reply back to the server
bba287fd
SP
1254 if ((ret = ffurl_write(rt->stream, tosend,
1255 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1256 return ret;
acd554c1 1257
f7bfb126 1258 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1259 /* Set RC4 keys for encryption and update the keystreams. */
1260 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1261 return ret;
1262 }
6bf22e18 1263 } else {
f7bfb126 1264 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1265 /* Compute the shared secret key sent by the server and initialize
1266 * the RC4 encryption. */
1267 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1268 tosend + 1, 1)) < 0)
1269 return ret;
1270
1271 if (serverdata[0] == 9) {
1272 /* Encrypt the signature received by the server. */
1273 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1274 serverdata[0]);
1275 }
1276 }
1277
bba287fd
SP
1278 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1279 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1280 return ret;
acd554c1 1281
f7bfb126 1282 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1283 /* Set RC4 keys for encryption and update the keystreams. */
1284 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1285 return ret;
1286 }
6bf22e18
S
1287 }
1288
9fd6b843
KS
1289 return 0;
1290}
1291
e5f2731c
JO
1292static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1293 uint32_t *second_int, char *arraydata,
1294 int size)
1295{
cb5ab02a 1296 int inoutsize;
e5f2731c
JO
1297
1298 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1299 RTMP_HANDSHAKE_PACKET_SIZE);
1300 if (inoutsize <= 0)
1301 return AVERROR(EIO);
1302 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1303 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1304 " not following standard\n", (int)inoutsize);
1305 return AVERROR(EINVAL);
1306 }
1307
1308 *first_int = AV_RB32(arraydata);
1309 *second_int = AV_RB32(arraydata + 4);
1310 return 0;
1311}
1312
1313static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1314 uint32_t second_int, char *arraydata, int size)
1315{
cb5ab02a 1316 int inoutsize;
e5f2731c
JO
1317
1318 AV_WB32(arraydata, first_int);
1319 AV_WB32(arraydata + 4, first_int);
1320 inoutsize = ffurl_write(rt->stream, arraydata,
1321 RTMP_HANDSHAKE_PACKET_SIZE);
1322 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1323 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1324 return AVERROR(EIO);
1325 }
1326
1327 return 0;
1328}
1329
1330/**
1331 * rtmp handshake server side
1332 */
1333static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1334{
1335 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1336 uint32_t hs_epoch;
1337 uint32_t hs_my_epoch;
1338 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1339 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1340 uint32_t zeroes;
1341 uint32_t temp = 0;
1342 int randomidx = 0;
cb5ab02a 1343 int inoutsize = 0;
e5f2731c
JO
1344 int ret;
1345
1346 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1347 if (inoutsize <= 0) {
1348 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1349 return AVERROR(EIO);
1350 }
1351 // Check Version
1352 if (buffer[0] != 3) {
1353 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1354 return AVERROR(EIO);
1355 }
1356 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1357 av_log(s, AV_LOG_ERROR,
1358 "Unable to write answer - RTMP S0\n");
1359 return AVERROR(EIO);
1360 }
1361 /* Receive C1 */
1362 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1363 RTMP_HANDSHAKE_PACKET_SIZE);
1364 if (ret) {
1365 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1366 return ret;
1367 }
1368 if (zeroes)
1369 av_log(s, AV_LOG_WARNING, "Erroneous C1 Message zero != 0\n");
1370 /* Send S1 */
1371 /* By now same epoch will be sent */
1372 hs_my_epoch = hs_epoch;
1373 /* Generate random */
2f1b2ff9 1374 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
e5f2731c 1375 randomidx += 4)
2f1b2ff9 1376 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
e5f2731c
JO
1377
1378 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1379 RTMP_HANDSHAKE_PACKET_SIZE);
1380 if (ret) {
1381 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1382 return ret;
1383 }
1384 /* Send S2 */
1385 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1386 RTMP_HANDSHAKE_PACKET_SIZE);
1387 if (ret) {
1388 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1389 return ret;
1390 }
1391 /* Receive C2 */
1392 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1393 RTMP_HANDSHAKE_PACKET_SIZE);
1394 if (ret) {
1395 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1396 return ret;
1397 }
1398 if (temp != hs_my_epoch)
1399 av_log(s, AV_LOG_WARNING,
1400 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1401 if (memcmp(buffer + 8, hs_s1 + 8,
1402 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1403 av_log(s, AV_LOG_WARNING,
1404 "Erroneous C2 Message random does not match up\n");
1405
1406 return 0;
1407}
1408
7be2a7d8
SP
1409static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1410{
1411 RTMPContext *rt = s->priv_data;
1412 int ret;
1413
e49e6b64 1414 if (pkt->data_size < 4) {
7be2a7d8 1415 av_log(s, AV_LOG_ERROR,
e49e6b64 1416 "Too short chunk size change packet (%d)\n",
7be2a7d8 1417 pkt->data_size);
e7ea6883 1418 return AVERROR_INVALIDDATA;
7be2a7d8
SP
1419 }
1420
1421 if (!rt->is_input) {
f5ce90f2
JO
1422 /* Send the same chunk size change packet back to the server,
1423 * setting the outgoing chunk size to the same as the incoming one. */
1424 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
7be2a7d8
SP
1425 rt->prev_pkt[1])) < 0)
1426 return ret;
f5ce90f2 1427 rt->out_chunk_size = AV_RB32(pkt->data);
7be2a7d8
SP
1428 }
1429
f5ce90f2
JO
1430 rt->in_chunk_size = AV_RB32(pkt->data);
1431 if (rt->in_chunk_size <= 0) {
1432 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1433 rt->in_chunk_size);
e7ea6883 1434 return AVERROR_INVALIDDATA;
7be2a7d8 1435 }
f5ce90f2
JO
1436 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1437 rt->in_chunk_size);
7be2a7d8
SP
1438
1439 return 0;
1440}
1441
0ffd5161
SP
1442static int handle_ping(URLContext *s, RTMPPacket *pkt)
1443{
1444 RTMPContext *rt = s->priv_data;
1445 int t, ret;
1446
8ea1459b
SP
1447 if (pkt->data_size < 2) {
1448 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1449 pkt->data_size);
1450 return AVERROR_INVALIDDATA;
1451 }
1452
0ffd5161
SP
1453 t = AV_RB16(pkt->data);
1454 if (t == 6) {
1455 if ((ret = gen_pong(s, rt, pkt)) < 0)
1456 return ret;
635ac8e1
SP
1457 } else if (t == 26) {
1458 if (rt->swfsize) {
1459 if ((ret = gen_swf_verification(s, rt)) < 0)
1460 return ret;
1461 } else {
1462 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1463 }
0ffd5161
SP
1464 }
1465
1466 return 0;
1467}
1468
912ecc9a
SP
1469static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1470{
1471 RTMPContext *rt = s->priv_data;
1472
1473 if (pkt->data_size < 4) {
1474 av_log(s, AV_LOG_ERROR,
1475 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1476 pkt->data_size);
088a82bb 1477 return AVERROR_INVALIDDATA;
912ecc9a 1478 }
abf77a24
SP
1479
1480 rt->client_report_size = AV_RB32(pkt->data);
1481 if (rt->client_report_size <= 0) {
1482 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1483 rt->client_report_size);
1484 return AVERROR_INVALIDDATA;
1485
1486 }
1487 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1488 rt->client_report_size >>= 1;
912ecc9a
SP
1489
1490 return 0;
1491}
1492
9b498148
SP
1493static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1494{
1495 RTMPContext *rt = s->priv_data;
1496
2357f606
SP
1497 if (pkt->data_size < 4) {
1498 av_log(s, AV_LOG_ERROR,
1499 "Too short server bandwidth report packet (%d)\n",
1500 pkt->data_size);
1501 return AVERROR_INVALIDDATA;
1502 }
1503
9b498148
SP
1504 rt->server_bw = AV_RB32(pkt->data);
1505 if (rt->server_bw <= 0) {
1506 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1507 rt->server_bw);
be8f9492 1508 return AVERROR_INVALIDDATA;
9b498148
SP
1509 }
1510 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1511
1512 return 0;
1513}
1514
3eebc1e1
SP
1515static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1516{
1517 const uint8_t *data_end = pkt->data + pkt->data_size;
fb7e7808
SP
1518 char *tracked_method = NULL;
1519 int level = AV_LOG_ERROR;
3eebc1e1 1520 uint8_t tmpstr[256];
fb7e7808
SP
1521 int ret;
1522
1523 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1524 return ret;
3eebc1e1
SP
1525
1526 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1527 "description", tmpstr, sizeof(tmpstr))) {
7011a42b
SP
1528 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1529 !strcmp(tracked_method, "releaseStream") ||
1530 !strcmp(tracked_method, "FCSubscribe") ||
1531 !strcmp(tracked_method, "FCPublish"))) {
1532 /* Gracefully ignore Adobe-specific historical artifact errors. */
fb7e7808
SP
1533 level = AV_LOG_WARNING;
1534 ret = 0;
1535 } else
c76daa89 1536 ret = AVERROR_UNKNOWN;
fb7e7808 1537 av_log(s, level, "Server error: %s\n", tmpstr);
3eebc1e1
SP
1538 }
1539
fb7e7808
SP
1540 av_free(tracked_method);
1541 return ret;
3eebc1e1
SP
1542}
1543
e5f2731c
JO
1544static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1545{
1546 RTMPContext *rt = s->priv_data;
1547 double seqnum;
1548 char filename[64];
1549 char command[64];
1550 char statusmsg[128];
1551 int stringlen;
1552 char *pchar;
1553 const uint8_t *p = pkt->data;
1554 uint8_t *pp = NULL;
1555 RTMPPacket spkt = { 0 };
1556 GetByteContext gbc;
1557 int ret;
1558
1559 bytestream2_init(&gbc, p, pkt->data_size);
1560 if (ff_amf_read_string(&gbc, command, sizeof(command),
1561 &stringlen)) {
1562 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1563 return AVERROR_INVALIDDATA;
1564 }
1565
1566 ret = ff_amf_read_number(&gbc, &seqnum);
1567 if (ret)
1568 return ret;
1569 ret = ff_amf_read_null(&gbc);
1570 if (ret)
1571 return ret;
1572 if (!strcmp(command, "FCPublish") ||
1573 !strcmp(command, "publish")) {
1574 ret = ff_amf_read_string(&gbc, filename,
1575 sizeof(filename), &stringlen);
1576 // check with url
1577 if (s->filename) {
1578 pchar = strrchr(s->filename, '/');
1579 if (!pchar) {
1580 av_log(s, AV_LOG_WARNING,
1581 "Unable to find / in url %s, bad format\n",
1582 s->filename);
1583 pchar = s->filename;
1584 }
1585 pchar++;
1586 if (strcmp(pchar, filename))
1587 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1588 " %s\n", filename, pchar);
1589 }
1590 rt->state = STATE_RECEIVING;
1591 }
1592
1593 if (!strcmp(command, "FCPublish")) {
1594 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1595 RTMP_PT_INVOKE, 0,
1596 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1597 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1598 return ret;
1599 }
1600 pp = spkt.data;
1601 ff_amf_write_string(&pp, "onFCPublish");
1602 } else if (!strcmp(command, "publish")) {
1603 PutByteContext pbc;
1604 // Send Stream Begin 1
1605 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1606 RTMP_PT_PING, 0, 6)) < 0) {
1607 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1608 return ret;
1609 }
1610 pp = spkt.data;
1611 bytestream2_init_writer(&pbc, pp, spkt.data_size);
1612 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1613 bytestream2_put_be32(&pbc, rt->nb_streamid);
1614 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1615 rt->prev_pkt[1]);
1616 ff_rtmp_packet_destroy(&spkt);
1617 if (ret < 0)
1618 return ret;
1619
1620 // Send onStatus(NetStream.Publish.Start)
1621 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1622 RTMP_PT_INVOKE, 0,
1623 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1624 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1625 return ret;
1626 }
1627 spkt.extra = pkt->extra;
1628 pp = spkt.data;
1629 ff_amf_write_string(&pp, "onStatus");
1630 ff_amf_write_number(&pp, 0);
1631 ff_amf_write_null(&pp);
1632
1633 ff_amf_write_object_start(&pp);
1634 ff_amf_write_field_name(&pp, "level");
1635 ff_amf_write_string(&pp, "status");
1636 ff_amf_write_field_name(&pp, "code");
1637 ff_amf_write_string(&pp, "NetStream.Publish.Start");
1638 ff_amf_write_field_name(&pp, "description");
1639 snprintf(statusmsg, sizeof(statusmsg),
1640 "%s is now published", filename);
1641 ff_amf_write_string(&pp, statusmsg);
1642 ff_amf_write_field_name(&pp, "details");
1643 ff_amf_write_string(&pp, filename);
1644 ff_amf_write_field_name(&pp, "clientid");
1645 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1646 ff_amf_write_string(&pp, statusmsg);
1647 ff_amf_write_object_end(&pp);
1648
1649 } else {
1650 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1651 RTMP_PT_INVOKE, 0,
1652 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1653 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1654 return ret;
1655 }
1656 pp = spkt.data;
1657 ff_amf_write_string(&pp, "_result");
1658 ff_amf_write_number(&pp, seqnum);
1659 ff_amf_write_null(&pp);
1660 if (!strcmp(command, "createStream")) {
1661 rt->nb_streamid++;
1662 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1663 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1664 ff_amf_write_number(&pp, rt->nb_streamid);
1665 /* By now we don't control which streams are removed in
1666 * deleteStream. There is no stream creation control
1667 * if a client creates more than 2^32 - 2 streams. */
1668 }
1669 }
1670 spkt.data_size = pp - spkt.data;
1671 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1672 rt->prev_pkt[1]);
1673 ff_rtmp_packet_destroy(&spkt);
1674 return ret;
1675}
1676
5e6001db
SP
1677static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
1678{
1679 RTMPContext *rt = s->priv_data;
1680 char *tracked_method = NULL;
5e6001db 1681 int ret = 0;
5e6001db 1682
a8103503 1683 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
5e6001db
SP
1684 return ret;
1685
5e6001db
SP
1686 if (!tracked_method) {
1687 /* Ignore this reply when the current method is not tracked. */
1688 return ret;
1689 }
1690
1691 if (!memcmp(tracked_method, "connect", 7)) {
1692 if (!rt->is_input) {
1693 if ((ret = gen_release_stream(s, rt)) < 0)
1694 goto fail;
1695
1696 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1697 goto fail;
1698 } else {
1699 if ((ret = gen_server_bw(s, rt)) < 0)
1700 goto fail;
1701 }
1702
1703 if ((ret = gen_create_stream(s, rt)) < 0)
1704 goto fail;
1705
1706 if (rt->is_input) {
1707 /* Send the FCSubscribe command when the name of live
1708 * stream is defined by the user or if it's a live stream. */
1709 if (rt->subscribe) {
1710 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
1711 goto fail;
1712 } else if (rt->live == -1) {
1713 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
1714 goto fail;
1715 }
1716 }
1717 } else if (!memcmp(tracked_method, "createStream", 12)) {
1718 //extract a number from the result
1719 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1720 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
1721 } else {
1722 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
1723 }
1724
1725 if (!rt->is_input) {
1726 if ((ret = gen_publish(s, rt)) < 0)
1727 goto fail;
1728 } else {
1729 if ((ret = gen_play(s, rt)) < 0)
1730 goto fail;
1731 if ((ret = gen_buffer_time(s, rt)) < 0)
1732 goto fail;
1733 }
1734 }
1735
1736fail:
1737 av_free(tracked_method);
1738 return ret;
1739}
1740
71036a3a 1741static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
9fd6b843 1742{
6d1c9945 1743 RTMPContext *rt = s->priv_data;
71036a3a
SP
1744 const uint8_t *data_end = pkt->data + pkt->data_size;
1745 const uint8_t *ptr = pkt->data + 11;
1746 uint8_t tmpstr[256];
9fd6b843 1747 int i, t;
71036a3a
SP
1748
1749 for (i = 0; i < 2; i++) {
1750 t = ff_amf_tag_size(ptr, data_end);
1751 if (t < 0)
1752 return 1;
1753 ptr += t;
1754 }
1755
1756 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
1757 if (!t && !strcmp(tmpstr, "error")) {
1758 if (!ff_amf_get_field_value(ptr, data_end,
1759 "description", tmpstr, sizeof(tmpstr)))
1760 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
1761 return -1;
1762 }
1763
1764 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
1765 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1766 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1767 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1768 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1769
1770 return 0;
1771}
1772
1773static int handle_invoke(URLContext *s, RTMPPacket *pkt)
1774{
1775 RTMPContext *rt = s->priv_data;
f89584ca 1776 int ret = 0;
9fd6b843 1777
6d1c9945
SP
1778 //TODO: check for the messages sent for wrong state?
1779 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
3eebc1e1
SP
1780 if ((ret = handle_invoke_error(s, pkt)) < 0)
1781 return ret;
6d1c9945 1782 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
5e6001db 1783 if ((ret = handle_invoke_result(s, pkt)) < 0)
f89584ca 1784 return ret;
6d1c9945 1785 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
71036a3a
SP
1786 if ((ret = handle_invoke_status(s, pkt)) < 0)
1787 return ret;
6d1c9945
SP
1788 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1789 if ((ret = gen_check_bw(s, rt)) < 0)
1790 return ret;
e5f2731c
JO
1791 } else if (!memcmp(pkt->data, "\002\000\015releaseStream", 16) ||
1792 !memcmp(pkt->data, "\002\000\011FCPublish", 12) ||
1793 !memcmp(pkt->data, "\002\000\007publish", 10) ||
1794 !memcmp(pkt->data, "\002\000\010_checkbw", 11) ||
1795 !memcmp(pkt->data, "\002\000\014createStream", 15)) {
1796 if (ret = send_invoke_response(s, pkt) < 0)
1797 return ret;
6d1c9945
SP
1798 }
1799
f89584ca 1800 return ret;
6d1c9945
SP
1801}
1802
e5f2731c
JO
1803static int handle_notify(URLContext *s, RTMPPacket *pkt) {
1804 RTMPContext *rt = s->priv_data;
1805 const uint8_t *p = NULL;
1806 uint8_t *cp = NULL;
1807 uint8_t commandbuffer[64];
1808 char statusmsg[128];
1809 int stringlen;
1810 GetByteContext gbc;
1811 PutByteContext pbc;
1812 uint32_t ts;
1813 int old_flv_size;
1814 const uint8_t *datatowrite;
1815 unsigned datatowritelength;
1816
1817 p = pkt->data;
1818 bytestream2_init(&gbc, p, pkt->data_size);
1819 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
1820 &stringlen))
1821 return AVERROR_INVALIDDATA;
1822 if (!strcmp(commandbuffer, "@setDataFrame")) {
1823 datatowrite = gbc.buffer;
1824 datatowritelength = bytestream2_get_bytes_left(&gbc);
1825 if (ff_amf_read_string(&gbc, statusmsg,
1826 sizeof(statusmsg), &stringlen))
1827 return AVERROR_INVALIDDATA;
1828 if (strcmp(statusmsg, "onMetaData")) {
1829 av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n",
1830 statusmsg);
1831 return 0;
1832 }
1833
1834 /* Provide ECMAArray to flv */
1835 ts = pkt->timestamp;
1836
1837 // generate packet header and put data into buffer for FLV demuxer
1838 if (rt->flv_off < rt->flv_size) {
1839 old_flv_size = rt->flv_size;
1840 rt->flv_size += datatowritelength + 15;
1841 } else {
1842 old_flv_size = 0;
1843 rt->flv_size = datatowritelength + 15;
1844 rt->flv_off = 0;
1845 }
1846
1847 cp = av_realloc(rt->flv_data, rt->flv_size);
1848 if (!cp)
1849 return AVERROR(ENOMEM);
1850 rt->flv_data = cp;
1851 bytestream2_init_writer(&pbc, cp, rt->flv_size);
1852 bytestream2_skip_p(&pbc, old_flv_size);
1853 bytestream2_put_byte(&pbc, pkt->type);
1854 bytestream2_put_be24(&pbc, datatowritelength);
1855 bytestream2_put_be24(&pbc, ts);
1856 bytestream2_put_byte(&pbc, ts >> 24);
1857 bytestream2_put_be24(&pbc, 0);
1858 bytestream2_put_buffer(&pbc, datatowrite, datatowritelength);
1859 bytestream2_put_be32(&pbc, 0);
1860 }
1861 return 0;
1862}
1863
6d1c9945
SP
1864/**
1865 * Parse received packet and possibly perform some action depending on
1866 * the packet contents.
1867 * @return 0 for no errors, negative values for serious errors which prevent
1868 * further communications, positive values for uncritical errors
1869 */
1870static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
1871{
1872 int ret;
1873
1874#ifdef DEBUG
1875 ff_rtmp_packet_dump(s, pkt);
1876#endif
1877
1878 switch (pkt->type) {
fb96c1c5
LB
1879 case RTMP_PT_BYTES_READ:
1880 av_dlog(s, "received bytes read report\n");
1881 break;
6d1c9945
SP
1882 case RTMP_PT_CHUNK_SIZE:
1883 if ((ret = handle_chunk_size(s, pkt)) < 0)
1884 return ret;
1885 break;
1886 case RTMP_PT_PING:
1887 if ((ret = handle_ping(s, pkt)) < 0)
1888 return ret;
1889 break;
1890 case RTMP_PT_CLIENT_BW:
1891 if ((ret = handle_client_bw(s, pkt)) < 0)
1892 return ret;
1893 break;
1894 case RTMP_PT_SERVER_BW:
1895 if ((ret = handle_server_bw(s, pkt)) < 0)
1896 return ret;
1897 break;
1898 case RTMP_PT_INVOKE:
1899 if ((ret = handle_invoke(s, pkt)) < 0)
1900 return ret;
9fd6b843 1901 break;
08e087cc
JO
1902 case RTMP_PT_VIDEO:
1903 case RTMP_PT_AUDIO:
9c9c21ea 1904 case RTMP_PT_METADATA:
e5f2731c 1905 case RTMP_PT_NOTIFY:
9c9c21ea 1906 /* Audio, Video and Metadata packets are parsed in get_packet() */
08e087cc 1907 break;
9ff930aa
SP
1908 default:
1909 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
1910 break;
9fd6b843
KS
1911 }
1912 return 0;
1913}
1914
1915/**
49bd8e4b 1916 * Interact with the server by receiving and sending RTMP packets until
9fd6b843
KS
1917 * there is some significant data (media data or expected status notification).
1918 *
1919 * @param s reading context
1d8041b3
SS
1920 * @param for_header non-zero value tells function to work until it
1921 * gets notification from the server that playing has been started,
1922 * otherwise function will work until some media data is received (or
1923 * an error happens)
9fd6b843
KS
1924 * @return 0 for successful operation, negative value in case of error
1925 */
1926static int get_packet(URLContext *s, int for_header)
1927{
1928 RTMPContext *rt = s->priv_data;
1929 int ret;
56e29bf2
S
1930 uint8_t *p;
1931 const uint8_t *next;
1932 uint32_t data_size;
1933 uint32_t ts, cts, pts=0;
9fd6b843 1934
72b870b9
MS
1935 if (rt->state == STATE_STOPPED)
1936 return AVERROR_EOF;
1937
e07c92e4 1938 for (;;) {
271c869c 1939 RTMPPacket rpkt = { 0 };
9fd6b843 1940 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
f5ce90f2 1941 rt->in_chunk_size, rt->prev_pkt[0])) <= 0) {
b381a823 1942 if (ret == 0) {
9fd6b843
KS
1943 return AVERROR(EAGAIN);
1944 } else {
1945 return AVERROR(EIO);
1946 }
1947 }
bf7c1719
KS
1948 rt->bytes_read += ret;
1949 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
7f804085 1950 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
f645f1d6
SP
1951 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1952 return ret;
bf7c1719
KS
1953 rt->last_bytes_read = rt->bytes_read;
1954 }
9fd6b843
KS
1955
1956 ret = rtmp_parse_result(s, rt, &rpkt);
1957 if (ret < 0) {//serious error in current packet
1958 ff_rtmp_packet_destroy(&rpkt);
f645f1d6 1959 return ret;
9fd6b843 1960 }
72b870b9
MS
1961 if (rt->state == STATE_STOPPED) {
1962 ff_rtmp_packet_destroy(&rpkt);
1963 return AVERROR_EOF;
1964 }
e5f2731c
JO
1965 if (for_header && (rt->state == STATE_PLAYING ||
1966 rt->state == STATE_PUBLISHING ||
1967 rt->state == STATE_RECEIVING)) {
9fd6b843
KS
1968 ff_rtmp_packet_destroy(&rpkt);
1969 return 0;
1970 }
6bf22e18 1971 if (!rpkt.data_size || !rt->is_input) {
9fd6b843
KS
1972 ff_rtmp_packet_destroy(&rpkt);
1973 continue;
1974 }
1975 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
afbacb93 1976 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
56e29bf2 1977 ts = rpkt.timestamp;
9fd6b843 1978
9fd6b843
KS
1979 // generate packet header and put data into buffer for FLV demuxer
1980 rt->flv_off = 0;
1981 rt->flv_size = rpkt.data_size + 15;
1982 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1983 bytestream_put_byte(&p, rpkt.type);
1984 bytestream_put_be24(&p, rpkt.data_size);
1985 bytestream_put_be24(&p, ts);
1986 bytestream_put_byte(&p, ts >> 24);
1987 bytestream_put_be24(&p, 0);
1988 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1989 bytestream_put_be32(&p, 0);
1990 ff_rtmp_packet_destroy(&rpkt);
1991 return 0;
e5f2731c
JO
1992 } else if (rpkt.type == RTMP_PT_NOTIFY) {
1993 ret = handle_notify(s, &rpkt);
1994 ff_rtmp_packet_destroy(&rpkt);
1995 if (ret) {
1996 av_log(s, AV_LOG_ERROR, "Handle notify error\n");
1997 return ret;
1998 }
1999 return 0;
9fd6b843
KS
2000 } else if (rpkt.type == RTMP_PT_METADATA) {
2001 // we got raw FLV data, make it available for FLV demuxer
2002 rt->flv_off = 0;
2003 rt->flv_size = rpkt.data_size;
2004 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
56e29bf2
S
2005 /* rewrite timestamps */
2006 next = rpkt.data;
2007 ts = rpkt.timestamp;
2008 while (next - rpkt.data < rpkt.data_size - 11) {
2009 next++;
2010 data_size = bytestream_get_be24(&next);
2011 p=next;
2012 cts = bytestream_get_be24(&next);
aae9a093 2013 cts |= bytestream_get_byte(&next) << 24;
56e29bf2
S
2014 if (pts==0)
2015 pts=cts;
2016 ts += cts - pts;
2017 pts = cts;
2018 bytestream_put_be24(&p, ts);
2019 bytestream_put_byte(&p, ts >> 24);
2020 next += data_size + 3 + 4;
2021 }
9fd6b843
KS
2022 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
2023 ff_rtmp_packet_destroy(&rpkt);
2024 return 0;
2025 }
2026 ff_rtmp_packet_destroy(&rpkt);
2027 }
9fd6b843
KS
2028}
2029
2030static int rtmp_close(URLContext *h)
2031{
2032 RTMPContext *rt = h->priv_data;
f645f1d6 2033 int ret = 0;
9fd6b843 2034
e07c92e4 2035 if (!rt->is_input) {
6bf22e18
S
2036 rt->flv_data = NULL;
2037 if (rt->out_pkt.data_size)
2038 ff_rtmp_packet_destroy(&rt->out_pkt);
615c2879 2039 if (rt->state > STATE_FCPUBLISH)
f645f1d6 2040 ret = gen_fcunpublish_stream(h, rt);
6bf22e18 2041 }
615c2879 2042 if (rt->state > STATE_HANDSHAKED)
f645f1d6 2043 ret = gen_delete_stream(h, rt);
6bf22e18 2044
f89584ca 2045 free_tracked_methods(rt);
9fd6b843 2046 av_freep(&rt->flv_data);
e52a9145 2047 ffurl_close(rt->stream);
f645f1d6 2048 return ret;
9fd6b843
KS
2049}
2050
2051/**
49bd8e4b 2052 * Open RTMP connection and verify that the stream can be played.
9fd6b843
KS
2053 *
2054 * URL syntax: rtmp://server[:port][/app][/playpath]
2055 * where 'app' is first one or two directories in the path
2056 * (e.g. /ondemand/, /flash/live/, etc.)
2057 * and 'playpath' is a file name (the rest of the path,
2058 * may be prefixed with "mp4:")
2059 */
2060static int rtmp_open(URLContext *s, const char *uri, int flags)
2061{
7e580505 2062 RTMPContext *rt = s->priv_data;
5e9ad759 2063 char proto[8], hostname[256], path[1024], *fname;
6465562e 2064 char *old_app;
9fd6b843 2065 uint8_t buf[2048];
b316991b 2066 int port;
86991ce2 2067 AVDictionary *opts = NULL;
9fd6b843
KS
2068 int ret;
2069
e5f2731c
JO
2070 if (rt->listen_timeout > 0)
2071 rt->listen = 1;
2072
59d96941 2073 rt->is_input = !(flags & AVIO_FLAG_WRITE);
9fd6b843 2074
f3bfe388 2075 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
f984dcf6 2076 path, sizeof(path), s->filename);
9fd6b843 2077
e5f2731c
JO
2078 if (rt->listen && strcmp(proto, "rtmp")) {
2079 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2080 proto);
2081 return AVERROR(EINVAL);
2082 }
86991ce2
SP
2083 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2084 if (!strcmp(proto, "rtmpts"))
2085 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2086
8e50c57d 2087 /* open the http tunneling connection */
775c4d36 2088 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
6aedabc9
SP
2089 } else if (!strcmp(proto, "rtmps")) {
2090 /* open the tls connection */
2091 if (port < 0)
2092 port = RTMPS_DEFAULT_PORT;
2093 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
08cd95e8
SP
2094 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2095 if (!strcmp(proto, "rtmpte"))
2096 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2097
acd554c1
SP
2098 /* open the encrypted connection */
2099 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2100 rt->encrypted = 1;
8e50c57d
SP
2101 } else {
2102 /* open the tcp connection */
2103 if (port < 0)
2104 port = RTMP_DEFAULT_PORT;
e5f2731c
JO
2105 if (rt->listen)
2106 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2107 "?listen&listen_timeout=%d",
2108 rt->listen_timeout * 1000);
2109 else
2110 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
8e50c57d 2111 }
9fd6b843 2112
f645f1d6 2113 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
86991ce2 2114 &s->interrupt_callback, &opts)) < 0) {
59d96941 2115 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
9fd6b843 2116 goto fail;
fe523958 2117 }
9fd6b843 2118
93f257db
SP
2119 if (rt->swfverify) {
2120 if ((ret = rtmp_calc_swfhash(s)) < 0)
2121 goto fail;
2122 }
2123
c7240611 2124 rt->state = STATE_START;
e5f2731c
JO
2125 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2126 goto fail;
2127 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
02490bf3 2128 goto fail;
9fd6b843 2129
f5ce90f2
JO
2130 rt->out_chunk_size = 128;
2131 rt->in_chunk_size = 128; // Probably overwritten later
c7240611 2132 rt->state = STATE_HANDSHAKED;
6465562e
SP
2133
2134 // Keep the application name when it has been defined by the user.
2135 old_app = rt->app;
2136
2137 rt->app = av_malloc(APP_MAX_LENGTH);
2138 if (!rt->app) {
f645f1d6
SP
2139 ret = AVERROR(ENOMEM);
2140 goto fail;
6465562e
SP
2141 }
2142
c7240611
KS
2143 //extract "app" part from path
2144 if (!strncmp(path, "/ondemand/", 10)) {
2145 fname = path + 10;
2146 memcpy(rt->app, "ondemand", 9);
2147 } else {
4b7304e8
MS
2148 char *next = *path ? path + 1 : path;
2149 char *p = strchr(next, '/');
c7240611 2150 if (!p) {
4b7304e8 2151 fname = next;
c7240611 2152 rt->app[0] = '\0';
9fd6b843 2153 } else {
c6eeb9b7 2154 // make sure we do not mismatch a playpath for an application instance
c7240611
KS
2155 char *c = strchr(p + 1, ':');
2156 fname = strchr(p + 1, '/');
c6eeb9b7 2157 if (!fname || (c && c < fname)) {
c7240611
KS
2158 fname = p + 1;
2159 av_strlcpy(rt->app, path + 1, p - path);
9fd6b843 2160 } else {
c7240611
KS
2161 fname++;
2162 av_strlcpy(rt->app, path + 1, fname - path - 1);
9fd6b843
KS
2163 }
2164 }
c7240611 2165 }
6465562e
SP
2166
2167 if (old_app) {
2168 // The name of application has been defined by the user, override it.
2169 av_free(rt->app);
2170 rt->app = old_app;
2171 }
2172
b3b17512 2173 if (!rt->playpath) {
f862537d
SP
2174 int len = strlen(fname);
2175
b3b17512
SP
2176 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2177 if (!rt->playpath) {
f645f1d6
SP
2178 ret = AVERROR(ENOMEM);
2179 goto fail;
b3b17512
SP
2180 }
2181
0a9a2257 2182 if (!strchr(fname, ':') && len >= 4 &&
f862537d
SP
2183 (!strcmp(fname + len - 4, ".f4v") ||
2184 !strcmp(fname + len - 4, ".mp4"))) {
b3b17512 2185 memcpy(rt->playpath, "mp4:", 5);
0a9a2257 2186 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
f862537d 2187 fname[len - 4] = '\0';
b3b17512
SP
2188 } else {
2189 rt->playpath[0] = 0;
2190 }
d578f947 2191 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
c7240611 2192 }
9fd6b843 2193
55c9320e
SP
2194 if (!rt->tcurl) {
2195 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
08e93f5b
SP
2196 if (!rt->tcurl) {
2197 ret = AVERROR(ENOMEM);
2198 goto fail;
2199 }
55c9320e
SP
2200 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2201 port, "/%s", rt->app);
2202 }
2203
e64673e4
SP
2204 if (!rt->flashver) {
2205 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
08e93f5b
SP
2206 if (!rt->flashver) {
2207 ret = AVERROR(ENOMEM);
2208 goto fail;
2209 }
e64673e4
SP
2210 if (rt->is_input) {
2211 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2212 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2213 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2214 } else {
2215 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2216 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2217 }
2218 }
2219
bf7c1719
KS
2220 rt->client_report_size = 1048576;
2221 rt->bytes_read = 0;
2222 rt->last_bytes_read = 0;
c2d38bea 2223 rt->server_bw = 2500000;
bf7c1719 2224
7f804085 2225 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
c7240611 2226 proto, path, rt->app, rt->playpath);
e5f2731c
JO
2227 if (!rt->listen) {
2228 if ((ret = gen_connect(s, rt)) < 0)
2229 goto fail;
2230 } else {
2231 if (read_connect(s, s->priv_data) < 0)
2232 goto fail;
2233 rt->is_input = 1;
2234 }
9fd6b843 2235
c7240611
KS
2236 do {
2237 ret = get_packet(s, 1);
2238 } while (ret == EAGAIN);
2239 if (ret < 0)
2240 goto fail;
6bf22e18
S
2241
2242 if (rt->is_input) {
9fd6b843
KS
2243 // generate FLV header for demuxer
2244 rt->flv_size = 13;
2245 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
2246 rt->flv_off = 0;
2247 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
6bf22e18
S
2248 } else {
2249 rt->flv_size = 0;
2250 rt->flv_data = NULL;
2251 rt->flv_off = 0;
b14629e5 2252 rt->skip_bytes = 13;
9fd6b843
KS
2253 }
2254
5958df34 2255 s->max_packet_size = rt->stream->max_packet_size;
9fd6b843
KS
2256 s->is_streamed = 1;
2257 return 0;
2258
2259fail:
86991ce2 2260 av_dict_free(&opts);
9fd6b843 2261 rtmp_close(s);
f645f1d6 2262 return ret;
9fd6b843
KS
2263}
2264
2265static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2266{
2267 RTMPContext *rt = s->priv_data;
2268 int orig_size = size;
2269 int ret;
2270
2271 while (size > 0) {
2272 int data_left = rt->flv_size - rt->flv_off;
2273
2274 if (data_left >= size) {
2275 memcpy(buf, rt->flv_data + rt->flv_off, size);
2276 rt->flv_off += size;
2277 return orig_size;
2278 }
2279 if (data_left > 0) {
2280 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2281 buf += data_left;
2282 size -= data_left;
2283 rt->flv_off = rt->flv_size;
e8ccf245 2284 return data_left;
9fd6b843
KS
2285 }
2286 if ((ret = get_packet(s, 0)) < 0)
2287 return ret;
2288 }
2289 return orig_size;
2290}
2291
9ad4c65f 2292static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
9fd6b843 2293{
9ad4c65f 2294 RTMPContext *rt = s->priv_data;
6bf22e18
S
2295 int size_temp = size;
2296 int pktsize, pkttype;
2297 uint32_t ts;
2298 const uint8_t *buf_temp = buf;
7dc747f5 2299 uint8_t c;
f645f1d6 2300 int ret;
6bf22e18 2301
6bf22e18 2302 do {
b14629e5
MS
2303 if (rt->skip_bytes) {
2304 int skip = FFMIN(rt->skip_bytes, size_temp);
2305 buf_temp += skip;
2306 size_temp -= skip;
2307 rt->skip_bytes -= skip;
2308 continue;
2309 }
2310
2311 if (rt->flv_header_bytes < 11) {
2312 const uint8_t *header = rt->flv_header;
2313 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
2314 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2315 rt->flv_header_bytes += copy;
2316 size_temp -= copy;
2317 if (rt->flv_header_bytes < 11)
2318 break;
6bf22e18 2319
b14629e5
MS
2320 pkttype = bytestream_get_byte(&header);
2321 pktsize = bytestream_get_be24(&header);
2322 ts = bytestream_get_be24(&header);
2323 ts |= bytestream_get_byte(&header) << 24;
2324 bytestream_get_be24(&header);
6bf22e18
S
2325 rt->flv_size = pktsize;
2326
2327 //force 12bytes header
2328 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2329 pkttype == RTMP_PT_NOTIFY) {
2330 if (pkttype == RTMP_PT_NOTIFY)
2331 pktsize += 16;
2332 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
2333 }
2334
2335 //this can be a big packet, it's better to send it right here
f645f1d6
SP
2336 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
2337 pkttype, ts, pktsize)) < 0)
2338 return ret;
2339
6bf22e18
S
2340 rt->out_pkt.extra = rt->main_channel_id;
2341 rt->flv_data = rt->out_pkt.data;
2342
2343 if (pkttype == RTMP_PT_NOTIFY)
2344 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
2345 }
2346
2347 if (rt->flv_size - rt->flv_off > size_temp) {
2348 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
2349 rt->flv_off += size_temp;
a14c7842 2350 size_temp = 0;
6bf22e18
S
2351 } else {
2352 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
a14c7842 2353 size_temp -= rt->flv_size - rt->flv_off;
6bf22e18
S
2354 rt->flv_off += rt->flv_size - rt->flv_off;
2355 }
2356
2357 if (rt->flv_off == rt->flv_size) {
b14629e5
MS
2358 rt->skip_bytes = 4;
2359
f89584ca 2360 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
bba287fd 2361 return ret;
6bf22e18
S
2362 rt->flv_size = 0;
2363 rt->flv_off = 0;
b14629e5 2364 rt->flv_header_bytes = 0;
46743a85 2365 rt->flv_nb_packets++;
6bf22e18 2366 }
a14c7842 2367 } while (buf_temp - buf < size);
7dc747f5 2368
46743a85
SP
2369 if (rt->flv_nb_packets < rt->flush_interval)
2370 return size;
2371 rt->flv_nb_packets = 0;
2372
7dc747f5
SP
2373 /* set stream into nonblocking mode */
2374 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
2375
2376 /* try to read one byte from the stream */
2377 ret = ffurl_read(rt->stream, &c, 1);
2378
2379 /* switch the stream back into blocking mode */
2380 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
2381
2382 if (ret == AVERROR(EAGAIN)) {
2383 /* no incoming data to handle */
2384 return size;
2385 } else if (ret < 0) {
2386 return ret;
2387 } else if (ret == 1) {
2388 RTMPPacket rpkt = { 0 };
2389
2390 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
f5ce90f2 2391 rt->in_chunk_size,
7dc747f5
SP
2392 rt->prev_pkt[0], c)) <= 0)
2393 return ret;
2394
2395 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
2396 return ret;
2397
2398 ff_rtmp_packet_destroy(&rpkt);
2399 }
2400
6bf22e18 2401 return size;
9fd6b843
KS
2402}
2403
6465562e
SP
2404#define OFFSET(x) offsetof(RTMPContext, x)
2405#define DEC AV_OPT_FLAG_DECODING_PARAM
2406#define ENC AV_OPT_FLAG_ENCODING_PARAM
2407
2408static const AVOption rtmp_options[] = {
2409 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e6153f17 2410 {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {.i64 = 3000}, 0, INT_MAX, DEC|ENC},
8ee3e187 2411 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e64673e4 2412 {"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},
e6153f17
MS
2413 {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {.i64 = 10}, 0, INT_MAX, ENC},
2414 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = -2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
124134e4
MS
2415 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
2416 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
2417 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
758377a2 2418 {"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 2419 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
00cb52c6 2420 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
635ac8e1 2421 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
e6153f17 2422 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
05945db9 2423 {"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},
93f257db 2424 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
63ffa154 2425 {"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},
e6153f17
MS
2426 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
2427 {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
6465562e
SP
2428 { NULL },
2429};
2430
12127b65
SP
2431#define RTMP_PROTOCOL(flavor) \
2432static const AVClass flavor##_class = { \
2433 .class_name = #flavor, \
2434 .item_name = av_default_item_name, \
2435 .option = rtmp_options, \
2436 .version = LIBAVUTIL_VERSION_INT, \
2437}; \
2438 \
2439URLProtocol ff_##flavor##_protocol = { \
2440 .name = #flavor, \
2441 .url_open = rtmp_open, \
2442 .url_read = rtmp_read, \
2443 .url_write = rtmp_write, \
2444 .url_close = rtmp_close, \
2445 .priv_data_size = sizeof(RTMPContext), \
2446 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2447 .priv_data_class= &flavor##_class, \
6465562e
SP
2448};
2449
08cd95e8 2450
12127b65
SP
2451RTMP_PROTOCOL(rtmp)
2452RTMP_PROTOCOL(rtmpe)
2453RTMP_PROTOCOL(rtmps)
2454RTMP_PROTOCOL(rtmpt)
2455RTMP_PROTOCOL(rtmpte)
2456RTMP_PROTOCOL(rtmpts)