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