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