FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/rtmpproto.c
Date: 2026-05-14 01:12:21
Exec Total Coverage
Lines: 0 1630 0.0%
Functions: 0 63 0.0%
Branches: 0 910 0.0%

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