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