annotate ffmpeg/libavformat/rtmpproto.c @ 13:844d341cf643 tip

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