LCOV - code coverage report
Current view: top level - libavformat - rtmpproto.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1567 0.0 %
Date: 2017-12-16 13:57:32 Functions: 0 62 0.0 %

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

Generated by: LCOV version 1.13