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