lavf: remove FF_API_SYMVER cruft
[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"
29#include "libavutil/lfg.h"
30#include "libavutil/sha.h"
31#include "avformat.h"
e4a9e3cc 32#include "internal.h"
9fd6b843
KS
33
34#include "network.h"
35
36#include "flv.h"
37#include "rtmp.h"
38#include "rtmppkt.h"
0589da0a 39#include "url.h"
9fd6b843
KS
40
41/* we can't use av_log() with URLContext yet... */
ade800c5 42#if FF_API_URL_CLASS
9fd6b843 43#define LOG_CONTEXT s
ade800c5
AJ
44#else
45#define LOG_CONTEXT NULL
9fd6b843
KS
46#endif
47
cfac91fe
KS
48//#define DEBUG
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 {
65 URLContext* stream; ///< TCP stream used in interactions with RTMP server
66 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
67 int chunk_size; ///< size of the chunks RTMP packets are divided into
b316991b 68 int is_input; ///< input/output flag
9fd6b843 69 char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix)
5e9ad759 70 char app[128]; ///< application
9fd6b843
KS
71 ClientState state; ///< current state
72 int main_channel_id; ///< an additional channel ID which is used for some invocations
73 uint8_t* flv_data; ///< buffer with data for demuxer
74 int flv_size; ///< current buffer size
75 int flv_off; ///< number of bytes read from current buffer
6bf22e18 76 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
bf7c1719
KS
77 uint32_t client_report_size; ///< number of bytes after which client should report to server
78 uint32_t bytes_read; ///< number of bytes read from server
79 uint32_t last_bytes_read; ///< number of bytes read last reported to server
9fd6b843
KS
80} RTMPContext;
81
82#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
83/** Client key used for digest signing */
84static const uint8_t rtmp_player_key[] = {
85 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
86 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
87
88 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
89 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
90 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
91};
92
93#define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
94/** Key used for RTMP server digest signing */
95static const uint8_t rtmp_server_key[] = {
96 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
97 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
98 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
99
100 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
101 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
102 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
103};
104
105/**
49bd8e4b 106 * Generate 'connect' call and send it to the server.
9fd6b843
KS
107 */
108static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
5e9ad759 109 const char *host, int port)
9fd6b843
KS
110{
111 RTMPPacket pkt;
6bf22e18 112 uint8_t ver[64], *p;
9fd6b843
KS
113 char tcurl[512];
114
31da5966 115 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
9fd6b843
KS
116 p = pkt.data;
117
57b5555c 118 ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app);
9fd6b843
KS
119 ff_amf_write_string(&p, "connect");
120 ff_amf_write_number(&p, 1.0);
121 ff_amf_write_object_start(&p);
122 ff_amf_write_field_name(&p, "app");
5e9ad759 123 ff_amf_write_string(&p, rt->app);
9fd6b843 124
6bf22e18 125 if (rt->is_input) {
c7240611
KS
126 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
127 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
6bf22e18
S
128 } else {
129 snprintf(ver, sizeof(ver), "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
130 ff_amf_write_field_name(&p, "type");
131 ff_amf_write_string(&p, "nonprivate");
132 }
9fd6b843
KS
133 ff_amf_write_field_name(&p, "flashVer");
134 ff_amf_write_string(&p, ver);
135 ff_amf_write_field_name(&p, "tcUrl");
136 ff_amf_write_string(&p, tcurl);
6bf22e18 137 if (rt->is_input) {
c7240611
KS
138 ff_amf_write_field_name(&p, "fpad");
139 ff_amf_write_bool(&p, 0);
140 ff_amf_write_field_name(&p, "capabilities");
141 ff_amf_write_number(&p, 15.0);
142 ff_amf_write_field_name(&p, "audioCodecs");
143 ff_amf_write_number(&p, 1639.0);
144 ff_amf_write_field_name(&p, "videoCodecs");
145 ff_amf_write_number(&p, 252.0);
146 ff_amf_write_field_name(&p, "videoFunction");
147 ff_amf_write_number(&p, 1.0);
6bf22e18 148 }
9fd6b843
KS
149 ff_amf_write_object_end(&p);
150
151 pkt.data_size = p - pkt.data;
152
153 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
f8caa544 154 ff_rtmp_packet_destroy(&pkt);
9fd6b843
KS
155}
156
157/**
49bd8e4b 158 * Generate 'releaseStream' call and send it to the server. It should make
6bf22e18
S
159 * the server release some channel for media streams.
160 */
161static void gen_release_stream(URLContext *s, RTMPContext *rt)
162{
163 RTMPPacket pkt;
164 uint8_t *p;
165
166 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
167 29 + strlen(rt->playpath));
168
169 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Releasing stream...\n");
170 p = pkt.data;
171 ff_amf_write_string(&p, "releaseStream");
172 ff_amf_write_number(&p, 2.0);
173 ff_amf_write_null(&p);
174 ff_amf_write_string(&p, rt->playpath);
175
176 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
177 ff_rtmp_packet_destroy(&pkt);
178}
179
180/**
49bd8e4b 181 * Generate 'FCPublish' call and send it to the server. It should make
6bf22e18
S
182 * the server preapare for receiving media streams.
183 */
184static void gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
185{
186 RTMPPacket pkt;
187 uint8_t *p;
188
189 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
190 25 + strlen(rt->playpath));
191
192 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "FCPublish stream...\n");
193 p = pkt.data;
194 ff_amf_write_string(&p, "FCPublish");
195 ff_amf_write_number(&p, 3.0);
196 ff_amf_write_null(&p);
197 ff_amf_write_string(&p, rt->playpath);
198
199 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
200 ff_rtmp_packet_destroy(&pkt);
201}
202
203/**
49bd8e4b 204 * Generate 'FCUnpublish' call and send it to the server. It should make
6bf22e18
S
205 * the server destroy stream.
206 */
207static void gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
208{
209 RTMPPacket pkt;
210 uint8_t *p;
211
212 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
213 27 + strlen(rt->playpath));
214
215 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "UnPublishing stream...\n");
216 p = pkt.data;
217 ff_amf_write_string(&p, "FCUnpublish");
218 ff_amf_write_number(&p, 5.0);
219 ff_amf_write_null(&p);
220 ff_amf_write_string(&p, rt->playpath);
221
222 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
223 ff_rtmp_packet_destroy(&pkt);
224}
225
226/**
49bd8e4b 227 * Generate 'createStream' call and send it to the server. It should make
9fd6b843
KS
228 * the server allocate some channel for media streams.
229 */
230static void gen_create_stream(URLContext *s, RTMPContext *rt)
231{
232 RTMPPacket pkt;
233 uint8_t *p;
234
235 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Creating stream...\n");
31da5966 236 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 25);
9fd6b843
KS
237
238 p = pkt.data;
239 ff_amf_write_string(&p, "createStream");
6bf22e18
S
240 ff_amf_write_number(&p, rt->is_input ? 3.0 : 4.0);
241 ff_amf_write_null(&p);
242
243 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
244 ff_rtmp_packet_destroy(&pkt);
245}
246
247
248/**
49bd8e4b 249 * Generate 'deleteStream' call and send it to the server. It should make
6bf22e18
S
250 * the server remove some channel for media streams.
251 */
252static void gen_delete_stream(URLContext *s, RTMPContext *rt)
253{
254 RTMPPacket pkt;
255 uint8_t *p;
256
257 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Deleting stream...\n");
258 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 34);
259
260 p = pkt.data;
261 ff_amf_write_string(&p, "deleteStream");
262 ff_amf_write_number(&p, 0.0);
9fd6b843 263 ff_amf_write_null(&p);
6bf22e18 264 ff_amf_write_number(&p, rt->main_channel_id);
9fd6b843
KS
265
266 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
267 ff_rtmp_packet_destroy(&pkt);
268}
269
270/**
49bd8e4b 271 * Generate 'play' call and send it to the server, then ping the server
9fd6b843
KS
272 * to start actual playing.
273 */
274static void gen_play(URLContext *s, RTMPContext *rt)
275{
276 RTMPPacket pkt;
277 uint8_t *p;
278
279 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
280 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
f836fa17 281 20 + strlen(rt->playpath));
9fd6b843
KS
282 pkt.extra = rt->main_channel_id;
283
284 p = pkt.data;
285 ff_amf_write_string(&p, "play");
286 ff_amf_write_number(&p, 0.0);
287 ff_amf_write_null(&p);
288 ff_amf_write_string(&p, rt->playpath);
9fd6b843
KS
289
290 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
291 ff_rtmp_packet_destroy(&pkt);
292
293 // set client buffer time disguised in ping packet
294 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
295
296 p = pkt.data;
297 bytestream_put_be16(&p, 3);
298 bytestream_put_be32(&p, 1);
299 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
300
301 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
302 ff_rtmp_packet_destroy(&pkt);
303}
304
305/**
49bd8e4b 306 * Generate 'publish' call and send it to the server.
6bf22e18
S
307 */
308static void gen_publish(URLContext *s, RTMPContext *rt)
309{
310 RTMPPacket pkt;
311 uint8_t *p;
312
313 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
314 ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE, 0,
315 30 + strlen(rt->playpath));
316 pkt.extra = rt->main_channel_id;
317
318 p = pkt.data;
319 ff_amf_write_string(&p, "publish");
320 ff_amf_write_number(&p, 0.0);
321 ff_amf_write_null(&p);
322 ff_amf_write_string(&p, rt->playpath);
323 ff_amf_write_string(&p, "live");
324
325 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
326 ff_rtmp_packet_destroy(&pkt);
327}
328
329/**
49bd8e4b 330 * Generate ping reply and send it to the server.
9fd6b843
KS
331 */
332static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
333{
334 RTMPPacket pkt;
335 uint8_t *p;
336
337 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
338 p = pkt.data;
339 bytestream_put_be16(&p, 7);
4aaebf78 340 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
9fd6b843
KS
341 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
342 ff_rtmp_packet_destroy(&pkt);
343}
344
bf7c1719 345/**
49bd8e4b 346 * Generate report on bytes read so far and send it to the server.
bf7c1719
KS
347 */
348static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
349{
350 RTMPPacket pkt;
351 uint8_t *p;
352
353 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4);
354 p = pkt.data;
355 bytestream_put_be32(&p, rt->bytes_read);
356 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
357 ff_rtmp_packet_destroy(&pkt);
358}
359
9fd6b843
KS
360//TODO: Move HMAC code somewhere. Eventually.
361#define HMAC_IPAD_VAL 0x36
362#define HMAC_OPAD_VAL 0x5C
363
364/**
49bd8e4b 365 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
9fd6b843
KS
366 *
367 * @param src input buffer
368 * @param len input buffer length (should be 1536)
369 * @param gap offset in buffer where 32 bytes should not be taken into account
370 * when calculating digest (since it will be used to store that digest)
371 * @param key digest key
372 * @param keylen digest key length
373 * @param dst buffer where calculated digest will be stored (32 bytes)
374 */
375static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
376 const uint8_t *key, int keylen, uint8_t *dst)
377{
378 struct AVSHA *sha;
379 uint8_t hmac_buf[64+32] = {0};
380 int i;
381
382 sha = av_mallocz(av_sha_size);
383
384 if (keylen < 64) {
385 memcpy(hmac_buf, key, keylen);
386 } else {
387 av_sha_init(sha, 256);
388 av_sha_update(sha,key, keylen);
389 av_sha_final(sha, hmac_buf);
390 }
391 for (i = 0; i < 64; i++)
392 hmac_buf[i] ^= HMAC_IPAD_VAL;
393
394 av_sha_init(sha, 256);
395 av_sha_update(sha, hmac_buf, 64);
396 if (gap <= 0) {
397 av_sha_update(sha, src, len);
398 } else { //skip 32 bytes used for storing digest
399 av_sha_update(sha, src, gap);
400 av_sha_update(sha, src + gap + 32, len - gap - 32);
401 }
402 av_sha_final(sha, hmac_buf + 64);
403
404 for (i = 0; i < 64; i++)
405 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
406 av_sha_init(sha, 256);
407 av_sha_update(sha, hmac_buf, 64+32);
408 av_sha_final(sha, dst);
409
410 av_free(sha);
411}
412
413/**
49bd8e4b 414 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
9fd6b843
KS
415 * will be stored) into that packet.
416 *
417 * @param buf handshake data (1536 bytes)
418 * @return offset to the digest inside input data
419 */
420static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
421{
422 int i, digest_pos = 0;
423
424 for (i = 8; i < 12; i++)
425 digest_pos += buf[i];
426 digest_pos = (digest_pos % 728) + 12;
427
428 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
429 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
430 buf + digest_pos);
431 return digest_pos;
432}
433
434/**
49bd8e4b 435 * Verify that the received server response has the expected digest value.
9fd6b843
KS
436 *
437 * @param buf handshake data received from the server (1536 bytes)
438 * @param off position to search digest offset from
439 * @return 0 if digest is valid, digest position otherwise
440 */
441static int rtmp_validate_digest(uint8_t *buf, int off)
442{
443 int i, digest_pos = 0;
444 uint8_t digest[32];
445
446 for (i = 0; i < 4; i++)
447 digest_pos += buf[i + off];
448 digest_pos = (digest_pos % 728) + off + 4;
449
450 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
451 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
452 digest);
453 if (!memcmp(digest, buf + digest_pos, 32))
454 return digest_pos;
455 return 0;
456}
457
458/**
49bd8e4b 459 * Perform handshake with the server by means of exchanging pseudorandom data
9fd6b843
KS
460 * signed with HMAC-SHA2 digest.
461 *
462 * @return 0 if handshake succeeds, negative value otherwise
463 */
464static int rtmp_handshake(URLContext *s, RTMPContext *rt)
465{
466 AVLFG rnd;
467 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
468 3, // unencrypted data
469 0, 0, 0, 0, // client uptime
470 RTMP_CLIENT_VER1,
471 RTMP_CLIENT_VER2,
472 RTMP_CLIENT_VER3,
473 RTMP_CLIENT_VER4,
474 };
475 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
476 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
477 int i;
478 int server_pos, client_pos;
479 uint8_t digest[32];
480
481 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
482
483 av_lfg_init(&rnd, 0xDEADC0DE);
484 // generate handshake packet - 1536 bytes of pseudorandom data
485 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
486 tosend[i] = av_lfg_get(&rnd) >> 24;
487 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
488
925e908b 489 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
dce37564 490 i = ffurl_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
9fd6b843
KS
491 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
492 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
493 return -1;
494 }
dce37564 495 i = ffurl_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
9fd6b843
KS
496 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
497 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
498 return -1;
499 }
500
501 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
502 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
503
e2ee11e8 504 if (rt->is_input && serverdata[5] >= 3) {
c7240611 505 server_pos = rtmp_validate_digest(serverdata + 1, 772);
9fd6b843 506 if (!server_pos) {
c7240611
KS
507 server_pos = rtmp_validate_digest(serverdata + 1, 8);
508 if (!server_pos) {
509 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
510 return -1;
511 }
9fd6b843 512 }
9fd6b843 513
c7240611
KS
514 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
515 rtmp_server_key, sizeof(rtmp_server_key),
516 digest);
517 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
518 digest, 32,
519 digest);
520 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
521 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
522 return -1;
523 }
9fd6b843 524
c7240611
KS
525 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
526 tosend[i] = av_lfg_get(&rnd) >> 24;
527 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
528 rtmp_player_key, sizeof(rtmp_player_key),
529 digest);
530 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
531 digest, 32,
532 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
533
534 // write reply back to the server
925e908b 535 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
6bf22e18 536 } else {
925e908b 537 ffurl_write(rt->stream, serverdata+1, RTMP_HANDSHAKE_PACKET_SIZE);
6bf22e18
S
538 }
539
9fd6b843
KS
540 return 0;
541}
542
543/**
49bd8e4b 544 * Parse received packet and possibly perform some action depending on
9fd6b843
KS
545 * the packet contents.
546 * @return 0 for no errors, negative values for serious errors which prevent
547 * further communications, positive values for uncritical errors
548 */
549static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
550{
551 int i, t;
552 const uint8_t *data_end = pkt->data + pkt->data_size;
553
cfac91fe
KS
554#ifdef DEBUG
555 ff_rtmp_packet_dump(LOG_CONTEXT, pkt);
556#endif
557
9fd6b843
KS
558 switch (pkt->type) {
559 case RTMP_PT_CHUNK_SIZE:
560 if (pkt->data_size != 4) {
561 av_log(LOG_CONTEXT, AV_LOG_ERROR,
562 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
563 return -1;
564 }
6bf22e18
S
565 if (!rt->is_input)
566 ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size, rt->prev_pkt[1]);
9fd6b843
KS
567 rt->chunk_size = AV_RB32(pkt->data);
568 if (rt->chunk_size <= 0) {
569 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
570 return -1;
571 }
572 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
573 break;
574 case RTMP_PT_PING:
575 t = AV_RB16(pkt->data);
576 if (t == 6)
577 gen_pong(s, rt, pkt);
578 break;
bf7c1719
KS
579 case RTMP_PT_CLIENT_BW:
580 if (pkt->data_size < 4) {
581 av_log(LOG_CONTEXT, AV_LOG_ERROR,
582 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
583 pkt->data_size);
584 return -1;
585 }
586 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
587 rt->client_report_size = AV_RB32(pkt->data) >> 1;
588 break;
9fd6b843
KS
589 case RTMP_PT_INVOKE:
590 //TODO: check for the messages sent for wrong state?
591 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
592 uint8_t tmpstr[256];
593
594 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
595 "description", tmpstr, sizeof(tmpstr)))
596 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
597 return -1;
598 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
599 switch (rt->state) {
600 case STATE_HANDSHAKED:
6bf22e18
S
601 if (!rt->is_input) {
602 gen_release_stream(s, rt);
603 gen_fcpublish_stream(s, rt);
604 rt->state = STATE_RELEASING;
605 } else {
606 rt->state = STATE_CONNECTING;
607 }
9fd6b843 608 gen_create_stream(s, rt);
6bf22e18
S
609 break;
610 case STATE_FCPUBLISH:
9fd6b843
KS
611 rt->state = STATE_CONNECTING;
612 break;
6bf22e18
S
613 case STATE_RELEASING:
614 rt->state = STATE_FCPUBLISH;
615 /* hack for Wowza Media Server, it does not send result for
616 * releaseStream and FCPublish calls */
617 if (!pkt->data[10]) {
618 int pkt_id = (int) av_int2dbl(AV_RB64(pkt->data + 11));
619 if (pkt_id == 4)
620 rt->state = STATE_CONNECTING;
621 }
e07c92e4 622 if (rt->state != STATE_CONNECTING)
6bf22e18 623 break;
9fd6b843
KS
624 case STATE_CONNECTING:
625 //extract a number from the result
626 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
627 av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
628 } else {
629 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
630 }
6bf22e18 631 if (rt->is_input) {
c7240611 632 gen_play(s, rt);
6bf22e18
S
633 } else {
634 gen_publish(s, rt);
635 }
9fd6b843
KS
636 rt->state = STATE_READY;
637 break;
638 }
639 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
640 const uint8_t* ptr = pkt->data + 11;
641 uint8_t tmpstr[256];
9fd6b843
KS
642
643 for (i = 0; i < 2; i++) {
644 t = ff_amf_tag_size(ptr, data_end);
645 if (t < 0)
646 return 1;
647 ptr += t;
648 }
649 t = ff_amf_get_field_value(ptr, data_end,
650 "level", tmpstr, sizeof(tmpstr));
651 if (!t && !strcmp(tmpstr, "error")) {
652 if (!ff_amf_get_field_value(ptr, data_end,
653 "description", tmpstr, sizeof(tmpstr)))
654 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
655 return -1;
656 }
657 t = ff_amf_get_field_value(ptr, data_end,
658 "code", tmpstr, sizeof(tmpstr));
6bf22e18 659 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
72b870b9
MS
660 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
661 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
6bf22e18 662 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
9fd6b843
KS
663 }
664 break;
665 }
666 return 0;
667}
668
669/**
49bd8e4b 670 * Interact with the server by receiving and sending RTMP packets until
9fd6b843
KS
671 * there is some significant data (media data or expected status notification).
672 *
673 * @param s reading context
1d8041b3
SS
674 * @param for_header non-zero value tells function to work until it
675 * gets notification from the server that playing has been started,
676 * otherwise function will work until some media data is received (or
677 * an error happens)
9fd6b843
KS
678 * @return 0 for successful operation, negative value in case of error
679 */
680static int get_packet(URLContext *s, int for_header)
681{
682 RTMPContext *rt = s->priv_data;
683 int ret;
56e29bf2
S
684 uint8_t *p;
685 const uint8_t *next;
686 uint32_t data_size;
687 uint32_t ts, cts, pts=0;
9fd6b843 688
72b870b9
MS
689 if (rt->state == STATE_STOPPED)
690 return AVERROR_EOF;
691
e07c92e4 692 for (;;) {
9fd6b843
KS
693 RTMPPacket rpkt;
694 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
adb54961 695 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
b381a823 696 if (ret == 0) {
9fd6b843
KS
697 return AVERROR(EAGAIN);
698 } else {
699 return AVERROR(EIO);
700 }
701 }
bf7c1719
KS
702 rt->bytes_read += ret;
703 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
704 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending bytes read report\n");
705 gen_bytes_read(s, rt, rpkt.timestamp + 1);
706 rt->last_bytes_read = rt->bytes_read;
707 }
9fd6b843
KS
708
709 ret = rtmp_parse_result(s, rt, &rpkt);
710 if (ret < 0) {//serious error in current packet
711 ff_rtmp_packet_destroy(&rpkt);
712 return -1;
713 }
72b870b9
MS
714 if (rt->state == STATE_STOPPED) {
715 ff_rtmp_packet_destroy(&rpkt);
716 return AVERROR_EOF;
717 }
6bf22e18 718 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
9fd6b843
KS
719 ff_rtmp_packet_destroy(&rpkt);
720 return 0;
721 }
6bf22e18 722 if (!rpkt.data_size || !rt->is_input) {
9fd6b843
KS
723 ff_rtmp_packet_destroy(&rpkt);
724 continue;
725 }
726 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
afbacb93 727 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
56e29bf2 728 ts = rpkt.timestamp;
9fd6b843 729
9fd6b843
KS
730 // generate packet header and put data into buffer for FLV demuxer
731 rt->flv_off = 0;
732 rt->flv_size = rpkt.data_size + 15;
733 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
734 bytestream_put_byte(&p, rpkt.type);
735 bytestream_put_be24(&p, rpkt.data_size);
736 bytestream_put_be24(&p, ts);
737 bytestream_put_byte(&p, ts >> 24);
738 bytestream_put_be24(&p, 0);
739 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
740 bytestream_put_be32(&p, 0);
741 ff_rtmp_packet_destroy(&rpkt);
742 return 0;
743 } else if (rpkt.type == RTMP_PT_METADATA) {
744 // we got raw FLV data, make it available for FLV demuxer
745 rt->flv_off = 0;
746 rt->flv_size = rpkt.data_size;
747 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
56e29bf2
S
748 /* rewrite timestamps */
749 next = rpkt.data;
750 ts = rpkt.timestamp;
751 while (next - rpkt.data < rpkt.data_size - 11) {
752 next++;
753 data_size = bytestream_get_be24(&next);
754 p=next;
755 cts = bytestream_get_be24(&next);
aae9a093 756 cts |= bytestream_get_byte(&next) << 24;
56e29bf2
S
757 if (pts==0)
758 pts=cts;
759 ts += cts - pts;
760 pts = cts;
761 bytestream_put_be24(&p, ts);
762 bytestream_put_byte(&p, ts >> 24);
763 next += data_size + 3 + 4;
764 }
9fd6b843
KS
765 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
766 ff_rtmp_packet_destroy(&rpkt);
767 return 0;
768 }
769 ff_rtmp_packet_destroy(&rpkt);
770 }
771 return 0;
772}
773
774static int rtmp_close(URLContext *h)
775{
776 RTMPContext *rt = h->priv_data;
777
e07c92e4 778 if (!rt->is_input) {
6bf22e18
S
779 rt->flv_data = NULL;
780 if (rt->out_pkt.data_size)
781 ff_rtmp_packet_destroy(&rt->out_pkt);
615c2879
S
782 if (rt->state > STATE_FCPUBLISH)
783 gen_fcunpublish_stream(h, rt);
6bf22e18 784 }
615c2879
S
785 if (rt->state > STATE_HANDSHAKED)
786 gen_delete_stream(h, rt);
6bf22e18 787
9fd6b843 788 av_freep(&rt->flv_data);
e52a9145 789 ffurl_close(rt->stream);
9fd6b843
KS
790 av_free(rt);
791 return 0;
792}
793
794/**
49bd8e4b 795 * Open RTMP connection and verify that the stream can be played.
9fd6b843
KS
796 *
797 * URL syntax: rtmp://server[:port][/app][/playpath]
798 * where 'app' is first one or two directories in the path
799 * (e.g. /ondemand/, /flash/live/, etc.)
800 * and 'playpath' is a file name (the rest of the path,
801 * may be prefixed with "mp4:")
802 */
803static int rtmp_open(URLContext *s, const char *uri, int flags)
804{
805 RTMPContext *rt;
5e9ad759 806 char proto[8], hostname[256], path[1024], *fname;
9fd6b843 807 uint8_t buf[2048];
b316991b 808 int port;
9fd6b843
KS
809 int ret;
810
9fd6b843
KS
811 rt = av_mallocz(sizeof(RTMPContext));
812 if (!rt)
813 return AVERROR(ENOMEM);
814 s->priv_data = rt;
f87b1b37 815 rt->is_input = !(flags & AVIO_WRONLY);
9fd6b843 816
f3bfe388 817 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
f984dcf6 818 path, sizeof(path), s->filename);
9fd6b843
KS
819
820 if (port < 0)
821 port = RTMP_DEFAULT_PORT;
57b5555c 822 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
9fd6b843 823
f87b1b37 824 if (ffurl_open(&rt->stream, buf, AVIO_RDWR) < 0) {
fe523958 825 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot open connection %s\n", buf);
9fd6b843 826 goto fail;
fe523958 827 }
9fd6b843 828
c7240611
KS
829 rt->state = STATE_START;
830 if (rtmp_handshake(s, rt))
831 return -1;
9fd6b843 832
c7240611
KS
833 rt->chunk_size = 128;
834 rt->state = STATE_HANDSHAKED;
835 //extract "app" part from path
836 if (!strncmp(path, "/ondemand/", 10)) {
837 fname = path + 10;
838 memcpy(rt->app, "ondemand", 9);
839 } else {
840 char *p = strchr(path + 1, '/');
841 if (!p) {
842 fname = path + 1;
843 rt->app[0] = '\0';
9fd6b843 844 } else {
c7240611
KS
845 char *c = strchr(p + 1, ':');
846 fname = strchr(p + 1, '/');
847 if (!fname || c < fname) {
848 fname = p + 1;
849 av_strlcpy(rt->app, path + 1, p - path);
9fd6b843 850 } else {
c7240611
KS
851 fname++;
852 av_strlcpy(rt->app, path + 1, fname - path - 1);
9fd6b843
KS
853 }
854 }
c7240611
KS
855 }
856 if (!strchr(fname, ':') &&
857 (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
858 !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
859 memcpy(rt->playpath, "mp4:", 5);
860 } else {
861 rt->playpath[0] = 0;
862 }
863 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
9fd6b843 864
bf7c1719
KS
865 rt->client_report_size = 1048576;
866 rt->bytes_read = 0;
867 rt->last_bytes_read = 0;
868
c7240611
KS
869 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
870 proto, path, rt->app, rt->playpath);
871 gen_connect(s, rt, proto, hostname, port);
9fd6b843 872
c7240611
KS
873 do {
874 ret = get_packet(s, 1);
875 } while (ret == EAGAIN);
876 if (ret < 0)
877 goto fail;
6bf22e18
S
878
879 if (rt->is_input) {
9fd6b843
KS
880 // generate FLV header for demuxer
881 rt->flv_size = 13;
882 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
883 rt->flv_off = 0;
884 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
6bf22e18
S
885 } else {
886 rt->flv_size = 0;
887 rt->flv_data = NULL;
888 rt->flv_off = 0;
9fd6b843
KS
889 }
890
5958df34 891 s->max_packet_size = rt->stream->max_packet_size;
9fd6b843
KS
892 s->is_streamed = 1;
893 return 0;
894
895fail:
896 rtmp_close(s);
897 return AVERROR(EIO);
898}
899
900static int rtmp_read(URLContext *s, uint8_t *buf, int size)
901{
902 RTMPContext *rt = s->priv_data;
903 int orig_size = size;
904 int ret;
905
906 while (size > 0) {
907 int data_left = rt->flv_size - rt->flv_off;
908
909 if (data_left >= size) {
910 memcpy(buf, rt->flv_data + rt->flv_off, size);
911 rt->flv_off += size;
912 return orig_size;
913 }
914 if (data_left > 0) {
915 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
916 buf += data_left;
917 size -= data_left;
918 rt->flv_off = rt->flv_size;
e8ccf245 919 return data_left;
9fd6b843
KS
920 }
921 if ((ret = get_packet(s, 0)) < 0)
922 return ret;
923 }
924 return orig_size;
925}
926
9ad4c65f 927static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
9fd6b843 928{
9ad4c65f 929 RTMPContext *rt = s->priv_data;
6bf22e18
S
930 int size_temp = size;
931 int pktsize, pkttype;
932 uint32_t ts;
933 const uint8_t *buf_temp = buf;
934
935 if (size < 11) {
936 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "FLV packet too small %d\n", size);
937 return 0;
938 }
939
940 do {
941 if (!rt->flv_off) {
942 //skip flv header
943 if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') {
944 buf_temp += 9 + 4;
945 size_temp -= 9 + 4;
946 }
947
948 pkttype = bytestream_get_byte(&buf_temp);
949 pktsize = bytestream_get_be24(&buf_temp);
950 ts = bytestream_get_be24(&buf_temp);
951 ts |= bytestream_get_byte(&buf_temp) << 24;
952 bytestream_get_be24(&buf_temp);
953 size_temp -= 11;
954 rt->flv_size = pktsize;
955
956 //force 12bytes header
957 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
958 pkttype == RTMP_PT_NOTIFY) {
959 if (pkttype == RTMP_PT_NOTIFY)
960 pktsize += 16;
961 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
962 }
963
964 //this can be a big packet, it's better to send it right here
965 ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, pkttype, ts, pktsize);
966 rt->out_pkt.extra = rt->main_channel_id;
967 rt->flv_data = rt->out_pkt.data;
968
969 if (pkttype == RTMP_PT_NOTIFY)
970 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
971 }
972
973 if (rt->flv_size - rt->flv_off > size_temp) {
974 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
975 rt->flv_off += size_temp;
976 } else {
977 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
978 rt->flv_off += rt->flv_size - rt->flv_off;
979 }
980
981 if (rt->flv_off == rt->flv_size) {
982 bytestream_get_be32(&buf_temp);
983
984 ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
985 ff_rtmp_packet_destroy(&rt->out_pkt);
986 rt->flv_size = 0;
987 rt->flv_off = 0;
988 }
989 } while (buf_temp - buf < size_temp);
990 return size;
9fd6b843
KS
991}
992
c6610a21 993URLProtocol ff_rtmp_protocol = {
f35ff97f
AK
994 .name = "rtmp",
995 .url_open = rtmp_open,
996 .url_read = rtmp_read,
997 .url_write = rtmp_write,
998 .url_close = rtmp_close,
9fd6b843 999};