LCOV - code coverage report
Current view: top level - libavformat - rtpdec_mpeg4.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 137 0.0 %
Date: 2017-12-18 06:23:41 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Common code for the RTP depacketization of MPEG-4 formats.
       3             :  * Copyright (c) 2010 Fabrice Bellard
       4             :  *                    Romain Degez
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : /**
      24             :  * @file
      25             :  * @brief MPEG-4 / RTP Code
      26             :  * @author Fabrice Bellard
      27             :  * @author Romain Degez
      28             :  */
      29             : 
      30             : #include "rtpdec_formats.h"
      31             : #include "internal.h"
      32             : #include "libavutil/attributes.h"
      33             : #include "libavutil/avstring.h"
      34             : #include "libavcodec/get_bits.h"
      35             : 
      36             : #define MAX_AAC_HBR_FRAME_SIZE 8191
      37             : 
      38             : /** Structure listing useful vars to parse RTP packet payload */
      39             : struct PayloadContext {
      40             :     int sizelength;
      41             :     int indexlength;
      42             :     int indexdeltalength;
      43             :     int profile_level_id;
      44             :     int streamtype;
      45             :     int objecttype;
      46             :     char *mode;
      47             : 
      48             :     /** mpeg 4 AU headers */
      49             :     struct AUHeaders {
      50             :         int size;
      51             :         int index;
      52             :         int cts_flag;
      53             :         int cts;
      54             :         int dts_flag;
      55             :         int dts;
      56             :         int rap_flag;
      57             :         int streamstate;
      58             :     } *au_headers;
      59             :     int au_headers_allocated;
      60             :     int nb_au_headers;
      61             :     int au_headers_length_bytes;
      62             :     int cur_au_index;
      63             : 
      64             :     uint8_t buf[FFMAX(RTP_MAX_PACKET_LENGTH, MAX_AAC_HBR_FRAME_SIZE)];
      65             :     int buf_pos, buf_size;
      66             :     uint32_t timestamp;
      67             : };
      68             : 
      69             : typedef struct AttrNameMap {
      70             :     const char *str;
      71             :     uint16_t    type;
      72             :     uint32_t    offset;
      73             : } AttrNameMap;
      74             : 
      75             : /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
      76             : #define ATTR_NAME_TYPE_INT 0
      77             : #define ATTR_NAME_TYPE_STR 1
      78             : static const AttrNameMap attr_names[] = {
      79             :     { "SizeLength",       ATTR_NAME_TYPE_INT,
      80             :       offsetof(PayloadContext, sizelength) },
      81             :     { "IndexLength",      ATTR_NAME_TYPE_INT,
      82             :       offsetof(PayloadContext, indexlength) },
      83             :     { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
      84             :       offsetof(PayloadContext, indexdeltalength) },
      85             :     { "profile-level-id", ATTR_NAME_TYPE_INT,
      86             :       offsetof(PayloadContext, profile_level_id) },
      87             :     { "StreamType",       ATTR_NAME_TYPE_INT,
      88             :       offsetof(PayloadContext, streamtype) },
      89             :     { "mode",             ATTR_NAME_TYPE_STR,
      90             :       offsetof(PayloadContext, mode) },
      91             :     { NULL, -1, -1 },
      92             : };
      93             : 
      94           0 : static void close_context(PayloadContext *data)
      95             : {
      96           0 :     av_freep(&data->au_headers);
      97           0 :     av_freep(&data->mode);
      98           0 : }
      99             : 
     100           0 : static int parse_fmtp_config(AVCodecParameters *par, const char *value)
     101             : {
     102             :     /* decode the hexa encoded parameter */
     103           0 :     int len = ff_hex_to_data(NULL, value);
     104           0 :     av_freep(&par->extradata);
     105           0 :     if (ff_alloc_extradata(par, len))
     106           0 :         return AVERROR(ENOMEM);
     107           0 :     ff_hex_to_data(par->extradata, value);
     108           0 :     return 0;
     109             : }
     110             : 
     111           0 : static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf, int len)
     112             : {
     113             :     int au_headers_length, au_header_size, i;
     114             :     GetBitContext getbitcontext;
     115             : 
     116           0 :     if (len < 2)
     117           0 :         return AVERROR_INVALIDDATA;
     118             : 
     119             :     /* decode the first 2 bytes where the AUHeader sections are stored
     120             :        length in bits */
     121           0 :     au_headers_length = AV_RB16(buf);
     122             : 
     123           0 :     if (au_headers_length > RTP_MAX_PACKET_LENGTH)
     124           0 :       return -1;
     125             : 
     126           0 :     data->au_headers_length_bytes = (au_headers_length + 7) / 8;
     127             : 
     128             :     /* skip AU headers length section (2 bytes) */
     129           0 :     buf += 2;
     130           0 :     len -= 2;
     131             : 
     132           0 :     if (len < data->au_headers_length_bytes)
     133           0 :         return AVERROR_INVALIDDATA;
     134             : 
     135           0 :     init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
     136             : 
     137             :     /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */
     138           0 :     au_header_size = data->sizelength + data->indexlength;
     139           0 :     if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
     140           0 :         return -1;
     141             : 
     142           0 :     data->nb_au_headers = au_headers_length / au_header_size;
     143           0 :     if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
     144           0 :         av_free(data->au_headers);
     145           0 :         data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
     146           0 :         if (!data->au_headers)
     147           0 :             return AVERROR(ENOMEM);
     148           0 :         data->au_headers_allocated = data->nb_au_headers;
     149             :     }
     150             : 
     151           0 :     for (i = 0; i < data->nb_au_headers; ++i) {
     152           0 :         data->au_headers[i].size  = get_bits_long(&getbitcontext, data->sizelength);
     153           0 :         data->au_headers[i].index = get_bits_long(&getbitcontext, data->indexlength);
     154             :     }
     155             : 
     156           0 :     return 0;
     157             : }
     158             : 
     159             : 
     160             : /* Follows RFC 3640 */
     161           0 : static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
     162             :                             AVStream *st, AVPacket *pkt, uint32_t *timestamp,
     163             :                             const uint8_t *buf, int len, uint16_t seq,
     164             :                             int flags)
     165             : {
     166             :     int ret;
     167             : 
     168             : 
     169           0 :     if (!buf) {
     170           0 :         if (data->cur_au_index > data->nb_au_headers) {
     171           0 :             av_log(ctx, AV_LOG_ERROR, "Invalid parser state\n");
     172           0 :             return AVERROR_INVALIDDATA;
     173             :         }
     174           0 :         if (data->buf_size - data->buf_pos < data->au_headers[data->cur_au_index].size) {
     175           0 :             av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n");
     176           0 :             return AVERROR_INVALIDDATA;
     177             :         }
     178           0 :         if ((ret = av_new_packet(pkt, data->au_headers[data->cur_au_index].size)) < 0) {
     179           0 :             av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
     180           0 :             return ret;
     181             :         }
     182           0 :         memcpy(pkt->data, &data->buf[data->buf_pos], data->au_headers[data->cur_au_index].size);
     183           0 :         data->buf_pos += data->au_headers[data->cur_au_index].size;
     184           0 :         pkt->stream_index = st->index;
     185           0 :         data->cur_au_index++;
     186             : 
     187           0 :         if (data->cur_au_index == data->nb_au_headers) {
     188           0 :             data->buf_pos = 0;
     189           0 :             return 0;
     190             :         }
     191             : 
     192           0 :         return 1;
     193             :     }
     194             : 
     195           0 :     if (rtp_parse_mp4_au(data, buf, len)) {
     196           0 :         av_log(ctx, AV_LOG_ERROR, "Error parsing AU headers\n");
     197           0 :         return -1;
     198             :     }
     199             : 
     200           0 :     buf += data->au_headers_length_bytes + 2;
     201           0 :     len -= data->au_headers_length_bytes + 2;
     202           0 :     if (data->nb_au_headers == 1 && len < data->au_headers[0].size) {
     203             :         /* Packet is fragmented */
     204             : 
     205           0 :         if (!data->buf_pos) {
     206           0 :             if (data->au_headers[0].size > MAX_AAC_HBR_FRAME_SIZE) {
     207           0 :                 av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n");
     208           0 :                 return AVERROR_INVALIDDATA;
     209             :             }
     210             : 
     211           0 :             data->buf_size = data->au_headers[0].size;
     212           0 :             data->timestamp = *timestamp;
     213             :         }
     214             : 
     215           0 :         if (data->timestamp != *timestamp ||
     216           0 :             data->au_headers[0].size != data->buf_size ||
     217           0 :             data->buf_pos + len > MAX_AAC_HBR_FRAME_SIZE) {
     218           0 :             data->buf_pos = 0;
     219           0 :             data->buf_size = 0;
     220           0 :             av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n");
     221           0 :             return AVERROR_INVALIDDATA;
     222             :         }
     223             : 
     224           0 :         memcpy(&data->buf[data->buf_pos], buf, len);
     225           0 :         data->buf_pos += len;
     226             : 
     227           0 :         if (!(flags & RTP_FLAG_MARKER))
     228           0 :             return AVERROR(EAGAIN);
     229             : 
     230           0 :         if (data->buf_pos != data->buf_size) {
     231           0 :             data->buf_pos = 0;
     232           0 :             av_log(ctx, AV_LOG_ERROR, "Missed some packets, discarding frame\n");
     233           0 :             return AVERROR_INVALIDDATA;
     234             :         }
     235             : 
     236           0 :         data->buf_pos = 0;
     237           0 :         ret = av_new_packet(pkt, data->buf_size);
     238           0 :         if (ret < 0) {
     239           0 :             av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
     240           0 :             return ret;
     241             :         }
     242           0 :         pkt->stream_index = st->index;
     243             : 
     244           0 :         memcpy(pkt->data, data->buf, data->buf_size);
     245             : 
     246           0 :         return 0;
     247             :     }
     248             : 
     249           0 :     if (len < data->au_headers[0].size) {
     250           0 :         av_log(ctx, AV_LOG_ERROR, "First AU larger than packet size\n");
     251           0 :         return AVERROR_INVALIDDATA;
     252             :     }
     253           0 :     if ((ret = av_new_packet(pkt, data->au_headers[0].size)) < 0) {
     254           0 :         av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
     255           0 :         return ret;
     256             :     }
     257           0 :     memcpy(pkt->data, buf, data->au_headers[0].size);
     258           0 :     len -= data->au_headers[0].size;
     259           0 :     buf += data->au_headers[0].size;
     260           0 :     pkt->stream_index = st->index;
     261             : 
     262           0 :     if (len > 0 && data->nb_au_headers > 1) {
     263           0 :         data->buf_size = FFMIN(len, sizeof(data->buf));
     264           0 :         memcpy(data->buf, buf, data->buf_size);
     265           0 :         data->cur_au_index = 1;
     266           0 :         data->buf_pos = 0;
     267           0 :         return 1;
     268             :     }
     269             : 
     270           0 :     return 0;
     271             : }
     272             : 
     273           0 : static int parse_fmtp(AVFormatContext *s,
     274             :                       AVStream *stream, PayloadContext *data,
     275             :                       const char *attr, const char *value)
     276             : {
     277           0 :     AVCodecParameters *par = stream->codecpar;
     278             :     int res, i;
     279             : 
     280           0 :     if (!strcmp(attr, "config")) {
     281           0 :         res = parse_fmtp_config(par, value);
     282             : 
     283           0 :         if (res < 0)
     284           0 :             return res;
     285             :     }
     286             : 
     287           0 :     if (par->codec_id == AV_CODEC_ID_AAC) {
     288             :         /* Looking for a known attribute */
     289           0 :         for (i = 0; attr_names[i].str; ++i) {
     290           0 :             if (!av_strcasecmp(attr, attr_names[i].str)) {
     291           0 :                 if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
     292           0 :                     int val = atoi(value);
     293           0 :                     if (val > 32) {
     294           0 :                         av_log(s, AV_LOG_ERROR,
     295             :                                "The %s field size is invalid (%d)\n",
     296             :                                attr, val);
     297           0 :                         return AVERROR_INVALIDDATA;
     298             :                     }
     299           0 :                     *(int *)((char *)data+
     300           0 :                         attr_names[i].offset) = val;
     301           0 :                 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR) {
     302           0 :                     char *val = av_strdup(value);
     303           0 :                     if (!val)
     304           0 :                         return AVERROR(ENOMEM);
     305           0 :                     *(char **)((char *)data+
     306           0 :                         attr_names[i].offset) = val;
     307             :                 }
     308             :             }
     309             :         }
     310             :     }
     311           0 :     return 0;
     312             : }
     313             : 
     314           0 : static int parse_sdp_line(AVFormatContext *s, int st_index,
     315             :                           PayloadContext *data, const char *line)
     316             : {
     317             :     const char *p;
     318             : 
     319           0 :     if (st_index < 0)
     320           0 :         return 0;
     321             : 
     322           0 :     if (av_strstart(line, "fmtp:", &p))
     323           0 :         return ff_parse_fmtp(s, s->streams[st_index], data, p, parse_fmtp);
     324             : 
     325           0 :     return 0;
     326             : }
     327             : 
     328             : RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
     329             :     .enc_name           = "MP4V-ES",
     330             :     .codec_type         = AVMEDIA_TYPE_VIDEO,
     331             :     .codec_id           = AV_CODEC_ID_MPEG4,
     332             :     .need_parsing       = AVSTREAM_PARSE_FULL,
     333             :     .priv_data_size     = sizeof(PayloadContext),
     334             :     .parse_sdp_a_line   = parse_sdp_line,
     335             : };
     336             : 
     337             : RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
     338             :     .enc_name           = "mpeg4-generic",
     339             :     .codec_type         = AVMEDIA_TYPE_AUDIO,
     340             :     .codec_id           = AV_CODEC_ID_AAC,
     341             :     .priv_data_size     = sizeof(PayloadContext),
     342             :     .parse_sdp_a_line   = parse_sdp_line,
     343             :     .close              = close_context,
     344             :     .parse_packet       = aac_parse_packet,
     345             : };

Generated by: LCOV version 1.13