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