rtmp: Factorize the code by adding handle_invoke_result
[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
5e6001db
SP
1024static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
1025{
1026 RTMPContext *rt = s->priv_data;
1027 char *tracked_method = NULL;
1028 GetByteContext gbc;
1029 double pkt_id;
1030 int ret = 0;
1031 int i;
1032
1033 bytestream2_init(&gbc, pkt->data + 10, pkt->data_size);
1034 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
1035 return ret;
1036
1037 for (i = 0; i < rt->nb_tracked_methods; i++) {
1038 if (rt->tracked_methods[i].id != pkt_id)
1039 continue;
1040
1041 tracked_method = rt->tracked_methods[i].name;
1042 del_tracked_method(rt, i);
1043 break;
1044 }
1045
1046 if (!tracked_method) {
1047 /* Ignore this reply when the current method is not tracked. */
1048 return ret;
1049 }
1050
1051 if (!memcmp(tracked_method, "connect", 7)) {
1052 if (!rt->is_input) {
1053 if ((ret = gen_release_stream(s, rt)) < 0)
1054 goto fail;
1055
1056 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1057 goto fail;
1058 } else {
1059 if ((ret = gen_server_bw(s, rt)) < 0)
1060 goto fail;
1061 }
1062
1063 if ((ret = gen_create_stream(s, rt)) < 0)
1064 goto fail;
1065
1066 if (rt->is_input) {
1067 /* Send the FCSubscribe command when the name of live
1068 * stream is defined by the user or if it's a live stream. */
1069 if (rt->subscribe) {
1070 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
1071 goto fail;
1072 } else if (rt->live == -1) {
1073 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
1074 goto fail;
1075 }
1076 }
1077 } else if (!memcmp(tracked_method, "createStream", 12)) {
1078 //extract a number from the result
1079 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1080 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
1081 } else {
1082 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
1083 }
1084
1085 if (!rt->is_input) {
1086 if ((ret = gen_publish(s, rt)) < 0)
1087 goto fail;
1088 } else {
1089 if ((ret = gen_play(s, rt)) < 0)
1090 goto fail;
1091 if ((ret = gen_buffer_time(s, rt)) < 0)
1092 goto fail;
1093 }
1094 }
1095
1096fail:
1097 av_free(tracked_method);
1098 return ret;
1099}
1100
6d1c9945 1101static int handle_invoke(URLContext *s, RTMPPacket *pkt)
9fd6b843 1102{
6d1c9945 1103 RTMPContext *rt = s->priv_data;
9fd6b843
KS
1104 int i, t;
1105 const uint8_t *data_end = pkt->data + pkt->data_size;
f89584ca 1106 int ret = 0;
9fd6b843 1107
6d1c9945
SP
1108 //TODO: check for the messages sent for wrong state?
1109 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
1110 uint8_t tmpstr[256];
cfac91fe 1111
6d1c9945
SP
1112 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1113 "description", tmpstr, sizeof(tmpstr)))
1114 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
1115 return -1;
1116 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
5e6001db 1117 if ((ret = handle_invoke_result(s, pkt)) < 0)
f89584ca 1118 return ret;
6d1c9945
SP
1119 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
1120 const uint8_t* ptr = pkt->data + 11;
1121 uint8_t tmpstr[256];
1122
1123 for (i = 0; i < 2; i++) {
1124 t = ff_amf_tag_size(ptr, data_end);
1125 if (t < 0)
1126 return 1;
1127 ptr += t;
1128 }
1129 t = ff_amf_get_field_value(ptr, data_end,
1130 "level", tmpstr, sizeof(tmpstr));
1131 if (!t && !strcmp(tmpstr, "error")) {
1132 if (!ff_amf_get_field_value(ptr, data_end,
1133 "description", tmpstr, sizeof(tmpstr)))
1134 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
1135 return -1;
1136 }
1137 t = ff_amf_get_field_value(ptr, data_end,
1138 "code", tmpstr, sizeof(tmpstr));
1139 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1140 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1141 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1142 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1143 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1144 if ((ret = gen_check_bw(s, rt)) < 0)
1145 return ret;
1146 }
1147
f89584ca 1148 return ret;
6d1c9945
SP
1149}
1150
1151/**
1152 * Parse received packet and possibly perform some action depending on
1153 * the packet contents.
1154 * @return 0 for no errors, negative values for serious errors which prevent
1155 * further communications, positive values for uncritical errors
1156 */
1157static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
1158{
1159 int ret;
1160
1161#ifdef DEBUG
1162 ff_rtmp_packet_dump(s, pkt);
1163#endif
1164
1165 switch (pkt->type) {
1166 case RTMP_PT_CHUNK_SIZE:
1167 if ((ret = handle_chunk_size(s, pkt)) < 0)
1168 return ret;
1169 break;
1170 case RTMP_PT_PING:
1171 if ((ret = handle_ping(s, pkt)) < 0)
1172 return ret;
1173 break;
1174 case RTMP_PT_CLIENT_BW:
1175 if ((ret = handle_client_bw(s, pkt)) < 0)
1176 return ret;
1177 break;
1178 case RTMP_PT_SERVER_BW:
1179 if ((ret = handle_server_bw(s, pkt)) < 0)
1180 return ret;
1181 break;
1182 case RTMP_PT_INVOKE:
1183 if ((ret = handle_invoke(s, pkt)) < 0)
1184 return ret;
9fd6b843 1185 break;
08e087cc
JO
1186 case RTMP_PT_VIDEO:
1187 case RTMP_PT_AUDIO:
9c9c21ea
SP
1188 case RTMP_PT_METADATA:
1189 /* Audio, Video and Metadata packets are parsed in get_packet() */
08e087cc 1190 break;
9ff930aa
SP
1191 default:
1192 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
1193 break;
9fd6b843
KS
1194 }
1195 return 0;
1196}
1197
1198/**
49bd8e4b 1199 * Interact with the server by receiving and sending RTMP packets until
9fd6b843
KS
1200 * there is some significant data (media data or expected status notification).
1201 *
1202 * @param s reading context
1d8041b3
SS
1203 * @param for_header non-zero value tells function to work until it
1204 * gets notification from the server that playing has been started,
1205 * otherwise function will work until some media data is received (or
1206 * an error happens)
9fd6b843
KS
1207 * @return 0 for successful operation, negative value in case of error
1208 */
1209static int get_packet(URLContext *s, int for_header)
1210{
1211 RTMPContext *rt = s->priv_data;
1212 int ret;
56e29bf2
S
1213 uint8_t *p;
1214 const uint8_t *next;
1215 uint32_t data_size;
1216 uint32_t ts, cts, pts=0;
9fd6b843 1217
72b870b9
MS
1218 if (rt->state == STATE_STOPPED)
1219 return AVERROR_EOF;
1220
e07c92e4 1221 for (;;) {
271c869c 1222 RTMPPacket rpkt = { 0 };
9fd6b843 1223 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
adb54961 1224 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
b381a823 1225 if (ret == 0) {
9fd6b843
KS
1226 return AVERROR(EAGAIN);
1227 } else {
1228 return AVERROR(EIO);
1229 }
1230 }
bf7c1719
KS
1231 rt->bytes_read += ret;
1232 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
7f804085 1233 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
f645f1d6
SP
1234 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1235 return ret;
bf7c1719
KS
1236 rt->last_bytes_read = rt->bytes_read;
1237 }
9fd6b843
KS
1238
1239 ret = rtmp_parse_result(s, rt, &rpkt);
1240 if (ret < 0) {//serious error in current packet
1241 ff_rtmp_packet_destroy(&rpkt);
f645f1d6 1242 return ret;
9fd6b843 1243 }
72b870b9
MS
1244 if (rt->state == STATE_STOPPED) {
1245 ff_rtmp_packet_destroy(&rpkt);
1246 return AVERROR_EOF;
1247 }
6bf22e18 1248 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
9fd6b843
KS
1249 ff_rtmp_packet_destroy(&rpkt);
1250 return 0;
1251 }
6bf22e18 1252 if (!rpkt.data_size || !rt->is_input) {
9fd6b843
KS
1253 ff_rtmp_packet_destroy(&rpkt);
1254 continue;
1255 }
1256 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
afbacb93 1257 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
56e29bf2 1258 ts = rpkt.timestamp;
9fd6b843 1259
9fd6b843
KS
1260 // generate packet header and put data into buffer for FLV demuxer
1261 rt->flv_off = 0;
1262 rt->flv_size = rpkt.data_size + 15;
1263 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1264 bytestream_put_byte(&p, rpkt.type);
1265 bytestream_put_be24(&p, rpkt.data_size);
1266 bytestream_put_be24(&p, ts);
1267 bytestream_put_byte(&p, ts >> 24);
1268 bytestream_put_be24(&p, 0);
1269 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1270 bytestream_put_be32(&p, 0);
1271 ff_rtmp_packet_destroy(&rpkt);
1272 return 0;
1273 } else if (rpkt.type == RTMP_PT_METADATA) {
1274 // we got raw FLV data, make it available for FLV demuxer
1275 rt->flv_off = 0;
1276 rt->flv_size = rpkt.data_size;
1277 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
56e29bf2
S
1278 /* rewrite timestamps */
1279 next = rpkt.data;
1280 ts = rpkt.timestamp;
1281 while (next - rpkt.data < rpkt.data_size - 11) {
1282 next++;
1283 data_size = bytestream_get_be24(&next);
1284 p=next;
1285 cts = bytestream_get_be24(&next);
aae9a093 1286 cts |= bytestream_get_byte(&next) << 24;
56e29bf2
S
1287 if (pts==0)
1288 pts=cts;
1289 ts += cts - pts;
1290 pts = cts;
1291 bytestream_put_be24(&p, ts);
1292 bytestream_put_byte(&p, ts >> 24);
1293 next += data_size + 3 + 4;
1294 }
9fd6b843
KS
1295 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1296 ff_rtmp_packet_destroy(&rpkt);
1297 return 0;
1298 }
1299 ff_rtmp_packet_destroy(&rpkt);
1300 }
9fd6b843
KS
1301}
1302
1303static int rtmp_close(URLContext *h)
1304{
1305 RTMPContext *rt = h->priv_data;
f645f1d6 1306 int ret = 0;
9fd6b843 1307
e07c92e4 1308 if (!rt->is_input) {
6bf22e18
S
1309 rt->flv_data = NULL;
1310 if (rt->out_pkt.data_size)
1311 ff_rtmp_packet_destroy(&rt->out_pkt);
615c2879 1312 if (rt->state > STATE_FCPUBLISH)
f645f1d6 1313 ret = gen_fcunpublish_stream(h, rt);
6bf22e18 1314 }
615c2879 1315 if (rt->state > STATE_HANDSHAKED)
f645f1d6 1316 ret = gen_delete_stream(h, rt);
6bf22e18 1317
f89584ca 1318 free_tracked_methods(rt);
9fd6b843 1319 av_freep(&rt->flv_data);
e52a9145 1320 ffurl_close(rt->stream);
f645f1d6 1321 return ret;
9fd6b843
KS
1322}
1323
1324/**
49bd8e4b 1325 * Open RTMP connection and verify that the stream can be played.
9fd6b843
KS
1326 *
1327 * URL syntax: rtmp://server[:port][/app][/playpath]
1328 * where 'app' is first one or two directories in the path
1329 * (e.g. /ondemand/, /flash/live/, etc.)
1330 * and 'playpath' is a file name (the rest of the path,
1331 * may be prefixed with "mp4:")
1332 */
1333static int rtmp_open(URLContext *s, const char *uri, int flags)
1334{
7e580505 1335 RTMPContext *rt = s->priv_data;
5e9ad759 1336 char proto[8], hostname[256], path[1024], *fname;
6465562e 1337 char *old_app;
9fd6b843 1338 uint8_t buf[2048];
b316991b 1339 int port;
86991ce2 1340 AVDictionary *opts = NULL;
9fd6b843
KS
1341 int ret;
1342
59d96941 1343 rt->is_input = !(flags & AVIO_FLAG_WRITE);
9fd6b843 1344
f3bfe388 1345 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
f984dcf6 1346 path, sizeof(path), s->filename);
9fd6b843 1347
86991ce2
SP
1348 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
1349 if (!strcmp(proto, "rtmpts"))
1350 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
1351
8e50c57d 1352 /* open the http tunneling connection */
775c4d36 1353 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
6aedabc9
SP
1354 } else if (!strcmp(proto, "rtmps")) {
1355 /* open the tls connection */
1356 if (port < 0)
1357 port = RTMPS_DEFAULT_PORT;
1358 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
08cd95e8
SP
1359 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
1360 if (!strcmp(proto, "rtmpte"))
1361 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
1362
acd554c1
SP
1363 /* open the encrypted connection */
1364 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
1365 rt->encrypted = 1;
8e50c57d
SP
1366 } else {
1367 /* open the tcp connection */
1368 if (port < 0)
1369 port = RTMP_DEFAULT_PORT;
1370 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1371 }
9fd6b843 1372
f645f1d6 1373 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
86991ce2 1374 &s->interrupt_callback, &opts)) < 0) {
59d96941 1375 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
9fd6b843 1376 goto fail;
fe523958 1377 }
9fd6b843 1378
c7240611 1379 rt->state = STATE_START;
f645f1d6 1380 if ((ret = rtmp_handshake(s, rt)) < 0)
02490bf3 1381 goto fail;
9fd6b843 1382
c7240611
KS
1383 rt->chunk_size = 128;
1384 rt->state = STATE_HANDSHAKED;
6465562e
SP
1385
1386 // Keep the application name when it has been defined by the user.
1387 old_app = rt->app;
1388
1389 rt->app = av_malloc(APP_MAX_LENGTH);
1390 if (!rt->app) {
f645f1d6
SP
1391 ret = AVERROR(ENOMEM);
1392 goto fail;
6465562e
SP
1393 }
1394
c7240611
KS
1395 //extract "app" part from path
1396 if (!strncmp(path, "/ondemand/", 10)) {
1397 fname = path + 10;
1398 memcpy(rt->app, "ondemand", 9);
1399 } else {
4b7304e8
MS
1400 char *next = *path ? path + 1 : path;
1401 char *p = strchr(next, '/');
c7240611 1402 if (!p) {
4b7304e8 1403 fname = next;
c7240611 1404 rt->app[0] = '\0';
9fd6b843 1405 } else {
c6eeb9b7 1406 // make sure we do not mismatch a playpath for an application instance
c7240611
KS
1407 char *c = strchr(p + 1, ':');
1408 fname = strchr(p + 1, '/');
c6eeb9b7 1409 if (!fname || (c && c < fname)) {
c7240611
KS
1410 fname = p + 1;
1411 av_strlcpy(rt->app, path + 1, p - path);
9fd6b843 1412 } else {
c7240611
KS
1413 fname++;
1414 av_strlcpy(rt->app, path + 1, fname - path - 1);
9fd6b843
KS
1415 }
1416 }
c7240611 1417 }
6465562e
SP
1418
1419 if (old_app) {
1420 // The name of application has been defined by the user, override it.
1421 av_free(rt->app);
1422 rt->app = old_app;
1423 }
1424
b3b17512 1425 if (!rt->playpath) {
f862537d
SP
1426 int len = strlen(fname);
1427
b3b17512
SP
1428 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1429 if (!rt->playpath) {
f645f1d6
SP
1430 ret = AVERROR(ENOMEM);
1431 goto fail;
b3b17512
SP
1432 }
1433
0a9a2257 1434 if (!strchr(fname, ':') && len >= 4 &&
f862537d
SP
1435 (!strcmp(fname + len - 4, ".f4v") ||
1436 !strcmp(fname + len - 4, ".mp4"))) {
b3b17512 1437 memcpy(rt->playpath, "mp4:", 5);
0a9a2257 1438 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
f862537d 1439 fname[len - 4] = '\0';
b3b17512
SP
1440 } else {
1441 rt->playpath[0] = 0;
1442 }
1443 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
c7240611 1444 }
9fd6b843 1445
55c9320e
SP
1446 if (!rt->tcurl) {
1447 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
08e93f5b
SP
1448 if (!rt->tcurl) {
1449 ret = AVERROR(ENOMEM);
1450 goto fail;
1451 }
55c9320e
SP
1452 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1453 port, "/%s", rt->app);
1454 }
1455
e64673e4
SP
1456 if (!rt->flashver) {
1457 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
08e93f5b
SP
1458 if (!rt->flashver) {
1459 ret = AVERROR(ENOMEM);
1460 goto fail;
1461 }
e64673e4
SP
1462 if (rt->is_input) {
1463 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1464 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1465 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1466 } else {
1467 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1468 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1469 }
1470 }
1471
bf7c1719
KS
1472 rt->client_report_size = 1048576;
1473 rt->bytes_read = 0;
1474 rt->last_bytes_read = 0;
c2d38bea 1475 rt->server_bw = 2500000;
bf7c1719 1476
7f804085 1477 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
c7240611 1478 proto, path, rt->app, rt->playpath);
f645f1d6
SP
1479 if ((ret = gen_connect(s, rt)) < 0)
1480 goto fail;
9fd6b843 1481
c7240611
KS
1482 do {
1483 ret = get_packet(s, 1);
1484 } while (ret == EAGAIN);
1485 if (ret < 0)
1486 goto fail;
6bf22e18
S
1487
1488 if (rt->is_input) {
9fd6b843
KS
1489 // generate FLV header for demuxer
1490 rt->flv_size = 13;
1491 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1492 rt->flv_off = 0;
1493 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
6bf22e18
S
1494 } else {
1495 rt->flv_size = 0;
1496 rt->flv_data = NULL;
1497 rt->flv_off = 0;
b14629e5 1498 rt->skip_bytes = 13;
9fd6b843
KS
1499 }
1500
5958df34 1501 s->max_packet_size = rt->stream->max_packet_size;
9fd6b843
KS
1502 s->is_streamed = 1;
1503 return 0;
1504
1505fail:
86991ce2 1506 av_dict_free(&opts);
9fd6b843 1507 rtmp_close(s);
f645f1d6 1508 return ret;
9fd6b843
KS
1509}
1510
1511static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1512{
1513 RTMPContext *rt = s->priv_data;
1514 int orig_size = size;
1515 int ret;
1516
1517 while (size > 0) {
1518 int data_left = rt->flv_size - rt->flv_off;
1519
1520 if (data_left >= size) {
1521 memcpy(buf, rt->flv_data + rt->flv_off, size);
1522 rt->flv_off += size;
1523 return orig_size;
1524 }
1525 if (data_left > 0) {
1526 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1527 buf += data_left;
1528 size -= data_left;
1529 rt->flv_off = rt->flv_size;
e8ccf245 1530 return data_left;
9fd6b843
KS
1531 }
1532 if ((ret = get_packet(s, 0)) < 0)
1533 return ret;
1534 }
1535 return orig_size;
1536}
1537
9ad4c65f 1538static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
9fd6b843 1539{
9ad4c65f 1540 RTMPContext *rt = s->priv_data;
6bf22e18
S
1541 int size_temp = size;
1542 int pktsize, pkttype;
1543 uint32_t ts;
1544 const uint8_t *buf_temp = buf;
7dc747f5 1545 uint8_t c;
f645f1d6 1546 int ret;
6bf22e18 1547
6bf22e18 1548 do {
b14629e5
MS
1549 if (rt->skip_bytes) {
1550 int skip = FFMIN(rt->skip_bytes, size_temp);
1551 buf_temp += skip;
1552 size_temp -= skip;
1553 rt->skip_bytes -= skip;
1554 continue;
1555 }
1556
1557 if (rt->flv_header_bytes < 11) {
1558 const uint8_t *header = rt->flv_header;
1559 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1560 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1561 rt->flv_header_bytes += copy;
1562 size_temp -= copy;
1563 if (rt->flv_header_bytes < 11)
1564 break;
6bf22e18 1565
b14629e5
MS
1566 pkttype = bytestream_get_byte(&header);
1567 pktsize = bytestream_get_be24(&header);
1568 ts = bytestream_get_be24(&header);
1569 ts |= bytestream_get_byte(&header) << 24;
1570 bytestream_get_be24(&header);
6bf22e18
S
1571 rt->flv_size = pktsize;
1572
1573 //force 12bytes header
1574 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1575 pkttype == RTMP_PT_NOTIFY) {
1576 if (pkttype == RTMP_PT_NOTIFY)
1577 pktsize += 16;
1578 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1579 }
1580
1581 //this can be a big packet, it's better to send it right here
f645f1d6
SP
1582 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1583 pkttype, ts, pktsize)) < 0)
1584 return ret;
1585
6bf22e18
S
1586 rt->out_pkt.extra = rt->main_channel_id;
1587 rt->flv_data = rt->out_pkt.data;
1588
1589 if (pkttype == RTMP_PT_NOTIFY)
1590 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1591 }
1592
1593 if (rt->flv_size - rt->flv_off > size_temp) {
1594 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1595 rt->flv_off += size_temp;
a14c7842 1596 size_temp = 0;
6bf22e18
S
1597 } else {
1598 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
a14c7842 1599 size_temp -= rt->flv_size - rt->flv_off;
6bf22e18
S
1600 rt->flv_off += rt->flv_size - rt->flv_off;
1601 }
1602
1603 if (rt->flv_off == rt->flv_size) {
b14629e5
MS
1604 rt->skip_bytes = 4;
1605
f89584ca 1606 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
bba287fd 1607 return ret;
6bf22e18
S
1608 rt->flv_size = 0;
1609 rt->flv_off = 0;
b14629e5 1610 rt->flv_header_bytes = 0;
46743a85 1611 rt->flv_nb_packets++;
6bf22e18 1612 }
a14c7842 1613 } while (buf_temp - buf < size);
7dc747f5 1614
46743a85
SP
1615 if (rt->flv_nb_packets < rt->flush_interval)
1616 return size;
1617 rt->flv_nb_packets = 0;
1618
7dc747f5
SP
1619 /* set stream into nonblocking mode */
1620 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
1621
1622 /* try to read one byte from the stream */
1623 ret = ffurl_read(rt->stream, &c, 1);
1624
1625 /* switch the stream back into blocking mode */
1626 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
1627
1628 if (ret == AVERROR(EAGAIN)) {
1629 /* no incoming data to handle */
1630 return size;
1631 } else if (ret < 0) {
1632 return ret;
1633 } else if (ret == 1) {
1634 RTMPPacket rpkt = { 0 };
1635
1636 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
1637 rt->chunk_size,
1638 rt->prev_pkt[0], c)) <= 0)
1639 return ret;
1640
1641 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
1642 return ret;
1643
1644 ff_rtmp_packet_destroy(&rpkt);
1645 }
1646
6bf22e18 1647 return size;
9fd6b843
KS
1648}
1649
6465562e
SP
1650#define OFFSET(x) offsetof(RTMPContext, x)
1651#define DEC AV_OPT_FLAG_DECODING_PARAM
1652#define ENC AV_OPT_FLAG_ENCODING_PARAM
1653
1654static const AVOption rtmp_options[] = {
1655 {"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 1656 {"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 1657 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e64673e4 1658 {"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 1659 {"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
1660 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1661 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1662 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1663 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
758377a2 1664 {"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 1665 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
00cb52c6 1666 {"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 1667 {"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 1668 {"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
1669 { NULL },
1670};
1671
12127b65
SP
1672#define RTMP_PROTOCOL(flavor) \
1673static const AVClass flavor##_class = { \
1674 .class_name = #flavor, \
1675 .item_name = av_default_item_name, \
1676 .option = rtmp_options, \
1677 .version = LIBAVUTIL_VERSION_INT, \
1678}; \
1679 \
1680URLProtocol ff_##flavor##_protocol = { \
1681 .name = #flavor, \
1682 .url_open = rtmp_open, \
1683 .url_read = rtmp_read, \
1684 .url_write = rtmp_write, \
1685 .url_close = rtmp_close, \
1686 .priv_data_size = sizeof(RTMPContext), \
1687 .flags = URL_PROTOCOL_FLAG_NETWORK, \
1688 .priv_data_class= &flavor##_class, \
6465562e
SP
1689};
1690
08cd95e8 1691
12127b65
SP
1692RTMP_PROTOCOL(rtmp)
1693RTMP_PROTOCOL(rtmpe)
1694RTMP_PROTOCOL(rtmps)
1695RTMP_PROTOCOL(rtmpt)
1696RTMP_PROTOCOL(rtmpte)
1697RTMP_PROTOCOL(rtmpts)