LCOV - code coverage report
Current view: top level - libavformat - rtmppkt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 471 0.0 %
Date: 2017-12-17 04:34:43 Functions: 0 28 0.0 %

          Line data    Source code
       1             : /*
       2             :  * RTMP input format
       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             : #include "libavcodec/bytestream.h"
      23             : #include "libavutil/avstring.h"
      24             : #include "libavutil/intfloat.h"
      25             : #include "avformat.h"
      26             : 
      27             : #include "rtmppkt.h"
      28             : #include "flv.h"
      29             : #include "url.h"
      30             : 
      31           0 : void ff_amf_write_bool(uint8_t **dst, int val)
      32             : {
      33           0 :     bytestream_put_byte(dst, AMF_DATA_TYPE_BOOL);
      34           0 :     bytestream_put_byte(dst, val);
      35           0 : }
      36             : 
      37           0 : void ff_amf_write_number(uint8_t **dst, double val)
      38             : {
      39           0 :     bytestream_put_byte(dst, AMF_DATA_TYPE_NUMBER);
      40           0 :     bytestream_put_be64(dst, av_double2int(val));
      41           0 : }
      42             : 
      43           0 : void ff_amf_write_string(uint8_t **dst, const char *str)
      44             : {
      45           0 :     bytestream_put_byte(dst, AMF_DATA_TYPE_STRING);
      46           0 :     bytestream_put_be16(dst, strlen(str));
      47           0 :     bytestream_put_buffer(dst, str, strlen(str));
      48           0 : }
      49             : 
      50           0 : void ff_amf_write_string2(uint8_t **dst, const char *str1, const char *str2)
      51             : {
      52           0 :     int len1 = 0, len2 = 0;
      53           0 :     if (str1)
      54           0 :         len1 = strlen(str1);
      55           0 :     if (str2)
      56           0 :         len2 = strlen(str2);
      57           0 :     bytestream_put_byte(dst, AMF_DATA_TYPE_STRING);
      58           0 :     bytestream_put_be16(dst, len1 + len2);
      59           0 :     bytestream_put_buffer(dst, str1, len1);
      60           0 :     bytestream_put_buffer(dst, str2, len2);
      61           0 : }
      62             : 
      63           0 : void ff_amf_write_null(uint8_t **dst)
      64             : {
      65           0 :     bytestream_put_byte(dst, AMF_DATA_TYPE_NULL);
      66           0 : }
      67             : 
      68           0 : void ff_amf_write_object_start(uint8_t **dst)
      69             : {
      70           0 :     bytestream_put_byte(dst, AMF_DATA_TYPE_OBJECT);
      71           0 : }
      72             : 
      73           0 : void ff_amf_write_field_name(uint8_t **dst, const char *str)
      74             : {
      75           0 :     bytestream_put_be16(dst, strlen(str));
      76           0 :     bytestream_put_buffer(dst, str, strlen(str));
      77           0 : }
      78             : 
      79           0 : void ff_amf_write_object_end(uint8_t **dst)
      80             : {
      81             :     /* first two bytes are field name length = 0,
      82             :      * AMF object should end with it and end marker
      83             :      */
      84           0 :     bytestream_put_be24(dst, AMF_DATA_TYPE_OBJECT_END);
      85           0 : }
      86             : 
      87           0 : int ff_amf_read_bool(GetByteContext *bc, int *val)
      88             : {
      89           0 :     if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_BOOL)
      90           0 :         return AVERROR_INVALIDDATA;
      91           0 :     *val = bytestream2_get_byte(bc);
      92           0 :     return 0;
      93             : }
      94             : 
      95           0 : int ff_amf_read_number(GetByteContext *bc, double *val)
      96             : {
      97             :     uint64_t read;
      98           0 :     if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NUMBER)
      99           0 :         return AVERROR_INVALIDDATA;
     100           0 :     read = bytestream2_get_be64(bc);
     101           0 :     *val = av_int2double(read);
     102           0 :     return 0;
     103             : }
     104             : 
     105           0 : int ff_amf_get_string(GetByteContext *bc, uint8_t *str,
     106             :                       int strsize, int *length)
     107             : {
     108           0 :     int stringlen = 0;
     109             :     int readsize;
     110           0 :     stringlen = bytestream2_get_be16(bc);
     111           0 :     if (stringlen + 1 > strsize)
     112           0 :         return AVERROR(EINVAL);
     113           0 :     readsize = bytestream2_get_buffer(bc, str, stringlen);
     114           0 :     if (readsize != stringlen) {
     115           0 :         av_log(NULL, AV_LOG_WARNING,
     116             :                "Unable to read as many bytes as AMF string signaled\n");
     117             :     }
     118           0 :     str[readsize] = '\0';
     119           0 :     *length = FFMIN(stringlen, readsize);
     120           0 :     return 0;
     121             : }
     122             : 
     123           0 : int ff_amf_read_string(GetByteContext *bc, uint8_t *str,
     124             :                        int strsize, int *length)
     125             : {
     126           0 :     if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_STRING)
     127           0 :         return AVERROR_INVALIDDATA;
     128           0 :     return ff_amf_get_string(bc, str, strsize, length);
     129             : }
     130             : 
     131           0 : int ff_amf_read_null(GetByteContext *bc)
     132             : {
     133           0 :     if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NULL)
     134           0 :         return AVERROR_INVALIDDATA;
     135           0 :     return 0;
     136             : }
     137             : 
     138           0 : int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt,
     139             :                               int channel)
     140             : {
     141             :     int nb_alloc;
     142             :     RTMPPacket *ptr;
     143           0 :     if (channel < *nb_prev_pkt)
     144           0 :         return 0;
     145             : 
     146           0 :     nb_alloc = channel + 16;
     147             :     // This can't use the av_reallocp family of functions, since we
     148             :     // would need to free each element in the array before the array
     149             :     // itself is freed.
     150           0 :     ptr = av_realloc_array(*prev_pkt, nb_alloc, sizeof(**prev_pkt));
     151           0 :     if (!ptr)
     152           0 :         return AVERROR(ENOMEM);
     153           0 :     memset(ptr + *nb_prev_pkt, 0, (nb_alloc - *nb_prev_pkt) * sizeof(*ptr));
     154           0 :     *prev_pkt = ptr;
     155           0 :     *nb_prev_pkt = nb_alloc;
     156           0 :     return 0;
     157             : }
     158             : 
     159           0 : int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
     160             :                         int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt)
     161             : {
     162             :     uint8_t hdr;
     163             : 
     164           0 :     if (ffurl_read(h, &hdr, 1) != 1)
     165           0 :         return AVERROR(EIO);
     166             : 
     167           0 :     return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt,
     168             :                                         nb_prev_pkt, hdr);
     169             : }
     170             : 
     171           0 : static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p,
     172             :                                       int chunk_size, RTMPPacket **prev_pkt_ptr,
     173             :                                       int *nb_prev_pkt, uint8_t hdr)
     174             : {
     175             : 
     176             :     uint8_t buf[16];
     177             :     int channel_id, timestamp, size;
     178             :     uint32_t ts_field; // non-extended timestamp or delta field
     179           0 :     uint32_t extra = 0;
     180             :     enum RTMPPacketType type;
     181           0 :     int written = 0;
     182             :     int ret, toread;
     183             :     RTMPPacket *prev_pkt;
     184             : 
     185           0 :     written++;
     186           0 :     channel_id = hdr & 0x3F;
     187             : 
     188           0 :     if (channel_id < 2) { //special case for channel number >= 64
     189           0 :         buf[1] = 0;
     190           0 :         if (ffurl_read_complete(h, buf, channel_id + 1) != channel_id + 1)
     191           0 :             return AVERROR(EIO);
     192           0 :         written += channel_id + 1;
     193           0 :         channel_id = AV_RL16(buf) + 64;
     194             :     }
     195           0 :     if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
     196             :                                          channel_id)) < 0)
     197           0 :         return ret;
     198           0 :     prev_pkt = *prev_pkt_ptr;
     199           0 :     size  = prev_pkt[channel_id].size;
     200           0 :     type  = prev_pkt[channel_id].type;
     201           0 :     extra = prev_pkt[channel_id].extra;
     202             : 
     203           0 :     hdr >>= 6; // header size indicator
     204           0 :     if (hdr == RTMP_PS_ONEBYTE) {
     205           0 :         ts_field = prev_pkt[channel_id].ts_field;
     206             :     } else {
     207           0 :         if (ffurl_read_complete(h, buf, 3) != 3)
     208           0 :             return AVERROR(EIO);
     209           0 :         written += 3;
     210           0 :         ts_field = AV_RB24(buf);
     211           0 :         if (hdr != RTMP_PS_FOURBYTES) {
     212           0 :             if (ffurl_read_complete(h, buf, 3) != 3)
     213           0 :                 return AVERROR(EIO);
     214           0 :             written += 3;
     215           0 :             size = AV_RB24(buf);
     216           0 :             if (ffurl_read_complete(h, buf, 1) != 1)
     217           0 :                 return AVERROR(EIO);
     218           0 :             written++;
     219           0 :             type = buf[0];
     220           0 :             if (hdr == RTMP_PS_TWELVEBYTES) {
     221           0 :                 if (ffurl_read_complete(h, buf, 4) != 4)
     222           0 :                     return AVERROR(EIO);
     223           0 :                 written += 4;
     224           0 :                 extra = AV_RL32(buf);
     225             :             }
     226             :         }
     227             :     }
     228           0 :     if (ts_field == 0xFFFFFF) {
     229           0 :         if (ffurl_read_complete(h, buf, 4) != 4)
     230           0 :             return AVERROR(EIO);
     231           0 :         timestamp = AV_RB32(buf);
     232             :     } else {
     233           0 :         timestamp = ts_field;
     234             :     }
     235           0 :     if (hdr != RTMP_PS_TWELVEBYTES)
     236           0 :         timestamp += prev_pkt[channel_id].timestamp;
     237             : 
     238           0 :     if (prev_pkt[channel_id].read && size != prev_pkt[channel_id].size) {
     239           0 :         av_log(h, AV_LOG_ERROR, "RTMP packet size mismatch %d != %d\n",
     240           0 :                                 size, prev_pkt[channel_id].size);
     241           0 :         ff_rtmp_packet_destroy(&prev_pkt[channel_id]);
     242           0 :         prev_pkt[channel_id].read = 0;
     243           0 :         return AVERROR_INVALIDDATA;
     244             :     }
     245             : 
     246           0 :     if (!prev_pkt[channel_id].read) {
     247           0 :         if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp,
     248             :                                          size)) < 0)
     249           0 :             return ret;
     250           0 :         p->read = written;
     251           0 :         p->offset = 0;
     252           0 :         prev_pkt[channel_id].ts_field   = ts_field;
     253           0 :         prev_pkt[channel_id].timestamp  = timestamp;
     254             :     } else {
     255             :         // previous packet in this channel hasn't completed reading
     256           0 :         RTMPPacket *prev = &prev_pkt[channel_id];
     257           0 :         p->data          = prev->data;
     258           0 :         p->size          = prev->size;
     259           0 :         p->channel_id    = prev->channel_id;
     260           0 :         p->type          = prev->type;
     261           0 :         p->ts_field      = prev->ts_field;
     262           0 :         p->extra         = prev->extra;
     263           0 :         p->offset        = prev->offset;
     264           0 :         p->read          = prev->read + written;
     265           0 :         p->timestamp     = prev->timestamp;
     266           0 :         prev->data       = NULL;
     267             :     }
     268           0 :     p->extra = extra;
     269             :     // save history
     270           0 :     prev_pkt[channel_id].channel_id = channel_id;
     271           0 :     prev_pkt[channel_id].type       = type;
     272           0 :     prev_pkt[channel_id].size       = size;
     273           0 :     prev_pkt[channel_id].extra      = extra;
     274           0 :     size = size - p->offset;
     275             : 
     276           0 :     toread = FFMIN(size, chunk_size);
     277           0 :     if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) {
     278           0 :         ff_rtmp_packet_destroy(p);
     279           0 :         return AVERROR(EIO);
     280             :     }
     281           0 :     size      -= toread;
     282           0 :     p->read   += toread;
     283           0 :     p->offset += toread;
     284             : 
     285           0 :     if (size > 0) {
     286           0 :        RTMPPacket *prev = &prev_pkt[channel_id];
     287           0 :        prev->data = p->data;
     288           0 :        prev->read = p->read;
     289           0 :        prev->offset = p->offset;
     290           0 :        p->data      = NULL;
     291           0 :        return AVERROR(EAGAIN);
     292             :     }
     293             : 
     294           0 :     prev_pkt[channel_id].read = 0; // read complete; reset if needed
     295           0 :     return p->read;
     296             : }
     297             : 
     298           0 : int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
     299             :                                  RTMPPacket **prev_pkt, int *nb_prev_pkt,
     300             :                                  uint8_t hdr)
     301             : {
     302           0 :     while (1) {
     303           0 :         int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt,
     304             :                                              nb_prev_pkt, hdr);
     305           0 :         if (ret > 0 || ret != AVERROR(EAGAIN))
     306           0 :             return ret;
     307             : 
     308           0 :         if (ffurl_read(h, &hdr, 1) != 1)
     309           0 :             return AVERROR(EIO);
     310             :     }
     311             : }
     312             : 
     313           0 : int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
     314             :                          int chunk_size, RTMPPacket **prev_pkt_ptr,
     315             :                          int *nb_prev_pkt)
     316             : {
     317           0 :     uint8_t pkt_hdr[16], *p = pkt_hdr;
     318           0 :     int mode = RTMP_PS_TWELVEBYTES;
     319           0 :     int off = 0;
     320           0 :     int written = 0;
     321             :     int ret;
     322             :     RTMPPacket *prev_pkt;
     323             :     int use_delta; // flag if using timestamp delta, not RTMP_PS_TWELVEBYTES
     324             :     uint32_t timestamp; // full 32-bit timestamp or delta value
     325             : 
     326           0 :     if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
     327             :                                          pkt->channel_id)) < 0)
     328           0 :         return ret;
     329           0 :     prev_pkt = *prev_pkt_ptr;
     330             : 
     331             :     //if channel_id = 0, this is first presentation of prev_pkt, send full hdr.
     332           0 :     use_delta = prev_pkt[pkt->channel_id].channel_id &&
     333           0 :         pkt->extra == prev_pkt[pkt->channel_id].extra &&
     334           0 :         pkt->timestamp >= prev_pkt[pkt->channel_id].timestamp;
     335             : 
     336           0 :     timestamp = pkt->timestamp;
     337           0 :     if (use_delta) {
     338           0 :         timestamp -= prev_pkt[pkt->channel_id].timestamp;
     339             :     }
     340           0 :     if (timestamp >= 0xFFFFFF) {
     341           0 :         pkt->ts_field = 0xFFFFFF;
     342             :     } else {
     343           0 :         pkt->ts_field = timestamp;
     344             :     }
     345             : 
     346           0 :     if (use_delta) {
     347           0 :         if (pkt->type == prev_pkt[pkt->channel_id].type &&
     348           0 :             pkt->size == prev_pkt[pkt->channel_id].size) {
     349           0 :             mode = RTMP_PS_FOURBYTES;
     350           0 :             if (pkt->ts_field == prev_pkt[pkt->channel_id].ts_field)
     351           0 :                 mode = RTMP_PS_ONEBYTE;
     352             :         } else {
     353           0 :             mode = RTMP_PS_EIGHTBYTES;
     354             :         }
     355             :     }
     356             : 
     357           0 :     if (pkt->channel_id < 64) {
     358           0 :         bytestream_put_byte(&p, pkt->channel_id | (mode << 6));
     359           0 :     } else if (pkt->channel_id < 64 + 256) {
     360           0 :         bytestream_put_byte(&p, 0               | (mode << 6));
     361           0 :         bytestream_put_byte(&p, pkt->channel_id - 64);
     362             :     } else {
     363           0 :         bytestream_put_byte(&p, 1               | (mode << 6));
     364           0 :         bytestream_put_le16(&p, pkt->channel_id - 64);
     365             :     }
     366           0 :     if (mode != RTMP_PS_ONEBYTE) {
     367           0 :         bytestream_put_be24(&p, pkt->ts_field);
     368           0 :         if (mode != RTMP_PS_FOURBYTES) {
     369           0 :             bytestream_put_be24(&p, pkt->size);
     370           0 :             bytestream_put_byte(&p, pkt->type);
     371           0 :             if (mode == RTMP_PS_TWELVEBYTES)
     372           0 :                 bytestream_put_le32(&p, pkt->extra);
     373             :         }
     374             :     }
     375           0 :     if (pkt->ts_field == 0xFFFFFF)
     376           0 :         bytestream_put_be32(&p, timestamp);
     377             :     // save history
     378           0 :     prev_pkt[pkt->channel_id].channel_id = pkt->channel_id;
     379           0 :     prev_pkt[pkt->channel_id].type       = pkt->type;
     380           0 :     prev_pkt[pkt->channel_id].size       = pkt->size;
     381           0 :     prev_pkt[pkt->channel_id].timestamp  = pkt->timestamp;
     382           0 :     prev_pkt[pkt->channel_id].ts_field   = pkt->ts_field;
     383           0 :     prev_pkt[pkt->channel_id].extra      = pkt->extra;
     384             : 
     385           0 :     if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0)
     386           0 :         return ret;
     387           0 :     written = p - pkt_hdr + pkt->size;
     388           0 :     while (off < pkt->size) {
     389           0 :         int towrite = FFMIN(chunk_size, pkt->size - off);
     390           0 :         if ((ret = ffurl_write(h, pkt->data + off, towrite)) < 0)
     391           0 :             return ret;
     392           0 :         off += towrite;
     393           0 :         if (off < pkt->size) {
     394           0 :             uint8_t marker = 0xC0 | pkt->channel_id;
     395           0 :             if ((ret = ffurl_write(h, &marker, 1)) < 0)
     396           0 :                 return ret;
     397           0 :             written++;
     398           0 :             if (pkt->ts_field == 0xFFFFFF) {
     399             :                 uint8_t ts_header[4];
     400           0 :                 AV_WB32(ts_header, timestamp);
     401           0 :                 if ((ret = ffurl_write(h, ts_header, 4)) < 0)
     402           0 :                     return ret;
     403           0 :                 written += 4;
     404             :             }
     405             :         }
     406             :     }
     407           0 :     return written;
     408             : }
     409             : 
     410           0 : int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type,
     411             :                           int timestamp, int size)
     412             : {
     413           0 :     if (size) {
     414           0 :         pkt->data = av_realloc(NULL, size);
     415           0 :         if (!pkt->data)
     416           0 :             return AVERROR(ENOMEM);
     417             :     }
     418           0 :     pkt->size       = size;
     419           0 :     pkt->channel_id = channel_id;
     420           0 :     pkt->type       = type;
     421           0 :     pkt->timestamp  = timestamp;
     422           0 :     pkt->extra      = 0;
     423           0 :     pkt->ts_field   = 0;
     424             : 
     425           0 :     return 0;
     426             : }
     427             : 
     428           0 : void ff_rtmp_packet_destroy(RTMPPacket *pkt)
     429             : {
     430           0 :     if (!pkt)
     431           0 :         return;
     432           0 :     av_freep(&pkt->data);
     433           0 :     pkt->size = 0;
     434             : }
     435             : 
     436           0 : static int amf_tag_skip(GetByteContext *gb)
     437             : {
     438             :     AMFDataType type;
     439           0 :     unsigned nb   = -1;
     440           0 :     int parse_key = 1;
     441             : 
     442           0 :     if (bytestream2_get_bytes_left(gb) < 1)
     443           0 :         return -1;
     444             : 
     445           0 :     type = bytestream2_get_byte(gb);
     446           0 :     switch (type) {
     447           0 :     case AMF_DATA_TYPE_NUMBER:
     448           0 :         bytestream2_get_be64(gb);
     449           0 :         return 0;
     450           0 :     case AMF_DATA_TYPE_BOOL:
     451           0 :         bytestream2_get_byte(gb);
     452           0 :         return 0;
     453           0 :     case AMF_DATA_TYPE_STRING:
     454           0 :         bytestream2_skip(gb, bytestream2_get_be16(gb));
     455           0 :         return 0;
     456           0 :     case AMF_DATA_TYPE_LONG_STRING:
     457           0 :         bytestream2_skip(gb, bytestream2_get_be32(gb));
     458           0 :         return 0;
     459           0 :     case AMF_DATA_TYPE_NULL:
     460           0 :         return 0;
     461           0 :     case AMF_DATA_TYPE_DATE:
     462           0 :         bytestream2_skip(gb, 10);
     463           0 :         return 0;
     464           0 :     case AMF_DATA_TYPE_ARRAY:
     465           0 :         parse_key = 0;
     466           0 :     case AMF_DATA_TYPE_MIXEDARRAY:
     467           0 :         nb = bytestream2_get_be32(gb);
     468           0 :     case AMF_DATA_TYPE_OBJECT:
     469           0 :         while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
     470             :             int t;
     471           0 :             if (parse_key) {
     472           0 :                 int size = bytestream2_get_be16(gb);
     473           0 :                 if (!size) {
     474           0 :                     bytestream2_get_byte(gb);
     475           0 :                     break;
     476             :                 }
     477           0 :                 if (size < 0 || size >= bytestream2_get_bytes_left(gb))
     478           0 :                     return -1;
     479           0 :                 bytestream2_skip(gb, size);
     480             :             }
     481           0 :             t = amf_tag_skip(gb);
     482           0 :             if (t < 0 || bytestream2_get_bytes_left(gb) <= 0)
     483           0 :                 return -1;
     484             :         }
     485           0 :         return 0;
     486           0 :     case AMF_DATA_TYPE_OBJECT_END:  return 0;
     487           0 :     default:                        return -1;
     488             :     }
     489             : }
     490             : 
     491           0 : int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
     492             : {
     493             :     GetByteContext gb;
     494             :     int ret;
     495             : 
     496           0 :     if (data >= data_end)
     497           0 :         return -1;
     498             : 
     499           0 :     bytestream2_init(&gb, data, data_end - data);
     500             : 
     501           0 :     ret = amf_tag_skip(&gb);
     502           0 :     if (ret < 0 || bytestream2_get_bytes_left(&gb) <= 0)
     503           0 :         return -1;
     504           0 :     av_assert0(bytestream2_tell(&gb) >= 0 && bytestream2_tell(&gb) <= data_end - data);
     505           0 :     return bytestream2_tell(&gb);
     506             : }
     507             : 
     508           0 : static int amf_get_field_value2(GetByteContext *gb,
     509             :                            const uint8_t *name, uint8_t *dst, int dst_size)
     510             : {
     511           0 :     int namelen = strlen(name);
     512             :     int len;
     513             : 
     514           0 :     while (bytestream2_peek_byte(gb) != AMF_DATA_TYPE_OBJECT && bytestream2_get_bytes_left(gb) > 0) {
     515           0 :         int ret = amf_tag_skip(gb);
     516           0 :         if (ret < 0)
     517           0 :             return -1;
     518             :     }
     519           0 :     if (bytestream2_get_bytes_left(gb) < 3)
     520           0 :         return -1;
     521           0 :     bytestream2_get_byte(gb);
     522             : 
     523           0 :     for (;;) {
     524           0 :         int size = bytestream2_get_be16(gb);
     525           0 :         if (!size)
     526           0 :             break;
     527           0 :         if (size < 0 || size >= bytestream2_get_bytes_left(gb))
     528           0 :             return -1;
     529           0 :         bytestream2_skip(gb, size);
     530           0 :         if (size == namelen && !memcmp(gb->buffer-size, name, namelen)) {
     531           0 :             switch (bytestream2_get_byte(gb)) {
     532           0 :             case AMF_DATA_TYPE_NUMBER:
     533           0 :                 snprintf(dst, dst_size, "%g", av_int2double(bytestream2_get_be64(gb)));
     534           0 :                 break;
     535           0 :             case AMF_DATA_TYPE_BOOL:
     536           0 :                 snprintf(dst, dst_size, "%s", bytestream2_get_byte(gb) ? "true" : "false");
     537           0 :                 break;
     538           0 :             case AMF_DATA_TYPE_STRING:
     539           0 :                 len = bytestream2_get_be16(gb);
     540           0 :                 if (dst_size < 1)
     541           0 :                     return -1;
     542           0 :                 if (dst_size < len + 1)
     543           0 :                     len = dst_size - 1;
     544           0 :                 bytestream2_get_buffer(gb, dst, len);
     545           0 :                 dst[len] = 0;
     546           0 :                 break;
     547           0 :             default:
     548           0 :                 return -1;
     549             :             }
     550           0 :             return 0;
     551             :         }
     552           0 :         len = amf_tag_skip(gb);
     553           0 :         if (len < 0 || bytestream2_get_bytes_left(gb) <= 0)
     554           0 :             return -1;
     555             :     }
     556           0 :     return -1;
     557             : }
     558             : 
     559           0 : int ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end,
     560             :                            const uint8_t *name, uint8_t *dst, int dst_size)
     561             : {
     562             :     GetByteContext gb;
     563             : 
     564           0 :     if (data >= data_end)
     565           0 :         return -1;
     566             : 
     567           0 :     bytestream2_init(&gb, data, data_end - data);
     568             : 
     569           0 :     return amf_get_field_value2(&gb, name, dst, dst_size);
     570             : }
     571             : 
     572           0 : static const char* rtmp_packet_type(int type)
     573             : {
     574           0 :     switch (type) {
     575           0 :     case RTMP_PT_CHUNK_SIZE:     return "chunk size";
     576           0 :     case RTMP_PT_BYTES_READ:     return "bytes read";
     577           0 :     case RTMP_PT_USER_CONTROL:   return "user control";
     578           0 :     case RTMP_PT_WINDOW_ACK_SIZE: return "window acknowledgement size";
     579           0 :     case RTMP_PT_SET_PEER_BW:    return "set peer bandwidth";
     580           0 :     case RTMP_PT_AUDIO:          return "audio packet";
     581           0 :     case RTMP_PT_VIDEO:          return "video packet";
     582           0 :     case RTMP_PT_FLEX_STREAM:    return "Flex shared stream";
     583           0 :     case RTMP_PT_FLEX_OBJECT:    return "Flex shared object";
     584           0 :     case RTMP_PT_FLEX_MESSAGE:   return "Flex shared message";
     585           0 :     case RTMP_PT_NOTIFY:         return "notification";
     586           0 :     case RTMP_PT_SHARED_OBJ:     return "shared object";
     587           0 :     case RTMP_PT_INVOKE:         return "invoke";
     588           0 :     case RTMP_PT_METADATA:       return "metadata";
     589           0 :     default:                     return "unknown";
     590             :     }
     591             : }
     592             : 
     593           0 : static void amf_tag_contents(void *ctx, const uint8_t *data,
     594             :                              const uint8_t *data_end)
     595             : {
     596           0 :     unsigned int size, nb = -1;
     597             :     char buf[1024];
     598             :     AMFDataType type;
     599           0 :     int parse_key = 1;
     600             : 
     601           0 :     if (data >= data_end)
     602           0 :         return;
     603           0 :     switch ((type = *data++)) {
     604           0 :     case AMF_DATA_TYPE_NUMBER:
     605           0 :         av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2double(AV_RB64(data)));
     606           0 :         return;
     607           0 :     case AMF_DATA_TYPE_BOOL:
     608           0 :         av_log(ctx, AV_LOG_DEBUG, " bool %d\n", *data);
     609           0 :         return;
     610           0 :     case AMF_DATA_TYPE_STRING:
     611             :     case AMF_DATA_TYPE_LONG_STRING:
     612           0 :         if (type == AMF_DATA_TYPE_STRING) {
     613           0 :             size = bytestream_get_be16(&data);
     614             :         } else {
     615           0 :             size = bytestream_get_be32(&data);
     616             :         }
     617           0 :         size = FFMIN(size, sizeof(buf) - 1);
     618           0 :         memcpy(buf, data, size);
     619           0 :         buf[size] = 0;
     620           0 :         av_log(ctx, AV_LOG_DEBUG, " string '%s'\n", buf);
     621           0 :         return;
     622           0 :     case AMF_DATA_TYPE_NULL:
     623           0 :         av_log(ctx, AV_LOG_DEBUG, " NULL\n");
     624           0 :         return;
     625           0 :     case AMF_DATA_TYPE_ARRAY:
     626           0 :         parse_key = 0;
     627           0 :     case AMF_DATA_TYPE_MIXEDARRAY:
     628           0 :         nb = bytestream_get_be32(&data);
     629           0 :     case AMF_DATA_TYPE_OBJECT:
     630           0 :         av_log(ctx, AV_LOG_DEBUG, " {\n");
     631           0 :         while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
     632             :             int t;
     633           0 :             if (parse_key) {
     634           0 :                 size = bytestream_get_be16(&data);
     635           0 :                 size = FFMIN(size, sizeof(buf) - 1);
     636           0 :                 if (!size) {
     637           0 :                     av_log(ctx, AV_LOG_DEBUG, " }\n");
     638           0 :                     data++;
     639           0 :                     break;
     640             :                 }
     641           0 :                 memcpy(buf, data, size);
     642           0 :                 buf[size] = 0;
     643           0 :                 if (size >= data_end - data)
     644           0 :                     return;
     645           0 :                 data += size;
     646           0 :                 av_log(ctx, AV_LOG_DEBUG, "  %s: ", buf);
     647             :             }
     648           0 :             amf_tag_contents(ctx, data, data_end);
     649           0 :             t = ff_amf_tag_size(data, data_end);
     650           0 :             if (t < 0 || t >= data_end - data)
     651           0 :                 return;
     652           0 :             data += t;
     653             :         }
     654           0 :         return;
     655           0 :     case AMF_DATA_TYPE_OBJECT_END:
     656           0 :         av_log(ctx, AV_LOG_DEBUG, " }\n");
     657           0 :         return;
     658           0 :     default:
     659           0 :         return;
     660             :     }
     661             : }
     662             : 
     663           0 : void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
     664             : {
     665           0 :     av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n",
     666           0 :            rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->size);
     667           0 :     if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) {
     668           0 :         uint8_t *src = p->data, *src_end = p->data + p->size;
     669           0 :         while (src < src_end) {
     670             :             int sz;
     671           0 :             amf_tag_contents(ctx, src, src_end);
     672           0 :             sz = ff_amf_tag_size(src, src_end);
     673           0 :             if (sz < 0)
     674           0 :                 break;
     675           0 :             src += sz;
     676             :         }
     677           0 :     } else if (p->type == RTMP_PT_WINDOW_ACK_SIZE) {
     678           0 :         av_log(ctx, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", AV_RB32(p->data));
     679           0 :     } else if (p->type == RTMP_PT_SET_PEER_BW) {
     680           0 :         av_log(ctx, AV_LOG_DEBUG, "Set Peer BW = %d\n", AV_RB32(p->data));
     681           0 :     } else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) {
     682             :         int i;
     683           0 :         for (i = 0; i < p->size; i++)
     684           0 :             av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]);
     685           0 :         av_log(ctx, AV_LOG_DEBUG, "\n");
     686             :     }
     687           0 : }
     688             : 
     689           0 : int ff_amf_match_string(const uint8_t *data, int size, const char *str)
     690             : {
     691           0 :     int len = strlen(str);
     692             :     int amf_len, type;
     693             : 
     694           0 :     if (size < 1)
     695           0 :         return 0;
     696             : 
     697           0 :     type = *data++;
     698             : 
     699           0 :     if (type != AMF_DATA_TYPE_LONG_STRING &&
     700             :         type != AMF_DATA_TYPE_STRING)
     701           0 :         return 0;
     702             : 
     703           0 :     if (type == AMF_DATA_TYPE_LONG_STRING) {
     704           0 :         if ((size -= 4 + 1) < 0)
     705           0 :             return 0;
     706           0 :         amf_len = bytestream_get_be32(&data);
     707             :     } else {
     708           0 :         if ((size -= 2 + 1) < 0)
     709           0 :             return 0;
     710           0 :         amf_len = bytestream_get_be16(&data);
     711             :     }
     712             : 
     713           0 :     if (amf_len > size)
     714           0 :         return 0;
     715             : 
     716           0 :     if (amf_len != len)
     717           0 :         return 0;
     718             : 
     719           0 :     return !memcmp(data, str, len);
     720             : }

Generated by: LCOV version 1.13