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