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