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