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