]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtpdec_mpeg4.c
nutenc: fix a memleak
[ffmpeg] / libavformat / rtpdec_mpeg4.c
index 8a94d6ed4160d4680e8e26056e4c82a0aed6accb..5498d1c46bdc03c3fc274e6c8c4a8b711db56a41 100644 (file)
  * @author Romain Degez
  */
 
-#include "rtpdec_mpeg4.h"
+#include "rtpdec_formats.h"
 #include "internal.h"
 #include "libavutil/avstring.h"
 #include "libavcodec/get_bits.h"
 #include <strings.h>
 
-#include "rtsp.h" //XXX remove this dependency
-
-/* return the length and optionally the data */
-static int hex_to_data(uint8_t *data, const char *p)
+/** Structure listing useful vars to parse RTP packet payload*/
+struct PayloadContext
 {
-    int c, len, v;
-
-    len = 0;
-    v = 1;
-    for (;;) {
-        p += strspn(p, SPACE_CHARS);
-        if (*p == '\0')
-            break;
-        c = toupper((unsigned char) *p++);
-        if (c >= '0' && c <= '9')
-            c = c - '0';
-        else if (c >= 'A' && c <= 'F')
-            c = c - 'A' + 10;
-        else
-            break;
-        v = (v << 4) | c;
-        if (v & 0x100) {
-            if (data)
-                data[len] = v;
-            len++;
-            v = 1;
-        }
-    }
-    return len;
-}
+    int sizelength;
+    int indexlength;
+    int indexdeltalength;
+    int profile_level_id;
+    int streamtype;
+    int objecttype;
+    char *mode;
+
+    /** mpeg 4 AU headers */
+    struct AUHeaders {
+        int size;
+        int index;
+        int cts_flag;
+        int cts;
+        int dts_flag;
+        int dts;
+        int rap_flag;
+        int streamstate;
+    } *au_headers;
+    int au_headers_allocated;
+    int nb_au_headers;
+    int au_headers_length_bytes;
+    int cur_au_index;
+};
 
 typedef struct {
     const char *str;
@@ -76,43 +73,57 @@ typedef struct {
 static const AttrNameMap attr_names[]=
 {
     { "SizeLength",       ATTR_NAME_TYPE_INT,
-      offsetof(RTPPayloadData, sizelength) },
+      offsetof(PayloadContext, sizelength) },
     { "IndexLength",      ATTR_NAME_TYPE_INT,
-      offsetof(RTPPayloadData, indexlength) },
+      offsetof(PayloadContext, indexlength) },
     { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
-      offsetof(RTPPayloadData, indexdeltalength) },
+      offsetof(PayloadContext, indexdeltalength) },
     { "profile-level-id", ATTR_NAME_TYPE_INT,
-      offsetof(RTPPayloadData, profile_level_id) },
+      offsetof(PayloadContext, profile_level_id) },
     { "StreamType",       ATTR_NAME_TYPE_INT,
-      offsetof(RTPPayloadData, streamtype) },
+      offsetof(PayloadContext, streamtype) },
     { "mode",             ATTR_NAME_TYPE_STR,
-      offsetof(RTPPayloadData, mode) },
+      offsetof(PayloadContext, mode) },
     { NULL, -1, -1 },
 };
 
+static PayloadContext *new_context(void)
+{
+    return av_mallocz(sizeof(PayloadContext));
+}
+
+static void free_context(PayloadContext * data)
+{
+    int i;
+    for (i = 0; i < data->nb_au_headers; i++) {
+         /* according to rtp_parse_mp4_au, we treat multiple
+          * au headers as one, so nb_au_headers is always 1.
+          * loop anyway in case this changes.
+          * (note: changes done carelessly might lead to a double free)
+          */
+       av_free(&data->au_headers[i]);
+    }
+    av_free(data->mode);
+    av_free(data);
+}
+
 static int parse_fmtp_config(AVCodecContext * codec, char *value)
 {
     /* decode the hexa encoded parameter */
-    int len = hex_to_data(NULL, value);
-    if (codec->extradata)
-        av_free(codec->extradata);
+    int len = ff_hex_to_data(NULL, value);
+    av_free(codec->extradata);
     codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
     if (!codec->extradata)
         return AVERROR(ENOMEM);
     codec->extradata_size = len;
-    hex_to_data(codec->extradata, value);
+    ff_hex_to_data(codec->extradata, value);
     return 0;
 }
 
-static int rtp_parse_mp4_au(RTSPStream *rtsp_st, const uint8_t *buf)
+static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf)
 {
     int au_headers_length, au_header_size, i;
     GetBitContext getbitcontext;
-    RTPPayloadData *infos;
-
-    infos =  &rtsp_st->rtp_payload_data;
-    if (infos == NULL)
-        return -1;
 
     /* decode the first 2 bytes where the AUHeader sections are stored
        length in bits */
@@ -121,36 +132,36 @@ static int rtp_parse_mp4_au(RTSPStream *rtsp_st, const uint8_t *buf)
     if (au_headers_length > RTP_MAX_PACKET_LENGTH)
       return -1;
 
-    infos->au_headers_length_bytes = (au_headers_length + 7) / 8;
+    data->au_headers_length_bytes = (au_headers_length + 7) / 8;
 
     /* skip AU headers length section (2 bytes) */
     buf += 2;
 
-    init_get_bits(&getbitcontext, buf, infos->au_headers_length_bytes * 8);
+    init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
 
     /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */
-    au_header_size = infos->sizelength + infos->indexlength;
+    au_header_size = data->sizelength + data->indexlength;
     if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
         return -1;
 
-    infos->nb_au_headers = au_headers_length / au_header_size;
-    if (!infos->au_headers || infos->au_headers_allocated < infos->nb_au_headers) {
-        av_free(infos->au_headers);
-        infos->au_headers = av_malloc(sizeof(struct AUHeaders) * infos->nb_au_headers);
-        infos->au_headers_allocated = infos->nb_au_headers;
+    data->nb_au_headers = au_headers_length / au_header_size;
+    if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
+        av_free(data->au_headers);
+        data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
+        data->au_headers_allocated = data->nb_au_headers;
     }
 
     /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving)
        In my test, the FAAD decoder does not behave correctly when sending each AU one by one
        but does when sending the whole as one big packet...  */
