Imported Debian version 2.5.0~trusty1.1
[deb_ffmpeg.git] / ffmpeg / libavformat / rtmpproto.c
CommitLineData
2ba45a60
DM
1/*
2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
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 *
12 * FFmpeg is distributed in the hope that it will be useful,
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
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * RTMP protocol
25 */
26
27#include "libavcodec/bytestream.h"
28#include "libavutil/avstring.h"
29#include "libavutil/base64.h"
30#include "libavutil/intfloat.h"
31#include "libavutil/lfg.h"
32#include "libavutil/md5.h"
33#include "libavutil/opt.h"
34#include "libavutil/random_seed.h"
35#include "libavutil/sha.h"
36#include "avformat.h"
37#include "internal.h"
38
39#include "network.h"
40
41#include "flv.h"
42#include "rtmp.h"
43#include "rtmpcrypt.h"
44#include "rtmppkt.h"
45#include "url.h"
46
47#if CONFIG_ZLIB
48#include <zlib.h>
49#endif
50
51#define APP_MAX_LENGTH 1024
52#define PLAYPATH_MAX_LENGTH 256
53#define TCURL_MAX_LENGTH 512
54#define FLASHVER_MAX_LENGTH 64
55#define RTMP_PKTDATA_DEFAULT_SIZE 4096
56#define RTMP_HEADER 11
57
58/** RTMP protocol handler state */
59typedef enum {
60 STATE_START, ///< client has not done anything yet
61 STATE_HANDSHAKED, ///< client has performed handshake
62 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
63 STATE_PLAYING, ///< client has started receiving multimedia data from server
64 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
65 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
66 STATE_RECEIVING, ///< received a publish command (for input)
67 STATE_SENDING, ///< received a play command (for output)
68 STATE_STOPPED, ///< the broadcast has been stopped
69} ClientState;
70
71typedef struct TrackedMethod {
72 char *name;
73 int id;
74} TrackedMethod;
75
76/** protocol handler context */
77typedef struct RTMPContext {
78 const AVClass *class;
79 URLContext* stream; ///< TCP stream used in interactions with RTMP server
80 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
81 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
82 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
83 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
84 int is_input; ///< input/output flag
85 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
86 int live; ///< 0: recorded, -1: live, -2: both
87 char *app; ///< name of application
88 char *conn; ///< append arbitrary AMF data to the Connect message
89 ClientState state; ///< current state
90 int stream_id; ///< ID assigned by the server for the stream
91 uint8_t* flv_data; ///< buffer with data for demuxer
92 int flv_size; ///< current buffer size
93 int flv_off; ///< number of bytes read from current buffer
94 int flv_nb_packets; ///< number of flv packets published
95 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
96 uint32_t client_report_size; ///< number of bytes after which client should report to server
97 uint32_t bytes_read; ///< number of bytes read from server
98 uint32_t last_bytes_read; ///< number of bytes read last reported to server
f6fa7814 99 uint32_t last_timestamp; ///< last timestamp received in a packet
2ba45a60
DM
100 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
101 int has_audio; ///< presence of audio data
102 int has_video; ///< presence of video data
103 int received_metadata; ///< Indicates if we have received metadata about the streams
104 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
105 int flv_header_bytes; ///< number of initialized bytes in flv_header
106 int nb_invokes; ///< keeps track of invoke messages
107 char* tcurl; ///< url of the target stream
108 char* flashver; ///< version of the flash plugin
109 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
110 int swfhash_len; ///< length of the SHA256 hash
111 int swfsize; ///< size of the decompressed SWF file
112 char* swfurl; ///< url of the swf player
113 char* swfverify; ///< URL to player swf file, compute hash/size automatically
114 char swfverification[42]; ///< hash of the SWF verification
115 char* pageurl; ///< url of the web page
116 char* subscribe; ///< name of live stream to subscribe
117 int server_bw; ///< server bandwidth
118 int client_buffer_time; ///< client buffer time in ms
119 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
120 int encrypted; ///< use an encrypted connection (RTMPE only)
121 TrackedMethod*tracked_methods; ///< tracked methods buffer
122 int nb_tracked_methods; ///< number of tracked methods
123 int tracked_methods_size; ///< size of the tracked methods buffer
124 int listen; ///< listen mode flag
125 int listen_timeout; ///< listen timeout to wait for new connections
126 int nb_streamid; ///< The next stream id to return on createStream calls
f6fa7814 127 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
2ba45a60
DM
128 char username[50];
129 char password[50];
130 char auth_params[500];
131 int do_reconnect;
132 int auth_tried;
133} RTMPContext;
134
135#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
136/** Client key used for digest signing */
137static const uint8_t rtmp_player_key[] = {
138 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
139 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
140
141 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
142 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
143 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
144};
145
146#define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
147/** Key used for RTMP server digest signing */
148static const uint8_t rtmp_server_key[] = {
149 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
150 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
151 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
152
153 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
154 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
155 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
156};
157
158static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
159
160static int add_tracked_method(RTMPContext *rt, const char *name, int id)
161{
162 int err;
163
164 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
165 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
166 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
167 sizeof(*rt->tracked_methods))) < 0) {
168 rt->nb_tracked_methods = 0;
169 rt->tracked_methods_size = 0;
170 return err;
171 }
172 }
173
174 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
175 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
176 return AVERROR(ENOMEM);
177 rt->tracked_methods[rt->nb_tracked_methods].id = id;
178 rt->nb_tracked_methods++;
179
180 return 0;
181}
182
183static void del_tracked_method(RTMPContext *rt, int index)
184{
185 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
186 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
187 rt->nb_tracked_methods--;
188}
189
190static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
191 char **tracked_method)
192{
193 RTMPContext *rt = s->priv_data;
194 GetByteContext gbc;
195 double pkt_id;
196 int ret;
197 int i;
198
199 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
200 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
201 return ret;
202
203 for (i = 0; i < rt->nb_tracked_methods; i++) {
204 if (rt->tracked_methods[i].id != pkt_id)
205 continue;
206
207 *tracked_method = rt->tracked_methods[i].name;
208 del_tracked_method(rt, i);
209 break;
210 }
211
212 return 0;
213}
214
215static void free_tracked_methods(RTMPContext *rt)
216{
217 int i;
218
219 for (i = 0; i < rt->nb_tracked_methods; i ++)
220 av_free(rt->tracked_methods[i].name);
221 av_free(rt->tracked_methods);
222 rt->tracked_methods = NULL;
223 rt->tracked_methods_size = 0;
224 rt->nb_tracked_methods = 0;
225}
226
227static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
228{
229 int ret;
230
231 if (pkt->type == RTMP_PT_INVOKE && track) {
232 GetByteContext gbc;
233 char name[128];
234 double pkt_id;
235 int len;
236
237 bytestream2_init(&gbc, pkt->data, pkt->size);
238 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
239 goto fail;
240
241 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
242 goto fail;
243
244 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
245 goto fail;
246 }
247
248 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
249 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
250fail:
251 ff_rtmp_packet_destroy(pkt);
252 return ret;
253}
254
255static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
256{
257 char *field, *value;
258 char type;
259
260 /* The type must be B for Boolean, N for number, S for string, O for
261 * object, or Z for null. For Booleans the data must be either 0 or 1 for
262 * FALSE or TRUE, respectively. Likewise for Objects the data must be
263 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
264 * may be named, by prefixing the type with 'N' and specifying the name
265 * before the value (ie. NB:myFlag:1). This option may be used multiple times
266 * to construct arbitrary AMF sequences. */
267 if (param[0] && param[1] == ':') {
268 type = param[0];
269 value = param + 2;
270 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
271 type = param[1];
272 field = param + 3;
273 value = strchr(field, ':');
274 if (!value)
275 goto fail;
276 *value = '\0';
277 value++;
278
279 ff_amf_write_field_name(p, field);
280 } else {
281 goto fail;
282 }
283
284 switch (type) {
285 case 'B':
286 ff_amf_write_bool(p, value[0] != '0');
287 break;
288 case 'S':
289 ff_amf_write_string(p, value);
290 break;
291 case 'N':
292 ff_amf_write_number(p, strtod(value, NULL));
293 break;
294 case 'Z':
295 ff_amf_write_null(p);
296 break;
297 case 'O':
298 if (value[0] != '0')
299 ff_amf_write_object_start(p);
300 else
301 ff_amf_write_object_end(p);
302 break;
303 default:
304 goto fail;
305 break;
306 }
307
308 return 0;
309
310fail:
311 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
312 return AVERROR(EINVAL);
313}
314
315/**
316 * Generate 'connect' call and send it to the server.
317 */
318static int gen_connect(URLContext *s, RTMPContext *rt)
319{
320 RTMPPacket pkt;
321 uint8_t *p;
322 int ret;
323
324 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
325 0, 4096 + APP_MAX_LENGTH)) < 0)
326 return ret;
327
328 p = pkt.data;
329
330 ff_amf_write_string(&p, "connect");
331 ff_amf_write_number(&p, ++rt->nb_invokes);
332 ff_amf_write_object_start(&p);
333 ff_amf_write_field_name(&p, "app");
334 ff_amf_write_string2(&p, rt->app, rt->auth_params);
335
336 if (!rt->is_input) {
337 ff_amf_write_field_name(&p, "type");
338 ff_amf_write_string(&p, "nonprivate");
339 }
340 ff_amf_write_field_name(&p, "flashVer");
341 ff_amf_write_string(&p, rt->flashver);
342
343 if (rt->swfurl) {
344 ff_amf_write_field_name(&p, "swfUrl");
345 ff_amf_write_string(&p, rt->swfurl);
346 }
347
348 ff_amf_write_field_name(&p, "tcUrl");
349 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
350 if (rt->is_input) {
351 ff_amf_write_field_name(&p, "fpad");
352 ff_amf_write_bool(&p, 0);
353 ff_amf_write_field_name(&p, "capabilities");
354 ff_amf_write_number(&p, 15.0);
355
356 /* Tell the server we support all the audio codecs except
357 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
358 * which are unused in the RTMP protocol implementation. */
359 ff_amf_write_field_name(&p, "audioCodecs");
360 ff_amf_write_number(&p, 4071.0);
361 ff_amf_write_field_name(&p, "videoCodecs");
362 ff_amf_write_number(&p, 252.0);
363 ff_amf_write_field_name(&p, "videoFunction");
364 ff_amf_write_number(&p, 1.0);
365
366 if (rt->pageurl) {
367 ff_amf_write_field_name(&p, "pageUrl");
368 ff_amf_write_string(&p, rt->pageurl);
369 }
370 }
371 ff_amf_write_object_end(&p);
372
373 if (rt->conn) {
374 char *param = rt->conn;
375
376 // Write arbitrary AMF data to the Connect message.
377 while (param) {
378 char *sep;
379 param += strspn(param, " ");
380 if (!*param)
381 break;
382 sep = strchr(param, ' ');
383 if (sep)
384 *sep = '\0';
385 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
386 // Invalid AMF parameter.
387 ff_rtmp_packet_destroy(&pkt);
388 return ret;
389 }
390
391 if (sep)
392 param = sep + 1;
393 else
394 break;
395 }
396 }
397
398 pkt.size = p - pkt.data;
399
400 return rtmp_send_packet(rt, &pkt, 1);
401}
402
403static int read_connect(URLContext *s, RTMPContext *rt)
404{
405 RTMPPacket pkt = { 0 };
406 uint8_t *p;
407 const uint8_t *cp;
408 int ret;
409 char command[64];
410 int stringlen;
411 double seqnum;
412 uint8_t tmpstr[256];
413 GetByteContext gbc;
414
415 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
416 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
417 return ret;
418
419 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
420 if ((ret = handle_chunk_size(s, &pkt)) < 0)
421 return ret;
422
423 ff_rtmp_packet_destroy(&pkt);
424 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
425 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
426 return ret;
427 }
428
429 cp = pkt.data;
430 bytestream2_init(&gbc, cp, pkt.size);
431 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
432 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
433 ff_rtmp_packet_destroy(&pkt);
434 return AVERROR_INVALIDDATA;
435 }
436 if (strcmp(command, "connect")) {
437 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
438 ff_rtmp_packet_destroy(&pkt);
439 return AVERROR_INVALIDDATA;
440 }
441 ret = ff_amf_read_number(&gbc, &seqnum);
442 if (ret)
443 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
444 /* Here one could parse an AMF Object with data as flashVers and others. */
445 ret = ff_amf_get_field_value(gbc.buffer,
446 gbc.buffer + bytestream2_get_bytes_left(&gbc),
447 "app", tmpstr, sizeof(tmpstr));
448 if (ret)
449 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
450 if (!ret && strcmp(tmpstr, rt->app))
451 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
452 tmpstr, rt->app);
453 ff_rtmp_packet_destroy(&pkt);
454
455 // Send Window Acknowledgement Size (as defined in speficication)
456 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
457 RTMP_PT_SERVER_BW, 0, 4)) < 0)
458 return ret;
459 p = pkt.data;
460 bytestream_put_be32(&p, rt->server_bw);
461 pkt.size = p - pkt.data;
462 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
463 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
464 ff_rtmp_packet_destroy(&pkt);
465 if (ret < 0)
466 return ret;
467 // Send Peer Bandwidth
468 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
469 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
470 return ret;
471 p = pkt.data;
472 bytestream_put_be32(&p, rt->server_bw);
473 bytestream_put_byte(&p, 2); // dynamic
474 pkt.size = p - pkt.data;
475 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
476 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
477 ff_rtmp_packet_destroy(&pkt);
478 if (ret < 0)
479 return ret;
480
481 // Ping request
482 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
483 RTMP_PT_PING, 0, 6)) < 0)
484 return ret;
485
486 p = pkt.data;
487 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
488 bytestream_put_be32(&p, 0);
489 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
490 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
491 ff_rtmp_packet_destroy(&pkt);
492 if (ret < 0)
493 return ret;
494
495 // Chunk size
496 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
497 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
498 return ret;
499
500 p = pkt.data;
501 bytestream_put_be32(&p, rt->out_chunk_size);
502 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
503 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
504 ff_rtmp_packet_destroy(&pkt);
505 if (ret < 0)
506 return ret;
507
f6fa7814 508 // Send _result NetConnection.Connect.Success to connect
2ba45a60
DM
509 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
510 RTMP_PT_INVOKE, 0,
511 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
512 return ret;
513
514 p = pkt.data;
515 ff_amf_write_string(&p, "_result");
516 ff_amf_write_number(&p, seqnum);
517
518 ff_amf_write_object_start(&p);
519 ff_amf_write_field_name(&p, "fmsVer");
520 ff_amf_write_string(&p, "FMS/3,0,1,123");
521 ff_amf_write_field_name(&p, "capabilities");
522 ff_amf_write_number(&p, 31);
523 ff_amf_write_object_end(&p);
524
525 ff_amf_write_object_start(&p);
526 ff_amf_write_field_name(&p, "level");
527 ff_amf_write_string(&p, "status");
528 ff_amf_write_field_name(&p, "code");
529 ff_amf_write_string(&p, "NetConnection.Connect.Success");
530 ff_amf_write_field_name(&p, "description");
531 ff_amf_write_string(&p, "Connection succeeded.");
532 ff_amf_write_field_name(&p, "objectEncoding");
533 ff_amf_write_number(&p, 0);
534 ff_amf_write_object_end(&p);
535
536 pkt.size = p - pkt.data;
537 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
538 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
539 ff_rtmp_packet_destroy(&pkt);
540 if (ret < 0)
541 return ret;
542
543 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
544 RTMP_PT_INVOKE, 0, 30)) < 0)
545 return ret;
546 p = pkt.data;
547 ff_amf_write_string(&p, "onBWDone");
548 ff_amf_write_number(&p, 0);
549 ff_amf_write_null(&p);
550 ff_amf_write_number(&p, 8192);
551 pkt.size = p - pkt.data;
552 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
553 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
554 ff_rtmp_packet_destroy(&pkt);
555
556 return ret;
557}
558
559/**
560 * Generate 'releaseStream' call and send it to the server. It should make
561 * the server release some channel for media streams.
562 */
563static int gen_release_stream(URLContext *s, RTMPContext *rt)
564{
565 RTMPPacket pkt;
566 uint8_t *p;
567 int ret;
568
569 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
570 0, 29 + strlen(rt->playpath))) < 0)
571 return ret;
572
573 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
574 p = pkt.data;
575 ff_amf_write_string(&p, "releaseStream");
576 ff_amf_write_number(&p, ++rt->nb_invokes);
577 ff_amf_write_null(&p);
578 ff_amf_write_string(&p, rt->playpath);
579
580 return rtmp_send_packet(rt, &pkt, 1);
581}
582
583/**
584 * Generate 'FCPublish' call and send it to the server. It should make
585 * the server preapare for receiving media streams.
586 */
587static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
588{
589 RTMPPacket pkt;
590 uint8_t *p;
591 int ret;
592
593 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
594 0, 25 + strlen(rt->playpath))) < 0)
595 return ret;
596
597 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
598 p = pkt.data;
599 ff_amf_write_string(&p, "FCPublish");
600 ff_amf_write_number(&p, ++rt->nb_invokes);
601 ff_amf_write_null(&p);
602 ff_amf_write_string(&p, rt->playpath);
603
604 return rtmp_send_packet(rt, &pkt, 1);
605}
606
607/**
608 * Generate 'FCUnpublish' call and send it to the server. It should make
609 * the server destroy stream.
610 */
611static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
612{
613 RTMPPacket pkt;
614 uint8_t *p;
615 int ret;
616
617 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
618 0, 27 + strlen(rt->playpath))) < 0)
619 return ret;
620
621 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
622 p = pkt.data;
623 ff_amf_write_string(&p, "FCUnpublish");
624 ff_amf_write_number(&p, ++rt->nb_invokes);
625 ff_amf_write_null(&p);
626 ff_amf_write_string(&p, rt->playpath);
627
628 return rtmp_send_packet(rt, &pkt, 0);
629}
630
631/**
632 * Generate 'createStream' call and send it to the server. It should make
633 * the server allocate some channel for media streams.
634 */
635static int gen_create_stream(URLContext *s, RTMPContext *rt)
636{
637 RTMPPacket pkt;
638 uint8_t *p;
639 int ret;
640
641 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
642
643 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
644 0, 25)) < 0)
645 return ret;
646
647 p = pkt.data;
648 ff_amf_write_string(&p, "createStream");
649 ff_amf_write_number(&p, ++rt->nb_invokes);
650 ff_amf_write_null(&p);
651
652 return rtmp_send_packet(rt, &pkt, 1);
653}
654
655
656/**
657 * Generate 'deleteStream' call and send it to the server. It should make
658 * the server remove some channel for media streams.
659 */
660static int gen_delete_stream(URLContext *s, RTMPContext *rt)
661{
662 RTMPPacket pkt;
663 uint8_t *p;
664 int ret;
665
666 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
667
668 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
669 0, 34)) < 0)
670 return ret;
671
672 p = pkt.data;
673 ff_amf_write_string(&p, "deleteStream");
674 ff_amf_write_number(&p, ++rt->nb_invokes);
675 ff_amf_write_null(&p);
676 ff_amf_write_number(&p, rt->stream_id);
677
678 return rtmp_send_packet(rt, &pkt, 0);
679}
680
f6fa7814
DM
681/**
682 * Generate 'getStreamLength' call and send it to the server. If the server
683 * knows the duration of the selected stream, it will reply with the duration
684 * in seconds.
685 */
686static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
687{
688 RTMPPacket pkt;
689 uint8_t *p;
690 int ret;
691
692 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
693 0, 31 + strlen(rt->playpath))) < 0)
694 return ret;
695
696 p = pkt.data;
697 ff_amf_write_string(&p, "getStreamLength");
698 ff_amf_write_number(&p, ++rt->nb_invokes);
699 ff_amf_write_null(&p);
700 ff_amf_write_string(&p, rt->playpath);
701
702 return rtmp_send_packet(rt, &pkt, 1);
703}
704
2ba45a60
DM
705/**
706 * Generate client buffer time and send it to the server.
707 */
708static int gen_buffer_time(URLContext *s, RTMPContext *rt)
709{
710 RTMPPacket pkt;
711 uint8_t *p;
712 int ret;
713
714 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
715 1, 10)) < 0)
716 return ret;
717
718 p = pkt.data;
719 bytestream_put_be16(&p, 3);
720 bytestream_put_be32(&p, rt->stream_id);
721 bytestream_put_be32(&p, rt->client_buffer_time);
722
723 return rtmp_send_packet(rt, &pkt, 0);
724}
725
726/**
727 * Generate 'play' call and send it to the server, then ping the server
728 * to start actual playing.
729 */
730static int gen_play(URLContext *s, RTMPContext *rt)
731{
732 RTMPPacket pkt;
733 uint8_t *p;
734 int ret;
735
736 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
737
738 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
739 0, 29 + strlen(rt->playpath))) < 0)
740 return ret;
741
742 pkt.extra = rt->stream_id;
743
744 p = pkt.data;
745 ff_amf_write_string(&p, "play");
746 ff_amf_write_number(&p, ++rt->nb_invokes);
747 ff_amf_write_null(&p);
748 ff_amf_write_string(&p, rt->playpath);
749 ff_amf_write_number(&p, rt->live * 1000);
750
751 return rtmp_send_packet(rt, &pkt, 1);
752}
753
754static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
755{
756 RTMPPacket pkt;
757 uint8_t *p;
758 int ret;
759
760 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
761 timestamp);
762
763 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
764 return ret;
765
766 pkt.extra = rt->stream_id;
767
768 p = pkt.data;
769 ff_amf_write_string(&p, "seek");
770 ff_amf_write_number(&p, 0); //no tracking back responses
771 ff_amf_write_null(&p); //as usual, the first null param
772 ff_amf_write_number(&p, timestamp); //where we want to jump
773
774 return rtmp_send_packet(rt, &pkt, 1);
775}
776
f6fa7814
DM
777/**
778 * Generate a pause packet that either pauses or unpauses the current stream.
779 */
780static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
781{
782 RTMPPacket pkt;
783 uint8_t *p;
784 int ret;
785
786 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
787 timestamp);
788
789 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
790 return ret;
791
792 pkt.extra = rt->stream_id;
793
794 p = pkt.data;
795 ff_amf_write_string(&p, "pause");
796 ff_amf_write_number(&p, 0); //no tracking back responses
797 ff_amf_write_null(&p); //as usual, the first null param
798 ff_amf_write_bool(&p, pause); // pause or unpause
799 ff_amf_write_number(&p, timestamp); //where we pause the stream
800
801 return rtmp_send_packet(rt, &pkt, 1);
802}
803
2ba45a60
DM
804/**
805 * Generate 'publish' call and send it to the server.
806 */
807static int gen_publish(URLContext *s, RTMPContext *rt)
808{
809 RTMPPacket pkt;
810 uint8_t *p;
811 int ret;
812
813 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
814
815 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
816 0, 30 + strlen(rt->playpath))) < 0)
817 return ret;
818
819 pkt.extra = rt->stream_id;
820
821 p = pkt.data;
822 ff_amf_write_string(&p, "publish");
823 ff_amf_write_number(&p, ++rt->nb_invokes);
824 ff_amf_write_null(&p);
825 ff_amf_write_string(&p, rt->playpath);
826 ff_amf_write_string(&p, "live");
827
828 return rtmp_send_packet(rt, &pkt, 1);
829}
830
831/**
832 * Generate ping reply and send it to the server.
833 */
834static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
835{
836 RTMPPacket pkt;
837 uint8_t *p;
838 int ret;
839
840 if (ppkt->size < 6) {
841 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
842 ppkt->size);
843 return AVERROR_INVALIDDATA;
844 }
845
846 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
847 ppkt->timestamp + 1, 6)) < 0)
848 return ret;
849
850 p = pkt.data;
851 bytestream_put_be16(&p, 7);
852 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
853
854 return rtmp_send_packet(rt, &pkt, 0);
855}
856
857/**
858 * Generate SWF verification message and send it to the server.
859 */
860static int gen_swf_verification(URLContext *s, RTMPContext *rt)
861{
862 RTMPPacket pkt;
863 uint8_t *p;
864 int ret;
865
866 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
867 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
868 0, 44)) < 0)
869 return ret;
870
871 p = pkt.data;
872 bytestream_put_be16(&p, 27);
873 memcpy(p, rt->swfverification, 42);
874
875 return rtmp_send_packet(rt, &pkt, 0);
876}
877
878/**
879 * Generate server bandwidth message and send it to the server.
880 */
881static int gen_server_bw(URLContext *s, RTMPContext *rt)
882{
883 RTMPPacket pkt;
884 uint8_t *p;
885 int ret;
886
887 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
888 0, 4)) < 0)
889 return ret;
890
891 p = pkt.data;
892 bytestream_put_be32(&p, rt->server_bw);
893
894 return rtmp_send_packet(rt, &pkt, 0);
895}
896
897/**
898 * Generate check bandwidth message and send it to the server.
899 */
900static int gen_check_bw(URLContext *s, RTMPContext *rt)
901{
902 RTMPPacket pkt;
903 uint8_t *p;
904 int ret;
905
906 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
907 0, 21)) < 0)
908 return ret;
909
910 p = pkt.data;
911 ff_amf_write_string(&p, "_checkbw");
912 ff_amf_write_number(&p, ++rt->nb_invokes);
913 ff_amf_write_null(&p);
914
915 return rtmp_send_packet(rt, &pkt, 1);
916}
917
918/**
919 * Generate report on bytes read so far and send it to the server.
920 */
921static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
922{
923 RTMPPacket pkt;
924 uint8_t *p;
925 int ret;
926
927 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
928 ts, 4)) < 0)
929 return ret;
930
931 p = pkt.data;
932 bytestream_put_be32(&p, rt->bytes_read);
933
934 return rtmp_send_packet(rt, &pkt, 0);
935}
936
937static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
938 const char *subscribe)
939{
940 RTMPPacket pkt;
941 uint8_t *p;
942 int ret;
943
944 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
945 0, 27 + strlen(subscribe))) < 0)
946 return ret;
947
948 p = pkt.data;
949 ff_amf_write_string(&p, "FCSubscribe");
950 ff_amf_write_number(&p, ++rt->nb_invokes);
951 ff_amf_write_null(&p);
952 ff_amf_write_string(&p, subscribe);
953
954 return rtmp_send_packet(rt, &pkt, 1);
955}
956
957int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
958 const uint8_t *key, int keylen, uint8_t *dst)
959{
960 struct AVSHA *sha;
961 uint8_t hmac_buf[64+32] = {0};
962 int i;
963
964 sha = av_sha_alloc();
965 if (!sha)
966 return AVERROR(ENOMEM);
967
968 if (keylen < 64) {
969 memcpy(hmac_buf, key, keylen);
970 } else {
971 av_sha_init(sha, 256);
972 av_sha_update(sha,key, keylen);
973 av_sha_final(sha, hmac_buf);
974 }
975 for (i = 0; i < 64; i++)
976 hmac_buf[i] ^= HMAC_IPAD_VAL;
977
978 av_sha_init(sha, 256);
979 av_sha_update(sha, hmac_buf, 64);
980 if (gap <= 0) {
981 av_sha_update(sha, src, len);
982 } else { //skip 32 bytes used for storing digest
983 av_sha_update(sha, src, gap);
984 av_sha_update(sha, src + gap + 32, len - gap - 32);
985 }
986 av_sha_final(sha, hmac_buf + 64);
987
988 for (i = 0; i < 64; i++)
989 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
990 av_sha_init(sha, 256);
991 av_sha_update(sha, hmac_buf, 64+32);
992 av_sha_final(sha, dst);
993
994 av_free(sha);
995
996 return 0;
997}
998
999int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
1000 int add_val)
1001{
1002 int i, digest_pos = 0;
1003
1004 for (i = 0; i < 4; i++)
1005 digest_pos += buf[i + off];
1006 digest_pos = digest_pos % mod_val + add_val;
1007
1008 return digest_pos;
1009}
1010
1011/**
1012 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1013 * will be stored) into that packet.
1014 *
1015 * @param buf handshake data (1536 bytes)
1016 * @param encrypted use an encrypted connection (RTMPE)
1017 * @return offset to the digest inside input data
1018 */
1019static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1020{
1021 int ret, digest_pos;
1022
1023 if (encrypted)
1024 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1025 else
1026 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1027
1028 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1029 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1030 buf + digest_pos);
1031 if (ret < 0)
1032 return ret;
1033
1034 return digest_pos;
1035}
1036
1037/**
1038 * Verify that the received server response has the expected digest value.
1039 *
1040 * @param buf handshake data received from the server (1536 bytes)
1041 * @param off position to search digest offset from
1042 * @return 0 if digest is valid, digest position otherwise
1043 */
1044static int rtmp_validate_digest(uint8_t *buf, int off)
1045{
1046 uint8_t digest[32];
1047 int ret, digest_pos;
1048
1049 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1050
1051 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1052 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1053 digest);
1054 if (ret < 0)
1055 return ret;
1056
1057 if (!memcmp(digest, buf + digest_pos, 32))
1058 return digest_pos;
1059 return 0;
1060}
1061
1062static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1063 uint8_t *buf)
1064{
1065 uint8_t *p;
1066 int ret;
1067
1068 if (rt->swfhash_len != 32) {
1069 av_log(s, AV_LOG_ERROR,
1070 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1071 return AVERROR(EINVAL);
1072 }
1073
1074 p = &rt->swfverification[0];
1075 bytestream_put_byte(&p, 1);
1076 bytestream_put_byte(&p, 1);
1077 bytestream_put_be32(&p, rt->swfsize);
1078 bytestream_put_be32(&p, rt->swfsize);
1079
1080 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1081 return ret;
1082
1083 return 0;
1084}
1085
1086#if CONFIG_ZLIB
1087static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1088 uint8_t **out_data, int64_t *out_size)
1089{
1090 z_stream zs = { 0 };
1091 void *ptr;
1092 int size;
1093 int ret = 0;
1094
1095 zs.avail_in = in_size;
1096 zs.next_in = in_data;
1097 ret = inflateInit(&zs);
1098 if (ret != Z_OK)
1099 return AVERROR_UNKNOWN;
1100
1101 do {
1102 uint8_t tmp_buf[16384];
1103
1104 zs.avail_out = sizeof(tmp_buf);
1105 zs.next_out = tmp_buf;
1106
1107 ret = inflate(&zs, Z_NO_FLUSH);
1108 if (ret != Z_OK && ret != Z_STREAM_END) {
1109 ret = AVERROR_UNKNOWN;
1110 goto fail;
1111 }
1112
1113 size = sizeof(tmp_buf) - zs.avail_out;
1114 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1115 ret = AVERROR(ENOMEM);
1116 goto fail;
1117 }
1118 *out_data = ptr;
1119
1120 memcpy(*out_data + *out_size, tmp_buf, size);
1121 *out_size += size;
1122 } while (zs.avail_out == 0);
1123
1124fail:
1125 inflateEnd(&zs);
1126 return ret;
1127}
1128#endif
1129
1130static int rtmp_calc_swfhash(URLContext *s)
1131{
1132 RTMPContext *rt = s->priv_data;
1133 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1134 int64_t in_size, out_size;
1135 URLContext *stream;
1136 char swfhash[32];
1137 int swfsize;
1138 int ret = 0;
1139
1140 /* Get the SWF player file. */
1141 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1142 &s->interrupt_callback, NULL)) < 0) {
1143 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1144 goto fail;
1145 }
1146
1147 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1148 ret = AVERROR(EIO);
1149 goto fail;
1150 }
1151
1152 if (!(in_data = av_malloc(in_size))) {
1153 ret = AVERROR(ENOMEM);
1154 goto fail;
1155 }
1156
1157 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1158 goto fail;
1159
1160 if (in_size < 3) {
1161 ret = AVERROR_INVALIDDATA;
1162 goto fail;
1163 }
1164
1165 if (!memcmp(in_data, "CWS", 3)) {
1166 /* Decompress the SWF player file using Zlib. */
1167 if (!(out_data = av_malloc(8))) {
1168 ret = AVERROR(ENOMEM);
1169 goto fail;
1170 }
1171 *in_data = 'F'; // magic stuff
1172 memcpy(out_data, in_data, 8);
1173 out_size = 8;
1174
1175#if CONFIG_ZLIB
1176 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1177 &out_data, &out_size)) < 0)
1178 goto fail;
1179#else
1180 av_log(s, AV_LOG_ERROR,
1181 "Zlib is required for decompressing the SWF player file.\n");
1182 ret = AVERROR(EINVAL);
1183 goto fail;
1184#endif
1185 swfsize = out_size;
1186 swfdata = out_data;
1187 } else {
1188 swfsize = in_size;
1189 swfdata = in_data;
1190 }
1191
1192 /* Compute the SHA256 hash of the SWF player file. */
1193 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1194 "Genuine Adobe Flash Player 001", 30,
1195 swfhash)) < 0)
1196 goto fail;
1197
1198 /* Set SWFVerification parameters. */
1199 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1200 rt->swfsize = swfsize;
1201
1202fail:
1203 av_freep(&in_data);
1204 av_freep(&out_data);
1205 ffurl_close(stream);
1206 return ret;
1207}
1208
1209/**
1210 * Perform handshake with the server by means of exchanging pseudorandom data
1211 * signed with HMAC-SHA2 digest.
1212 *
1213 * @return 0 if handshake succeeds, negative value otherwise
1214 */
1215static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1216{
1217 AVLFG rnd;
1218 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1219 3, // unencrypted data
1220 0, 0, 0, 0, // client uptime
1221 RTMP_CLIENT_VER1,
1222 RTMP_CLIENT_VER2,
1223 RTMP_CLIENT_VER3,
1224 RTMP_CLIENT_VER4,
1225 };
1226 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1227 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1228 int i;
1229 int server_pos, client_pos;
1230 uint8_t digest[32], signature[32];
1231 int ret, type = 0;
1232
1233 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1234
1235 av_lfg_init(&rnd, 0xDEADC0DE);
1236 // generate handshake packet - 1536 bytes of pseudorandom data
1237 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1238 tosend[i] = av_lfg_get(&rnd) >> 24;
1239
1240 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1241 /* When the client wants to use RTMPE, we have to change the command
1242 * byte to 0x06 which means to use encrypted data and we have to set
1243 * the flash version to at least 9.0.115.0. */
1244 tosend[0] = 6;
1245 tosend[5] = 128;
1246 tosend[6] = 0;
1247 tosend[7] = 3;
1248 tosend[8] = 2;
1249
1250 /* Initialize the Diffie-Hellmann context and generate the public key
1251 * to send to the server. */
1252 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1253 return ret;
1254 }
1255
1256 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1257 if (client_pos < 0)
1258 return client_pos;
1259
1260 if ((ret = ffurl_write(rt->stream, tosend,
1261 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1262 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1263 return ret;
1264 }
1265
1266 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1267 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1268 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1269 return ret;
1270 }
1271
1272 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1273 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1274 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1275 return ret;
1276 }
1277
1278 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1279 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1280 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1281
1282 if (rt->is_input && serverdata[5] >= 3) {
1283 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1284 if (server_pos < 0)
1285 return server_pos;
1286
1287 if (!server_pos) {
1288 type = 1;
1289 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1290 if (server_pos < 0)
1291 return server_pos;
1292
1293 if (!server_pos) {
1294 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1295 return AVERROR(EIO);
1296 }
1297 }
1298
1299 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1300 * key are the last 32 bytes of the server handshake. */
1301 if (rt->swfsize) {
1302 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1303 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1304 return ret;
1305 }
1306
1307 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1308 rtmp_server_key, sizeof(rtmp_server_key),
1309 digest);
1310 if (ret < 0)
1311 return ret;
1312
1313 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1314 0, digest, 32, signature);
1315 if (ret < 0)
1316 return ret;
1317
1318 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1319 /* Compute the shared secret key sent by the server and initialize
1320 * the RC4 encryption. */
1321 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1322 tosend + 1, type)) < 0)
1323 return ret;
1324
1325 /* Encrypt the signature received by the server. */
1326 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1327 }
1328
1329 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1330 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1331 return AVERROR(EIO);
1332 }
1333
1334 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1335 tosend[i] = av_lfg_get(&rnd) >> 24;
1336 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1337 rtmp_player_key, sizeof(rtmp_player_key),
1338 digest);
1339 if (ret < 0)
1340 return ret;
1341
1342 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1343 digest, 32,
1344 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1345 if (ret < 0)
1346 return ret;
1347
1348 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1349 /* Encrypt the signature to be send to the server. */
1350 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1351 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1352 serverdata[0]);
1353 }
1354
1355 // write reply back to the server
1356 if ((ret = ffurl_write(rt->stream, tosend,
1357 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1358 return ret;
1359
1360 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1361 /* Set RC4 keys for encryption and update the keystreams. */
1362 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1363 return ret;
1364 }
1365 } else {
1366 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1367 /* Compute the shared secret key sent by the server and initialize
1368 * the RC4 encryption. */
1369 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1370 tosend + 1, 1)) < 0)
1371 return ret;
1372
1373 if (serverdata[0] == 9) {
1374 /* Encrypt the signature received by the server. */
1375 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1376 serverdata[0]);
1377 }
1378 }
1379
1380 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1381 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1382 return ret;
1383
1384 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1385 /* Set RC4 keys for encryption and update the keystreams. */
1386 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1387 return ret;
1388 }
1389 }
1390
1391 return 0;
1392}
1393
1394static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1395 uint32_t *second_int, char *arraydata,
1396 int size)
1397{
1398 int inoutsize;
1399
1400 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1401 RTMP_HANDSHAKE_PACKET_SIZE);
1402 if (inoutsize <= 0)
1403 return AVERROR(EIO);
1404 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1405 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1406 " not following standard\n", (int)inoutsize);
1407 return AVERROR(EINVAL);
1408 }
1409
1410 *first_int = AV_RB32(arraydata);
1411 *second_int = AV_RB32(arraydata + 4);
1412 return 0;
1413}
1414
1415static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1416 uint32_t second_int, char *arraydata, int size)
1417{
1418 int inoutsize;
1419
1420 AV_WB32(arraydata, first_int);
1421 AV_WB32(arraydata + 4, second_int);
1422 inoutsize = ffurl_write(rt->stream, arraydata,
1423 RTMP_HANDSHAKE_PACKET_SIZE);
1424 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1425 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1426 return AVERROR(EIO);
1427 }
1428
1429 return 0;
1430}
1431
1432/**
1433 * rtmp handshake server side
1434 */
1435static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1436{
1437 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1438 uint32_t hs_epoch;
1439 uint32_t hs_my_epoch;
1440 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1441 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1442 uint32_t zeroes;
1443 uint32_t temp = 0;
1444 int randomidx = 0;
1445 int inoutsize = 0;
1446 int ret;
1447
1448 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1449 if (inoutsize <= 0) {
1450 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1451 return AVERROR(EIO);
1452 }
1453 // Check Version
1454 if (buffer[0] != 3) {
1455 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1456 return AVERROR(EIO);
1457 }
1458 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1459 av_log(s, AV_LOG_ERROR,
1460 "Unable to write answer - RTMP S0\n");
1461 return AVERROR(EIO);
1462 }
1463 /* Receive C1 */
1464 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1465 RTMP_HANDSHAKE_PACKET_SIZE);
1466 if (ret) {
1467 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1468 return ret;
1469 }
1470 /* Send S1 */
1471 /* By now same epoch will be sent */
1472 hs_my_epoch = hs_epoch;
1473 /* Generate random */
1474 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1475 randomidx += 4)
1476 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1477
1478 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1479 RTMP_HANDSHAKE_PACKET_SIZE);
1480 if (ret) {
1481 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1482 return ret;
1483 }
1484 /* Send S2 */
1485 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1486 RTMP_HANDSHAKE_PACKET_SIZE);
1487 if (ret) {
1488 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1489 return ret;
1490 }
1491 /* Receive C2 */
1492 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1493 RTMP_HANDSHAKE_PACKET_SIZE);
1494 if (ret) {
1495 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1496 return ret;
1497 }
1498 if (temp != hs_my_epoch)
1499 av_log(s, AV_LOG_WARNING,
1500 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1501 if (memcmp(buffer + 8, hs_s1 + 8,
1502 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1503 av_log(s, AV_LOG_WARNING,
1504 "Erroneous C2 Message random does not match up\n");
1505
1506 return 0;
1507}
1508
1509static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1510{
1511 RTMPContext *rt = s->priv_data;
1512 int ret;
1513
1514 if (pkt->size < 4) {
1515 av_log(s, AV_LOG_ERROR,
1516 "Too short chunk size change packet (%d)\n",
1517 pkt->size);
1518 return AVERROR_INVALIDDATA;
1519 }
1520
1521 if (!rt->is_input) {
1522 /* Send the same chunk size change packet back to the server,
1523 * setting the outgoing chunk size to the same as the incoming one. */
1524 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1525 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1526 return ret;
1527 rt->out_chunk_size = AV_RB32(pkt->data);
1528 }
1529
1530 rt->in_chunk_size = AV_RB32(pkt->data);
1531 if (rt->in_chunk_size <= 0) {
1532 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1533 rt->in_chunk_size);
1534 return AVERROR_INVALIDDATA;
1535 }
1536 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1537 rt->in_chunk_size);
1538
1539 return 0;
1540}
1541
1542static int handle_ping(URLContext *s, RTMPPacket *pkt)
1543{
1544 RTMPContext *rt = s->priv_data;
1545 int t, ret;
1546
1547 if (pkt->size < 2) {
1548 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1549 pkt->size);
1550 return AVERROR_INVALIDDATA;
1551 }
1552
1553 t = AV_RB16(pkt->data);
1554 if (t == 6) {
1555 if ((ret = gen_pong(s, rt, pkt)) < 0)
1556 return ret;
1557 } else if (t == 26) {
1558 if (rt->swfsize) {
1559 if ((ret = gen_swf_verification(s, rt)) < 0)
1560 return ret;
1561 } else {
1562 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1563 }
1564 }
1565
1566 return 0;
1567}
1568
1569static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1570{
1571 RTMPContext *rt = s->priv_data;
1572
1573 if (pkt->size < 4) {
1574 av_log(s, AV_LOG_ERROR,
1575 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1576 pkt->size);
1577 return AVERROR_INVALIDDATA;
1578 }
1579
1580 rt->client_report_size = AV_RB32(pkt->data);
1581 if (rt->client_report_size <= 0) {
1582 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1583 rt->client_report_size);
1584 return AVERROR_INVALIDDATA;
1585
1586 }
1587 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1588 rt->client_report_size >>= 1;
1589
1590 return 0;
1591}
1592
1593static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1594{
1595 RTMPContext *rt = s->priv_data;
1596
1597 if (pkt->size < 4) {
1598 av_log(s, AV_LOG_ERROR,
1599 "Too short server bandwidth report packet (%d)\n",
1600 pkt->size);
1601 return AVERROR_INVALIDDATA;
1602 }
1603
1604 rt->server_bw = AV_RB32(pkt->data);
1605 if (rt->server_bw <= 0) {
1606 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1607 rt->server_bw);
1608 return AVERROR_INVALIDDATA;
1609 }
1610 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1611
1612 return 0;
1613}
1614
1615static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1616 const char *opaque, const char *challenge)
1617{
1618 uint8_t hash[16];
1619 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1620 struct AVMD5 *md5 = av_md5_alloc();
1621 if (!md5)
1622 return AVERROR(ENOMEM);
1623
1624 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1625
1626 av_md5_init(md5);
1627 av_md5_update(md5, user, strlen(user));
1628 av_md5_update(md5, salt, strlen(salt));
1629 av_md5_update(md5, rt->password, strlen(rt->password));
1630 av_md5_final(md5, hash);
1631 av_base64_encode(hashstr, sizeof(hashstr), hash,
1632 sizeof(hash));
1633 av_md5_init(md5);
1634 av_md5_update(md5, hashstr, strlen(hashstr));
1635 if (opaque)
1636 av_md5_update(md5, opaque, strlen(opaque));
1637 else if (challenge)
1638 av_md5_update(md5, challenge, strlen(challenge));
1639 av_md5_update(md5, challenge2, strlen(challenge2));
1640 av_md5_final(md5, hash);
1641 av_base64_encode(hashstr, sizeof(hashstr), hash,
1642 sizeof(hash));
1643 snprintf(rt->auth_params, sizeof(rt->auth_params),
1644 "?authmod=%s&user=%s&challenge=%s&response=%s",
1645 "adobe", user, challenge2, hashstr);
1646 if (opaque)
1647 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1648 "&opaque=%s", opaque);
1649
1650 av_free(md5);
1651 return 0;
1652}
1653
1654static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1655{
1656 uint8_t hash[16];
1657 char hashstr1[33], hashstr2[33];
1658 const char *realm = "live";
1659 const char *method = "publish";
1660 const char *qop = "auth";
1661 const char *nc = "00000001";
1662 char cnonce[10];
1663 struct AVMD5 *md5 = av_md5_alloc();
1664 if (!md5)
1665 return AVERROR(ENOMEM);
1666
1667 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1668
1669 av_md5_init(md5);
1670 av_md5_update(md5, user, strlen(user));
1671 av_md5_update(md5, ":", 1);
1672 av_md5_update(md5, realm, strlen(realm));
1673 av_md5_update(md5, ":", 1);
1674 av_md5_update(md5, rt->password, strlen(rt->password));
1675 av_md5_final(md5, hash);
1676 ff_data_to_hex(hashstr1, hash, 16, 1);
1677 hashstr1[32] = '\0';
1678
1679 av_md5_init(md5);
1680 av_md5_update(md5, method, strlen(method));
1681 av_md5_update(md5, ":/", 2);
1682 av_md5_update(md5, rt->app, strlen(rt->app));
1683 if (!strchr(rt->app, '/'))
1684 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1685 av_md5_final(md5, hash);
1686 ff_data_to_hex(hashstr2, hash, 16, 1);
1687 hashstr2[32] = '\0';
1688
1689 av_md5_init(md5);
1690 av_md5_update(md5, hashstr1, strlen(hashstr1));
1691 av_md5_update(md5, ":", 1);
1692 if (nonce)
1693 av_md5_update(md5, nonce, strlen(nonce));
1694 av_md5_update(md5, ":", 1);
1695 av_md5_update(md5, nc, strlen(nc));
1696 av_md5_update(md5, ":", 1);
1697 av_md5_update(md5, cnonce, strlen(cnonce));
1698 av_md5_update(md5, ":", 1);
1699 av_md5_update(md5, qop, strlen(qop));
1700 av_md5_update(md5, ":", 1);
1701 av_md5_update(md5, hashstr2, strlen(hashstr2));
1702 av_md5_final(md5, hash);
1703 ff_data_to_hex(hashstr1, hash, 16, 1);
1704
1705 snprintf(rt->auth_params, sizeof(rt->auth_params),
1706 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1707 "llnw", user, nonce, cnonce, nc, hashstr1);
1708
1709 av_free(md5);
1710 return 0;
1711}
1712
1713static int handle_connect_error(URLContext *s, const char *desc)
1714{
1715 RTMPContext *rt = s->priv_data;
1716 char buf[300], *ptr, authmod[15];
1717 int i = 0, ret = 0;
1718 const char *user = "", *salt = "", *opaque = NULL,
1719 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1720
1721 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1722 !(cptr = strstr(desc, "authmod=llnw"))) {
1723 av_log(s, AV_LOG_ERROR,
1724 "Unknown connect error (unsupported authentication method?)\n");
1725 return AVERROR_UNKNOWN;
1726 }
1727 cptr += strlen("authmod=");
1728 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1729 authmod[i++] = *cptr++;
1730 authmod[i] = '\0';
1731
1732 if (!rt->username[0] || !rt->password[0]) {
1733 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1734 return AVERROR_UNKNOWN;
1735 }
1736
1737 if (strstr(desc, "?reason=authfailed")) {
1738 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1739 return AVERROR_UNKNOWN;
1740 } else if (strstr(desc, "?reason=nosuchuser")) {
1741 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1742 return AVERROR_UNKNOWN;
1743 }
1744
1745 if (rt->auth_tried) {
1746 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1747 return AVERROR_UNKNOWN;
1748 }
1749
1750 rt->auth_params[0] = '\0';
1751
1752 if (strstr(desc, "code=403 need auth")) {
1753 snprintf(rt->auth_params, sizeof(rt->auth_params),
1754 "?authmod=%s&user=%s", authmod, rt->username);
1755 return 0;
1756 }
1757
1758 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1759 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1760 return AVERROR_UNKNOWN;
1761 }
1762
1763 av_strlcpy(buf, cptr + 1, sizeof(buf));
1764 ptr = buf;
1765
1766 while (ptr) {
1767 char *next = strchr(ptr, '&');
1768 char *value = strchr(ptr, '=');
1769 if (next)
1770 *next++ = '\0';
1771 if (value) {
1772 *value++ = '\0';
1773 if (!strcmp(ptr, "user")) {
1774 user = value;
1775 } else if (!strcmp(ptr, "salt")) {
1776 salt = value;
1777 } else if (!strcmp(ptr, "opaque")) {
1778 opaque = value;
1779 } else if (!strcmp(ptr, "challenge")) {
1780 challenge = value;
1781 } else if (!strcmp(ptr, "nonce")) {
1782 nonce = value;
1783 } else {
1784 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1785 }
1786 } else {
1787 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1788 }
1789 ptr = next;
1790 }
1791
1792 if (!strcmp(authmod, "adobe")) {
1793 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1794 return ret;
1795 } else {
1796 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1797 return ret;
1798 }
1799
1800 rt->auth_tried = 1;
1801 return 0;
1802}
1803
1804static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1805{
1806 RTMPContext *rt = s->priv_data;
1807 const uint8_t *data_end = pkt->data + pkt->size;
1808 char *tracked_method = NULL;
1809 int level = AV_LOG_ERROR;
1810 uint8_t tmpstr[256];
1811 int ret;
1812
1813 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1814 return ret;
1815
1816 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1817 "description", tmpstr, sizeof(tmpstr))) {
1818 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1819 !strcmp(tracked_method, "releaseStream") ||
1820 !strcmp(tracked_method, "FCSubscribe") ||
1821 !strcmp(tracked_method, "FCPublish"))) {
1822 /* Gracefully ignore Adobe-specific historical artifact errors. */
1823 level = AV_LOG_WARNING;
1824 ret = 0;
f6fa7814
DM
1825 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1826 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1827 ret = 0;
2ba45a60
DM
1828 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1829 ret = handle_connect_error(s, tmpstr);
1830 if (!ret) {
1831 rt->do_reconnect = 1;
1832 level = AV_LOG_VERBOSE;
1833 }
1834 } else
1835 ret = AVERROR_UNKNOWN;
1836 av_log(s, level, "Server error: %s\n", tmpstr);
1837 }
1838
1839 av_free(tracked_method);
1840 return ret;
1841}
1842
1843static int write_begin(URLContext *s)
1844{
1845 RTMPContext *rt = s->priv_data;
1846 PutByteContext pbc;
1847 RTMPPacket spkt = { 0 };
1848 int ret;
1849
1850 // Send Stream Begin 1
1851 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1852 RTMP_PT_PING, 0, 6)) < 0) {
1853 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1854 return ret;
1855 }
1856
1857 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1858 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1859 bytestream2_put_be32(&pbc, rt->nb_streamid);
1860
1861 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1862 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1863
1864 ff_rtmp_packet_destroy(&spkt);
1865
1866 return ret;
1867}
1868
1869static int write_status(URLContext *s, RTMPPacket *pkt,
1870 const char *status, const char *filename)
1871{
1872 RTMPContext *rt = s->priv_data;
1873 RTMPPacket spkt = { 0 };
1874 char statusmsg[128];
1875 uint8_t *pp;
1876 int ret;
1877
1878 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1879 RTMP_PT_INVOKE, 0,
1880 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1881 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1882 return ret;
1883 }
1884
1885 pp = spkt.data;
1886 spkt.extra = pkt->extra;
1887 ff_amf_write_string(&pp, "onStatus");
1888 ff_amf_write_number(&pp, 0);
1889 ff_amf_write_null(&pp);
1890
1891 ff_amf_write_object_start(&pp);
1892 ff_amf_write_field_name(&pp, "level");
1893 ff_amf_write_string(&pp, "status");
1894 ff_amf_write_field_name(&pp, "code");
1895 ff_amf_write_string(&pp, status);
1896 ff_amf_write_field_name(&pp, "description");
1897 snprintf(statusmsg, sizeof(statusmsg),
1898 "%s is now published", filename);
1899 ff_amf_write_string(&pp, statusmsg);
1900 ff_amf_write_field_name(&pp, "details");
1901 ff_amf_write_string(&pp, filename);
1902 ff_amf_write_field_name(&pp, "clientid");
1903 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1904 ff_amf_write_string(&pp, statusmsg);
1905 ff_amf_write_object_end(&pp);
1906
1907 spkt.size = pp - spkt.data;
1908 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1909 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1910 ff_rtmp_packet_destroy(&spkt);
1911
1912 return ret;
1913}
1914
1915static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1916{
1917 RTMPContext *rt = s->priv_data;
1918 double seqnum;
1919 char filename[64];
1920 char command[64];
1921 int stringlen;
1922 char *pchar;
1923 const uint8_t *p = pkt->data;
1924 uint8_t *pp = NULL;
1925 RTMPPacket spkt = { 0 };
1926 GetByteContext gbc;
1927 int ret;
1928
1929 bytestream2_init(&gbc, p, pkt->size);
1930 if (ff_amf_read_string(&gbc, command, sizeof(command),
1931 &stringlen)) {
1932 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1933 return AVERROR_INVALIDDATA;
1934 }
1935
1936 ret = ff_amf_read_number(&gbc, &seqnum);
1937 if (ret)
1938 return ret;
1939 ret = ff_amf_read_null(&gbc);
1940 if (ret)
1941 return ret;
1942 if (!strcmp(command, "FCPublish") ||
1943 !strcmp(command, "publish")) {
1944 ret = ff_amf_read_string(&gbc, filename,
1945 sizeof(filename), &stringlen);
1946 // check with url
1947 if (s->filename) {
1948 pchar = strrchr(s->filename, '/');
1949 if (!pchar) {
1950 av_log(s, AV_LOG_WARNING,
1951 "Unable to find / in url %s, bad format\n",
1952 s->filename);
1953 pchar = s->filename;
1954 }
1955 pchar++;
1956 if (strcmp(pchar, filename))
1957 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1958 " %s\n", filename, pchar);
1959 }
1960 rt->state = STATE_RECEIVING;
1961 }
1962
1963 if (!strcmp(command, "FCPublish")) {
1964 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1965 RTMP_PT_INVOKE, 0,
1966 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1967 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1968 return ret;
1969 }
1970 pp = spkt.data;
1971 ff_amf_write_string(&pp, "onFCPublish");
1972 } else if (!strcmp(command, "publish")) {
1973 ret = write_begin(s);
1974 if (ret < 0)
1975 return ret;
1976
1977 // Send onStatus(NetStream.Publish.Start)
1978 return write_status(s, pkt, "NetStream.Publish.Start",
1979 filename);
1980 } else if (!strcmp(command, "play")) {
1981 ret = write_begin(s);
1982 if (ret < 0)
1983 return ret;
1984 rt->state = STATE_SENDING;
1985 return write_status(s, pkt, "NetStream.Play.Start",
1986 filename);
1987 } else {
1988 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1989 RTMP_PT_INVOKE, 0,
1990 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1991 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1992 return ret;
1993 }
1994 pp = spkt.data;
1995 ff_amf_write_string(&pp, "_result");
1996 ff_amf_write_number(&pp, seqnum);
1997 ff_amf_write_null(&pp);
1998 if (!strcmp(command, "createStream")) {
1999 rt->nb_streamid++;
2000 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2001 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2002 ff_amf_write_number(&pp, rt->nb_streamid);
2003 /* By now we don't control which streams are removed in
2004 * deleteStream. There is no stream creation control
2005 * if a client creates more than 2^32 - 2 streams. */
2006 }
2007 }
2008 spkt.size = pp - spkt.data;
2009 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2010 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2011 ff_rtmp_packet_destroy(&spkt);
2012 return ret;
2013}
2014
f6fa7814
DM
2015/**
2016 * Read the AMF_NUMBER response ("_result") to a function call
2017 * (e.g. createStream()). This response should be made up of the AMF_STRING
2018 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2019 * successful response, we will return set the value to number (otherwise number
2020 * will not be changed).
2021 *
2022 * @return 0 if reading the value succeeds, negative value otherwiss
2023 */
2024static int read_number_result(RTMPPacket *pkt, double *number)
2025{
2026 // We only need to fit "_result" in this.
2027 uint8_t strbuffer[8];
2028 int stringlen;
2029 double numbuffer;
2030 GetByteContext gbc;
2031
2032 bytestream2_init(&gbc, pkt->data, pkt->size);
2033
2034 // Value 1/4: "_result" as AMF_STRING
2035 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2036 return AVERROR_INVALIDDATA;
2037 if (strcmp(strbuffer, "_result"))
2038 return AVERROR_INVALIDDATA;
2039 // Value 2/4: The callee reference number
2040 if (ff_amf_read_number(&gbc, &numbuffer))
2041 return AVERROR_INVALIDDATA;
2042 // Value 3/4: Null
2043 if (ff_amf_read_null(&gbc))
2044 return AVERROR_INVALIDDATA;
2045 // Value 4/4: The resonse as AMF_NUMBER
2046 if (ff_amf_read_number(&gbc, &numbuffer))
2047 return AVERROR_INVALIDDATA;
2048 else
2049 *number = numbuffer;
2050
2051 return 0;
2052}
2053
2ba45a60
DM
2054static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2055{
2056 RTMPContext *rt = s->priv_data;
2057 char *tracked_method = NULL;
2058 int ret = 0;
2059
2060 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2061 return ret;
2062
2063 if (!tracked_method) {
2064 /* Ignore this reply when the current method is not tracked. */
2065 return ret;
2066 }
2067
2068 if (!strcmp(tracked_method, "connect")) {
2069 if (!rt->is_input) {
2070 if ((ret = gen_release_stream(s, rt)) < 0)
2071 goto fail;
2072
2073 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2074 goto fail;
2075 } else {
2076 if ((ret = gen_server_bw(s, rt)) < 0)
2077 goto fail;
2078 }
2079
2080 if ((ret = gen_create_stream(s, rt)) < 0)
2081 goto fail;
2082
2083 if (rt->is_input) {
2084 /* Send the FCSubscribe command when the name of live
2085 * stream is defined by the user or if it's a live stream. */
2086 if (rt->subscribe) {
2087 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2088 goto fail;
2089 } else if (rt->live == -1) {
2090 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2091 goto fail;
2092 }
2093 }
2094 } else if (!strcmp(tracked_method, "createStream")) {
f6fa7814
DM
2095 double stream_id;
2096 if (read_number_result(pkt, &stream_id)) {
2ba45a60
DM
2097 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2098 } else {
f6fa7814 2099 rt->stream_id = stream_id;
2ba45a60
DM
2100 }
2101
2102 if (!rt->is_input) {
2103 if ((ret = gen_publish(s, rt)) < 0)
2104 goto fail;
2105 } else {
f6fa7814
DM
2106 if (rt->live != -1) {
2107 if ((ret = gen_get_stream_length(s, rt)) < 0)
2108 goto fail;
2109 }
2ba45a60
DM
2110 if ((ret = gen_play(s, rt)) < 0)
2111 goto fail;
2112 if ((ret = gen_buffer_time(s, rt)) < 0)
2113 goto fail;
2114 }
f6fa7814
DM
2115 } else if (!strcmp(tracked_method, "getStreamLength")) {
2116 if (read_number_result(pkt, &rt->duration)) {
2117 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2118 }
2ba45a60
DM
2119 }
2120
2121fail:
2122 av_free(tracked_method);
2123 return ret;
2124}
2125
2126static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2127{
2128 RTMPContext *rt = s->priv_data;
2129 const uint8_t *data_end = pkt->data + pkt->size;
2130 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2131 uint8_t tmpstr[256];
2132 int i, t;
2133
2134 for (i = 0; i < 2; i++) {
2135 t = ff_amf_tag_size(ptr, data_end);
2136 if (t < 0)
2137 return 1;
2138 ptr += t;
2139 }
2140
2141 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2142 if (!t && !strcmp(tmpstr, "error")) {
2143 t = ff_amf_get_field_value(ptr, data_end,
2144 "description", tmpstr, sizeof(tmpstr));
2145 if (t || !tmpstr[0])
2146 t = ff_amf_get_field_value(ptr, data_end, "code",
2147 tmpstr, sizeof(tmpstr));
2148 if (!t)
2149 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2150 return -1;
2151 }
2152
2153 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2154 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2155 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2156 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2157 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2158 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2159
2160 return 0;
2161}
2162
2163static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2164{
2165 RTMPContext *rt = s->priv_data;
2166 int ret = 0;
2167
2168 //TODO: check for the messages sent for wrong state?
2169 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2170 if ((ret = handle_invoke_error(s, pkt)) < 0)
2171 return ret;
2172 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2173 if ((ret = handle_invoke_result(s, pkt)) < 0)
2174 return ret;
2175 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2176 if ((ret = handle_invoke_status(s, pkt)) < 0)
2177 return ret;
2178 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2179 if ((ret = gen_check_bw(s, rt)) < 0)
2180 return ret;
2181 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2182 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2183 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2184 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2185 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2186 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2187 if ((ret = send_invoke_response(s, pkt)) < 0)
2188 return ret;
2189 }
2190
2191 return ret;
2192}
2193
2194static int update_offset(RTMPContext *rt, int size)
2195{
2196 int old_flv_size;
2197
2198 // generate packet header and put data into buffer for FLV demuxer
2199 if (rt->flv_off < rt->flv_size) {
2200 // There is old unread data in the buffer, thus append at the end
2201 old_flv_size = rt->flv_size;
2202 rt->flv_size += size;
2203 } else {
2204 // All data has been read, write the new data at the start of the buffer
2205 old_flv_size = 0;
2206 rt->flv_size = size;
2207 rt->flv_off = 0;
2208 }
2209
2210 return old_flv_size;
2211}
2212
2213static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2214{
2215 int old_flv_size, ret;
2216 PutByteContext pbc;
2217 const uint8_t *data = pkt->data + skip;
2218 const int size = pkt->size - skip;
2219 uint32_t ts = pkt->timestamp;
2220
2221 if (pkt->type == RTMP_PT_AUDIO) {
2222 rt->has_audio = 1;
2223 } else if (pkt->type == RTMP_PT_VIDEO) {
2224 rt->has_video = 1;
2225 }
2226
2227 old_flv_size = update_offset(rt, size + 15);
2228
2229 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2230 rt->flv_size = rt->flv_off = 0;
2231 return ret;
2232 }
2233 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2234 bytestream2_skip_p(&pbc, old_flv_size);
2235 bytestream2_put_byte(&pbc, pkt->type);
2236 bytestream2_put_be24(&pbc, size);
2237 bytestream2_put_be24(&pbc, ts);
2238 bytestream2_put_byte(&pbc, ts >> 24);
2239 bytestream2_put_be24(&pbc, 0);
2240 bytestream2_put_buffer(&pbc, data, size);
2241 bytestream2_put_be32(&pbc, 0);
2242
2243 return 0;
2244}
2245
2246static int handle_notify(URLContext *s, RTMPPacket *pkt)
2247{
2248 RTMPContext *rt = s->priv_data;
2249 uint8_t commandbuffer[64];
2250 char statusmsg[128];
2251 int stringlen, ret, skip = 0;
2252 GetByteContext gbc;
2253
2254 bytestream2_init(&gbc, pkt->data, pkt->size);
2255 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2256 &stringlen))
2257 return AVERROR_INVALIDDATA;
2258
2259 if (!strcmp(commandbuffer, "onMetaData")) {
2260 // metadata properties should be stored in a mixed array
2261 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2262 // We have found a metaData Array so flv can determine the streams
2263 // from this.
2264 rt->received_metadata = 1;
2265 // skip 32-bit max array index
2266 bytestream2_skip(&gbc, 4);
2267 while (bytestream2_get_bytes_left(&gbc) > 3) {
2268 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2269 &stringlen))
2270 return AVERROR_INVALIDDATA;
2271 // We do not care about the content of the property (yet).
2272 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2273 if (stringlen < 0)
2274 return AVERROR_INVALIDDATA;
2275 bytestream2_skip(&gbc, stringlen);
2276
2277 // The presence of the following properties indicates that the
2278 // respective streams are present.
2279 if (!strcmp(statusmsg, "videocodecid")) {
2280 rt->has_video = 1;
2281 }
2282 if (!strcmp(statusmsg, "audiocodecid")) {
2283 rt->has_audio = 1;
2284 }
2285 }
2286 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2287 return AVERROR_INVALIDDATA;
2288 }
2289 }
2290
2291 // Skip the @setDataFrame string and validate it is a notification
2292 if (!strcmp(commandbuffer, "@setDataFrame")) {
2293 skip = gbc.buffer - pkt->data;
2294 ret = ff_amf_read_string(&gbc, statusmsg,
2295 sizeof(statusmsg), &stringlen);
2296 if (ret < 0)
2297 return AVERROR_INVALIDDATA;
2298 }
2299
2300 return append_flv_data(rt, pkt, skip);
2301}
2302
2303/**
2304 * Parse received packet and possibly perform some action depending on
2305 * the packet contents.
2306 * @return 0 for no errors, negative values for serious errors which prevent
2307 * further communications, positive values for uncritical errors
2308 */
2309static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2310{
2311 int ret;
2312
2313#ifdef DEBUG
2314 ff_rtmp_packet_dump(s, pkt);
2315#endif
2316
2317 switch (pkt->type) {
2318 case RTMP_PT_BYTES_READ:
2319 av_dlog(s, "received bytes read report\n");
2320 break;
2321 case RTMP_PT_CHUNK_SIZE:
2322 if ((ret = handle_chunk_size(s, pkt)) < 0)
2323 return ret;
2324 break;
2325 case RTMP_PT_PING:
2326 if ((ret = handle_ping(s, pkt)) < 0)
2327 return ret;
2328 break;
2329 case RTMP_PT_CLIENT_BW:
2330 if ((ret = handle_client_bw(s, pkt)) < 0)
2331 return ret;
2332 break;
2333 case RTMP_PT_SERVER_BW:
2334 if ((ret = handle_server_bw(s, pkt)) < 0)
2335 return ret;
2336 break;
2337 case RTMP_PT_INVOKE:
2338 if ((ret = handle_invoke(s, pkt)) < 0)
2339 return ret;
2340 break;
2341 case RTMP_PT_VIDEO:
2342 case RTMP_PT_AUDIO:
2343 case RTMP_PT_METADATA:
2344 case RTMP_PT_NOTIFY:
2345 /* Audio, Video and Metadata packets are parsed in get_packet() */
2346 break;
2347 default:
2348 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2349 break;
2350 }
2351 return 0;
2352}
2353
2354static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2355{
2356 int ret, old_flv_size, type;
2357 const uint8_t *next;
2358 uint8_t *p;
2359 uint32_t size;
2360 uint32_t ts, cts, pts = 0;
2361
2362 old_flv_size = update_offset(rt, pkt->size);
2363
2364 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2365 rt->flv_size = rt->flv_off = 0;
2366 return ret;
2367 }
2368
2369 next = pkt->data;
2370 p = rt->flv_data + old_flv_size;
2371
2372 /* copy data while rewriting timestamps */
2373 ts = pkt->timestamp;
2374
2375 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2376 type = bytestream_get_byte(&next);
2377 size = bytestream_get_be24(&next);
2378 cts = bytestream_get_be24(&next);
2379 cts |= bytestream_get_byte(&next) << 24;
2380 if (!pts)
2381 pts = cts;
2382 ts += cts - pts;
2383 pts = cts;
2384 if (size + 3 + 4 > pkt->data + pkt->size - next)
2385 break;
2386 bytestream_put_byte(&p, type);
2387 bytestream_put_be24(&p, size);
2388 bytestream_put_be24(&p, ts);
2389 bytestream_put_byte(&p, ts >> 24);
2390 memcpy(p, next, size + 3 + 4);
2391 next += size + 3 + 4;
2392 p += size + 3 + 4;
2393 }
2394 if (p != rt->flv_data + rt->flv_size) {
2395 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2396 "RTMP_PT_METADATA packet\n");
2397 rt->flv_size = p - rt->flv_data;
2398 }
2399
2400 return 0;
2401}
2402
2403/**
2404 * Interact with the server by receiving and sending RTMP packets until
2405 * there is some significant data (media data or expected status notification).
2406 *
2407 * @param s reading context
2408 * @param for_header non-zero value tells function to work until it
2409 * gets notification from the server that playing has been started,
2410 * otherwise function will work until some media data is received (or
2411 * an error happens)
2412 * @return 0 for successful operation, negative value in case of error
2413 */
2414static int get_packet(URLContext *s, int for_header)
2415{
2416 RTMPContext *rt = s->priv_data;
2417 int ret;
2418
2419 if (rt->state == STATE_STOPPED)
2420 return AVERROR_EOF;
2421
2422 for (;;) {
2423 RTMPPacket rpkt = { 0 };
2424 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2425 rt->in_chunk_size, &rt->prev_pkt[0],
2426 &rt->nb_prev_pkt[0])) <= 0) {
2427 if (ret == 0) {
2428 return AVERROR(EAGAIN);
2429 } else {
2430 return AVERROR(EIO);
2431 }
2432 }
f6fa7814
DM
2433
2434 // Track timestamp for later use
2435 rt->last_timestamp = rpkt.timestamp;
2436
2ba45a60
DM
2437 rt->bytes_read += ret;
2438 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2439 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2440 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2441 return ret;
2442 rt->last_bytes_read = rt->bytes_read;
2443 }
2444
2445 ret = rtmp_parse_result(s, rt, &rpkt);
2446
2447 // At this point we must check if we are in the seek state and continue
2448 // with the next packet. handle_invoke will get us out of this state
2449 // when the right message is encountered
2450 if (rt->state == STATE_SEEKING) {
2451 ff_rtmp_packet_destroy(&rpkt);
2452 // We continue, let the natural flow of things happen:
2453 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2454 continue;
2455 }
2456
2457 if (ret < 0) {//serious error in current packet
2458 ff_rtmp_packet_destroy(&rpkt);
2459 return ret;
2460 }
2461 if (rt->do_reconnect && for_header) {
2462 ff_rtmp_packet_destroy(&rpkt);
2463 return 0;
2464 }
2465 if (rt->state == STATE_STOPPED) {
2466 ff_rtmp_packet_destroy(&rpkt);
2467 return AVERROR_EOF;
2468 }
2469 if (for_header && (rt->state == STATE_PLAYING ||
2470 rt->state == STATE_PUBLISHING ||
2471 rt->state == STATE_SENDING ||
2472 rt->state == STATE_RECEIVING)) {
2473 ff_rtmp_packet_destroy(&rpkt);
2474 return 0;
2475 }
2476 if (!rpkt.size || !rt->is_input) {
2477 ff_rtmp_packet_destroy(&rpkt);
2478 continue;
2479 }
2480 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2481 ret = append_flv_data(rt, &rpkt, 0);
2482 ff_rtmp_packet_destroy(&rpkt);
2483 return ret;
2484 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2485 ret = handle_notify(s, &rpkt);
2486 ff_rtmp_packet_destroy(&rpkt);
2487 return ret;
2488 } else if (rpkt.type == RTMP_PT_METADATA) {
2489 ret = handle_metadata(rt, &rpkt);
2490 ff_rtmp_packet_destroy(&rpkt);
2491 return 0;
2492 }
2493 ff_rtmp_packet_destroy(&rpkt);
2494 }
2495}
2496
2497static int rtmp_close(URLContext *h)
2498{
2499 RTMPContext *rt = h->priv_data;
2500 int ret = 0, i, j;
2501
2502 if (!rt->is_input) {
2503 rt->flv_data = NULL;
2504 if (rt->out_pkt.size)
2505 ff_rtmp_packet_destroy(&rt->out_pkt);
2506 if (rt->state > STATE_FCPUBLISH)
2507 ret = gen_fcunpublish_stream(h, rt);
2508 }
2509 if (rt->state > STATE_HANDSHAKED)
2510 ret = gen_delete_stream(h, rt);
2511 for (i = 0; i < 2; i++) {
2512 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2513 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2514 av_freep(&rt->prev_pkt[i]);
2515 }
2516
2517 free_tracked_methods(rt);
2518 av_freep(&rt->flv_data);
2519 ffurl_close(rt->stream);
2520 return ret;
2521}
2522
f6fa7814
DM
2523/**
2524 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2525 * demuxer about the duration of the stream.
2526 *
2527 * This should only be done if there was no real onMetadata packet sent by the
2528 * server at the start of the stream and if we were able to retrieve a valid
2529 * duration via a getStreamLength call.
2530 *
2531 * @return 0 for successful operation, negative value in case of error
2532 */
2533static int inject_fake_duration_metadata(RTMPContext *rt)
2534{
2535 // We need to insert the metdata packet directly after the FLV
2536 // header, i.e. we need to move all other already read data by the
2537 // size of our fake metadata packet.
2538
2539 uint8_t* p;
2540 // Keep old flv_data pointer
2541 uint8_t* old_flv_data = rt->flv_data;
2542 // Allocate a new flv_data pointer with enough space for the additional package
2543 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2544 rt->flv_data = old_flv_data;
2545 return AVERROR(ENOMEM);
2546 }
2547
2548 // Copy FLV header
2549 memcpy(rt->flv_data, old_flv_data, 13);
2550 // Copy remaining packets
2551 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2552 // Increase the size by the injected packet
2553 rt->flv_size += 55;
2554 // Delete the old FLV data
2555 av_free(old_flv_data);
2556
2557 p = rt->flv_data + 13;
2558 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2559 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2560 bytestream_put_be24(&p, 0); // timestamp
2561 bytestream_put_be32(&p, 0); // reserved
2562
2563 // first event name as a string
2564 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2565 // "onMetaData" as AMF string
2566 bytestream_put_be16(&p, 10);
2567 bytestream_put_buffer(&p, "onMetaData", 10);
2568
2569 // mixed array (hash) with size and string/type/data tuples
2570 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2571 bytestream_put_be32(&p, 1); // metadata_count
2572
2573 // "duration" as AMF string
2574 bytestream_put_be16(&p, 8);
2575 bytestream_put_buffer(&p, "duration", 8);
2576 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2577 bytestream_put_be64(&p, av_double2int(rt->duration));
2578
2579 // Finalise object
2580 bytestream_put_be16(&p, 0); // Empty string
2581 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2582 bytestream_put_be32(&p, 40); // size of data part (sum of all parts below)
2583
2584 return 0;
2585}
2586
2ba45a60
DM
2587/**
2588 * Open RTMP connection and verify that the stream can be played.
2589 *
2590 * URL syntax: rtmp://server[:port][/app][/playpath]
2591 * where 'app' is first one or two directories in the path
2592 * (e.g. /ondemand/, /flash/live/, etc.)
2593 * and 'playpath' is a file name (the rest of the path,
2594 * may be prefixed with "mp4:")
2595 */
2596static int rtmp_open(URLContext *s, const char *uri, int flags)
2597{
2598 RTMPContext *rt = s->priv_data;
2599 char proto[8], hostname[256], path[1024], auth[100], *fname;
f6fa7814 2600 char *old_app, *qmark, *n, fname_buffer[1024];
2ba45a60
DM
2601 uint8_t buf[2048];
2602 int port;
2603 AVDictionary *opts = NULL;
2604 int ret;
2605
2606 if (rt->listen_timeout > 0)
2607 rt->listen = 1;
2608
2609 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2610
2611 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2612 hostname, sizeof(hostname), &port,
2613 path, sizeof(path), s->filename);
2614
f6fa7814
DM
2615 n = strchr(path, ' ');
2616 if (n) {
2ba45a60
DM
2617 av_log(s, AV_LOG_WARNING,
2618 "Detected librtmp style URL parameters, these aren't supported "
2619 "by the libavformat internal RTMP handler currently enabled. "
2620 "See the documentation for the correct way to pass parameters.\n");
f6fa7814 2621 *n = '\0'; // Trim not supported part
2ba45a60
DM
2622 }
2623
2624 if (auth[0]) {
2625 char *ptr = strchr(auth, ':');
2626 if (ptr) {
2627 *ptr = '\0';
2628 av_strlcpy(rt->username, auth, sizeof(rt->username));
2629 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2630 }
2631 }
2632
2633 if (rt->listen && strcmp(proto, "rtmp")) {
2634 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2635 proto);
2636 return AVERROR(EINVAL);
2637 }
2638 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2639 if (!strcmp(proto, "rtmpts"))
2640 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2641
2642 /* open the http tunneling connection */
2643 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2644 } else if (!strcmp(proto, "rtmps")) {
2645 /* open the tls connection */
2646 if (port < 0)
2647 port = RTMPS_DEFAULT_PORT;
2648 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2649 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2650 if (!strcmp(proto, "rtmpte"))
2651 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2652
2653 /* open the encrypted connection */
2654 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2655 rt->encrypted = 1;
2656 } else {
2657 /* open the tcp connection */
2658 if (port < 0)
2659 port = RTMP_DEFAULT_PORT;
2660 if (rt->listen)
2661 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2662 "?listen&listen_timeout=%d",
2663 rt->listen_timeout * 1000);
2664 else
2665 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2666 }
2667
2668reconnect:
2669 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2670 &s->interrupt_callback, &opts)) < 0) {
2671 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2672 goto fail;
2673 }
2674
2675 if (rt->swfverify) {
2676 if ((ret = rtmp_calc_swfhash(s)) < 0)
2677 goto fail;
2678 }
2679
2680 rt->state = STATE_START;
2681 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2682 goto fail;
2683 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2684 goto fail;
2685
2686 rt->out_chunk_size = 128;
2687 rt->in_chunk_size = 128; // Probably overwritten later
2688 rt->state = STATE_HANDSHAKED;
2689
2690 // Keep the application name when it has been defined by the user.
2691 old_app = rt->app;
2692
2693 rt->app = av_malloc(APP_MAX_LENGTH);
2694 if (!rt->app) {
2695 ret = AVERROR(ENOMEM);
2696 goto fail;
2697 }
2698
2699 //extract "app" part from path
2700 qmark = strchr(path, '?');
2701 if (qmark && strstr(qmark, "slist=")) {
2702 char* amp;
2703 // After slist we have the playpath, before the params, the app
2704 av_strlcpy(rt->app, path + 1, FFMIN(qmark - path, APP_MAX_LENGTH));
2705 fname = strstr(path, "slist=") + 6;
2706 // Strip any further query parameters from fname
2707 amp = strchr(fname, '&');
2708 if (amp) {
2709 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2710 sizeof(fname_buffer)));
2711 fname = fname_buffer;
2712 }
2713 } else if (!strncmp(path, "/ondemand/", 10)) {
2714 fname = path + 10;
2715 memcpy(rt->app, "ondemand", 9);
2716 } else {
2717 char *next = *path ? path + 1 : path;
2718 char *p = strchr(next, '/');
2719 if (!p) {
f6fa7814
DM
2720 if (old_app) {
2721 // If name of application has been defined by the user, assume that
2722 // playpath is provided in the URL
2723 fname = next;
2724 } else {
2725 fname = NULL;
2726 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2727 }
2ba45a60
DM
2728 } else {
2729 // make sure we do not mismatch a playpath for an application instance
2730 char *c = strchr(p + 1, ':');
2731 fname = strchr(p + 1, '/');
2732 if (!fname || (c && c < fname)) {
2733 fname = p + 1;
2734 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2735 } else {
2736 fname++;
2737 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2738 }
2739 }
2740 }
2741
2742 if (old_app) {
2743 // The name of application has been defined by the user, override it.
2744 if (strlen(old_app) >= APP_MAX_LENGTH) {
2745 ret = AVERROR(EINVAL);
2746 goto fail;
2747 }
2748 av_free(rt->app);
2749 rt->app = old_app;
2750 }
2751
2752 if (!rt->playpath) {
2ba45a60
DM
2753 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2754 if (!rt->playpath) {
2755 ret = AVERROR(ENOMEM);
2756 goto fail;
2757 }
2758
f6fa7814
DM
2759 if (fname) {
2760 int len = strlen(fname);
2761 if (!strchr(fname, ':') && len >= 4 &&
2762 (!strcmp(fname + len - 4, ".f4v") ||
2763 !strcmp(fname + len - 4, ".mp4"))) {
2764 memcpy(rt->playpath, "mp4:", 5);
2765 } else {
2766 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2767 fname[len - 4] = '\0';
2768 rt->playpath[0] = 0;
2769 }
2770 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2ba45a60 2771 } else {
f6fa7814 2772 rt->playpath[0] = '\0';
2ba45a60 2773 }
2ba45a60
DM
2774 }
2775
2776 if (!rt->tcurl) {
2777 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2778 if (!rt->tcurl) {
2779 ret = AVERROR(ENOMEM);
2780 goto fail;
2781 }
2782 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2783 port, "/%s", rt->app);
2784 }
2785
2786 if (!rt->flashver) {
2787 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2788 if (!rt->flashver) {
2789 ret = AVERROR(ENOMEM);
2790 goto fail;
2791 }
2792 if (rt->is_input) {
2793 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2794 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2795 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2796 } else {
2797 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2798 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2799 }
2800 }
2801
2802 rt->client_report_size = 1048576;
2803 rt->bytes_read = 0;
2804 rt->has_audio = 0;
2805 rt->has_video = 0;
2806 rt->received_metadata = 0;
2807 rt->last_bytes_read = 0;
2808 rt->server_bw = 2500000;
f6fa7814 2809 rt->duration = 0;
2ba45a60
DM
2810
2811 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2812 proto, path, rt->app, rt->playpath);
2813 if (!rt->listen) {
2814 if ((ret = gen_connect(s, rt)) < 0)
2815 goto fail;
2816 } else {
2817 if ((ret = read_connect(s, s->priv_data)) < 0)
2818 goto fail;
2819 }
2820
2821 do {
2822 ret = get_packet(s, 1);
2823 } while (ret == AVERROR(EAGAIN));
2824 if (ret < 0)
2825 goto fail;
2826
2827 if (rt->do_reconnect) {
2828 int i;
2829 ffurl_close(rt->stream);
2830 rt->stream = NULL;
2831 rt->do_reconnect = 0;
2832 rt->nb_invokes = 0;
2833 for (i = 0; i < 2; i++)
2834 memset(rt->prev_pkt[i], 0,
2835 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2836 free_tracked_methods(rt);
2837 goto reconnect;
2838 }
2839
2840 if (rt->is_input) {
2ba45a60
DM
2841 // generate FLV header for demuxer
2842 rt->flv_size = 13;
f6fa7814
DM
2843 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2844 goto fail;
2ba45a60
DM
2845 rt->flv_off = 0;
2846 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2847
2848 // Read packets until we reach the first A/V packet or read metadata.
2849 // If there was a metadata package in front of the A/V packets, we can
2850 // build the FLV header from this. If we do not receive any metadata,
2851 // the FLV decoder will allocate the needed streams when their first
2852 // audio or video packet arrives.
2853 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2854 if ((ret = get_packet(s, 0)) < 0)
f6fa7814 2855 goto fail;
2ba45a60
DM
2856 }
2857
2858 // Either after we have read the metadata or (if there is none) the
2859 // first packet of an A/V stream, we have a better knowledge about the
2860 // streams, so set the FLV header accordingly.
2861 if (rt->has_audio) {
2862 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2863 }
2864 if (rt->has_video) {
2865 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2866 }
f6fa7814
DM
2867
2868 // If we received the first packet of an A/V stream and no metadata but
2869 // the server returned a valid duration, create a fake metadata packet
2870 // to inform the FLV decoder about the duration.
2871 if (!rt->received_metadata && rt->duration > 0) {
2872 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2873 goto fail;
2874 }
2ba45a60
DM
2875 } else {
2876 rt->flv_size = 0;
2877 rt->flv_data = NULL;
2878 rt->flv_off = 0;
2879 rt->skip_bytes = 13;
2880 }
2881
2882 s->max_packet_size = rt->stream->max_packet_size;
2883 s->is_streamed = 1;
2884 return 0;
2885
2886fail:
2887 av_dict_free(&opts);
2888 rtmp_close(s);
2889 return ret;
2890}
2891
2892static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2893{
2894 RTMPContext *rt = s->priv_data;
2895 int orig_size = size;
2896 int ret;
2897
2898 while (size > 0) {
2899 int data_left = rt->flv_size - rt->flv_off;
2900
2901 if (data_left >= size) {
2902 memcpy(buf, rt->flv_data + rt->flv_off, size);
2903 rt->flv_off += size;
2904 return orig_size;
2905 }
2906 if (data_left > 0) {
2907 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2908 buf += data_left;
2909 size -= data_left;
2910 rt->flv_off = rt->flv_size;
2911 return data_left;
2912 }
2913 if ((ret = get_packet(s, 0)) < 0)
2914 return ret;
2915 }
2916 return orig_size;
2917}
2918
2919static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2920 int flags)
2921{
2922 RTMPContext *rt = s->priv_data;
2923 int ret;
2924 av_log(s, AV_LOG_DEBUG,
2925 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2926 stream_index, timestamp, flags);
2927 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2928 av_log(s, AV_LOG_ERROR,
2929 "Unable to send seek command on stream index %d at timestamp "
2930 "%"PRId64" with flags %08x\n",
2931 stream_index, timestamp, flags);
2932 return ret;
2933 }
2934 rt->flv_off = rt->flv_size;
2935 rt->state = STATE_SEEKING;
2936 return timestamp;
2937}
2938
f6fa7814
DM
2939static int rtmp_pause(URLContext *s, int pause)
2940{
2941 RTMPContext *rt = s->priv_data;
2942 int ret;
2943 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2944 rt->last_timestamp);
2945 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2946 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2947 rt->last_timestamp);
2948 return ret;
2949 }
2950 return 0;
2951}
2952
2ba45a60
DM
2953static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2954{
2955 RTMPContext *rt = s->priv_data;
2956 int size_temp = size;
f6fa7814 2957 int pktsize, pkttype, copy;
2ba45a60
DM
2958 uint32_t ts;
2959 const uint8_t *buf_temp = buf;
2960 uint8_t c;
2961 int ret;
2962
2963 do {
2964 if (rt->skip_bytes) {
2965 int skip = FFMIN(rt->skip_bytes, size_temp);
2966 buf_temp += skip;
2967 size_temp -= skip;
2968 rt->skip_bytes -= skip;
2969 continue;
2970 }
2971
2972 if (rt->flv_header_bytes < RTMP_HEADER) {
2973 const uint8_t *header = rt->flv_header;
2ba45a60 2974 int channel = RTMP_AUDIO_CHANNEL;
f6fa7814
DM
2975
2976 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2ba45a60
DM
2977 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2978 rt->flv_header_bytes += copy;
2979 size_temp -= copy;
2980 if (rt->flv_header_bytes < RTMP_HEADER)
2981 break;
2982
2983 pkttype = bytestream_get_byte(&header);
2984 pktsize = bytestream_get_be24(&header);
2985 ts = bytestream_get_be24(&header);
2986 ts |= bytestream_get_byte(&header) << 24;
2987 bytestream_get_be24(&header);
2988 rt->flv_size = pktsize;
2989
2990 if (pkttype == RTMP_PT_VIDEO)
2991 channel = RTMP_VIDEO_CHANNEL;
2992
2ba45a60
DM
2993 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2994 pkttype == RTMP_PT_NOTIFY) {
2ba45a60
DM
2995 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2996 &rt->nb_prev_pkt[1],
2997 channel)) < 0)
2998 return ret;
f6fa7814
DM
2999 // Force sending a full 12 bytes header by clearing the
3000 // channel id, to make it not match a potential earlier
3001 // packet in the same channel.
2ba45a60
DM
3002 rt->prev_pkt[1][channel].channel_id = 0;
3003 }
3004
3005 //this can be a big packet, it's better to send it right here
3006 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3007 pkttype, ts, pktsize)) < 0)
3008 return ret;
3009
3010 rt->out_pkt.extra = rt->stream_id;
3011 rt->flv_data = rt->out_pkt.data;
2ba45a60
DM
3012 }
3013
f6fa7814
DM
3014 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3015 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3016 rt->flv_off += copy;
3017 size_temp -= copy;
2ba45a60
DM
3018
3019 if (rt->flv_off == rt->flv_size) {
3020 rt->skip_bytes = 4;
3021
f6fa7814
DM
3022 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3023 // For onMetaData and |RtmpSampleAccess packets, we want
3024 // @setDataFrame prepended to the packet before it gets sent.
3025 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3026 // and onCuePoint).
3027 uint8_t commandbuffer[64];
3028 int stringlen = 0;
3029 GetByteContext gbc;
3030
3031 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3032 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3033 &stringlen)) {
3034 if (!strcmp(commandbuffer, "onMetaData") ||
3035 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3036 uint8_t *ptr;
3037 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3038 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3039 return ret;
3040 }
3041 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3042 rt->out_pkt.size += 16;
3043 ptr = rt->out_pkt.data;
3044 ff_amf_write_string(&ptr, "@setDataFrame");
3045 }
3046 }
3047 }
3048
2ba45a60
DM
3049 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3050 return ret;
3051 rt->flv_size = 0;
3052 rt->flv_off = 0;
3053 rt->flv_header_bytes = 0;
3054 rt->flv_nb_packets++;
3055 }
3056 } while (buf_temp - buf < size);
3057
3058 if (rt->flv_nb_packets < rt->flush_interval)
3059 return size;
3060 rt->flv_nb_packets = 0;
3061
3062 /* set stream into nonblocking mode */
3063 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3064
3065 /* try to read one byte from the stream */
3066 ret = ffurl_read(rt->stream, &c, 1);
3067
3068 /* switch the stream back into blocking mode */
3069 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3070
3071 if (ret == AVERROR(EAGAIN)) {
3072 /* no incoming data to handle */
3073 return size;
3074 } else if (ret < 0) {
3075 return ret;
3076 } else if (ret == 1) {
3077 RTMPPacket rpkt = { 0 };
3078
3079 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3080 rt->in_chunk_size,
3081 &rt->prev_pkt[0],
3082 &rt->nb_prev_pkt[0], c)) <= 0)
3083 return ret;
3084
3085 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3086 return ret;
3087
3088 ff_rtmp_packet_destroy(&rpkt);
3089 }
3090
3091 return size;
3092}
3093
3094#define OFFSET(x) offsetof(RTMPContext, x)
3095#define DEC AV_OPT_FLAG_DECODING_PARAM
3096#define ENC AV_OPT_FLAG_ENCODING_PARAM
3097
3098static const AVOption rtmp_options[] = {
3099 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3100 {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {.i64 = 3000}, 0, INT_MAX, DEC|ENC},
3101 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3102 {"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},
3103 {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {.i64 = 10}, 0, INT_MAX, ENC},
3104 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = -2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
3105 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3106 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3107 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3108 {"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},
3109 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3110 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3111 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3112 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3113 {"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},
3114 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3115 {"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},
3116 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3117 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3118 {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3119 { NULL },
3120};
3121
3122#define RTMP_PROTOCOL(flavor) \
3123static const AVClass flavor##_class = { \
3124 .class_name = #flavor, \
3125 .item_name = av_default_item_name, \
3126 .option = rtmp_options, \
3127 .version = LIBAVUTIL_VERSION_INT, \
3128}; \
3129 \
3130URLProtocol ff_##flavor##_protocol = { \
3131 .name = #flavor, \
3132 .url_open = rtmp_open, \
3133 .url_read = rtmp_read, \
3134 .url_read_seek = rtmp_seek, \
f6fa7814 3135 .url_read_pause = rtmp_pause, \
2ba45a60
DM
3136 .url_write = rtmp_write, \
3137 .url_close = rtmp_close, \
3138 .priv_data_size = sizeof(RTMPContext), \
3139 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3140 .priv_data_class= &flavor##_class, \
3141};
3142
3143
3144RTMP_PROTOCOL(rtmp)
3145RTMP_PROTOCOL(rtmpe)
3146RTMP_PROTOCOL(rtmps)
3147RTMP_PROTOCOL(rtmpt)
3148RTMP_PROTOCOL(rtmpte)
3149RTMP_PROTOCOL(rtmpts)