rtpdec: Move AAC depacketization code in rtpdec to a proper payload handler
[libav.git] / libavformat / rtpdec_mpeg4.c
index b301444..8a94d6e 100644 (file)
@@ -30,6 +30,7 @@
 #include "rtpdec_mpeg4.h"
 #include "internal.h"
 #include "libavutil/avstring.h"
+#include "libavcodec/get_bits.h"
 #include <strings.h>
 
 #include "rtsp.h" //XXX remove this dependency
@@ -103,6 +104,87 @@ static int parse_fmtp_config(AVCodecContext * codec, char *value)
     return 0;
 }
 
+static int rtp_parse_mp4_au(RTSPStream *rtsp_st, 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 */
+    au_headers_length = AV_RB16(buf);
+
+    if (au_headers_length > RTP_MAX_PACKET_LENGTH)
+      return -1;
+
+    infos->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);
+
+    /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */
+    au_header_size = infos->sizelength + infos->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;
+    }
+
+    /* 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);
+    }
+
+    infos->nb_au_headers = 1;
+
+    return 0;
+}
+
+
+/* Follows RFC 3640 */
+static int aac_parse_packet(AVFormatContext *ctx,
+                            PayloadContext *data,
+                            AVStream *st,
+                            AVPacket *pkt,
+                            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))
+        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;
+
+    /* 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);
+
+    pkt->stream_index = st->index;
+    return 0;
+}
+
 static int parse_sdp_line(AVFormatContext *s, int st_index,
                           PayloadContext *data, const char *line)
 {
@@ -167,5 +249,5 @@ RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
     .parse_sdp_a_line   = parse_sdp_line,
     .open               = NULL,
     .close              = NULL,
-    .parse_packet       = NULL
+    .parse_packet       = aac_parse_packet
 };