-    infos->au_headers[0].size = 0;
-    infos->au_headers[0].index = 0;
-    for (i = 0; i < infos->nb_au_headers; ++i) {
-        infos->au_headers[0].size += get_bits_long(&getbitcontext, infos->sizelength);
-        infos->au_headers[0].index = get_bits_long(&getbitcontext, infos->indexlength);
+    data->au_headers[0].size = 0;
+    data->au_headers[0].index = 0;
+    for (i = 0; i < data->nb_au_headers; ++i) {
+        data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength);
+        data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength);
     }
 
-    infos->nb_au_headers = 1;
+    data->nb_au_headers = 1;
 
     return 0;
 }
@@ -164,72 +175,59 @@ static int aac_parse_packet(AVFormatContext *ctx,
                             uint32_t *timestamp,
                             const uint8_t *buf, int len, int flags)
 {
-    RTSPStream *rtsp_st = st->priv_data;
-    RTPPayloadData *infos;
-
-    if (rtp_parse_mp4_au(rtsp_st, buf))
+    if (rtp_parse_mp4_au(data, buf))
         return -1;
 
-    infos = &rtsp_st->rtp_payload_data;
-    if (infos == NULL)
-        return -1;
-    buf += infos->au_headers_length_bytes + 2;
-    len -= infos->au_headers_length_bytes + 2;
+    buf += data->au_headers_length_bytes + 2;
+    len -= data->au_headers_length_bytes + 2;
 
     /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define
                     one au_header */
-    av_new_packet(pkt, infos->au_headers[0].size);
-    memcpy(pkt->data, buf, infos->au_headers[0].size);
+    av_new_packet(pkt, data->au_headers[0].size);
+    memcpy(pkt->data, buf, data->au_headers[0].size);
 
     pkt->stream_index = st->index;
     return 0;
 }
 
-static int parse_sdp_line(AVFormatContext *s, int st_index,
-                          PayloadContext *data, const char *line)
+static int parse_fmtp(AVStream *stream, PayloadContext *data,
+                      char *attr, char *value)
 {
-    const char *p;
-    char value[4096], attr[25];
-    int res = 0, i;
-    AVStream *st = s->streams[st_index];
-    RTSPStream *rtsp_st = st->priv_data;
-    AVCodecContext* codec = st->codec;
-    RTPPayloadData *rtp_payload_data = &rtsp_st->rtp_payload_data;
-
-    if (av_strstart(line, "fmtp:", &p)) {
-        // remove protocol identifier
-        while (*p && *p == ' ') p++; // strip spaces
-        while (*p && *p != ' ') p++; // eat protocol identifier
-        while (*p && *p == ' ') p++; // strip trailing spaces
-
-        while (ff_rtsp_next_attr_and_value(&p,
-                                           attr, sizeof(attr),
-                                           value, sizeof(value))) {
-            if (!strcmp(attr, "config")) {
-                res = parse_fmtp_config(codec, value);
-
-                if (res < 0)
-                    return res;
-            }
+    AVCodecContext *codec = stream->codec;
+    int res, i;
 
-            if (codec->codec_id == CODEC_ID_AAC) {
-                /* Looking for a known attribute */
-                for (i = 0; attr_names[i].str; ++i) {
-                    if (!strcasecmp(attr, attr_names[i].str)) {
-                        if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
-                            *(int *)((char *)rtp_payload_data +
-                                attr_names[i].offset) = atoi(value);
-                        } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
-                            *(char **)((char *)rtp_payload_data +
-                                attr_names[i].offset) = av_strdup(value);
-                    }
-                }
+    if (!strcmp(attr, "config")) {
+        res = parse_fmtp_config(codec, value);
+
+        if (res < 0)
+            return res;
+    }
+
+    if (codec->codec_id == CODEC_ID_AAC) {
+        /* Looking for a known attribute */
+        for (i = 0; attr_names[i].str; ++i) {
+            if (!strcasecmp(attr, attr_names[i].str)) {
+                if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
+                    *(int *)((char *)data+
+                        attr_names[i].offset) = atoi(value);
+                } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
+                    *(char **)((char *)data+
+                        attr_names[i].offset) = av_strdup(value);
             }
         }
     }
-
     return 0;
+}
 
+static int parse_sdp_line(AVFormatContext *s, int st_index,
+                          PayloadContext *data, const char *line)
+{
+    const char *p;
+
+    if (av_strstart(line, "fmtp:", &p))
+        return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
+
+    return 0;
 }
 
 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
@@ -247,7 +245,7 @@ RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
     .codec_type         = AVMEDIA_TYPE_AUDIO,
     .codec_id           = CODEC_ID_AAC,
     .parse_sdp_a_line   = parse_sdp_line,
-    .open               = NULL,
-    .close              = NULL,
+    .open               = new_context,
+    .close              = free_context,
     .parse_packet       = aac_parse_packet
 };