diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c index f22086d5a8..167322b9f0 100644 --- a/libavformat/rtpdec_mpeg4.c +++ b/libavformat/rtpdec_mpeg4.c @@ -33,6 +33,8 @@ #include "libavutil/avstring.h" #include "libavcodec/get_bits.h" +#define MAX_AAC_HBR_FRAME_SIZE 8191 + /** Structure listing useful vars to parse RTP packet payload */ struct PayloadContext { int sizelength; @@ -59,8 +61,9 @@ struct PayloadContext { int au_headers_length_bytes; int cur_au_index; - uint8_t buf[RTP_MAX_PACKET_LENGTH]; + uint8_t buf[FFMAX(RTP_MAX_PACKET_LENGTH, MAX_AAC_HBR_FRAME_SIZE)]; int buf_pos, buf_size; + uint32_t timestamp; }; typedef struct AttrNameMap { @@ -168,30 +171,95 @@ static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data, { int ret; + if (!buf) { - if (data->cur_au_index > data->nb_au_headers) + if (data->cur_au_index > data->nb_au_headers) { + av_log(ctx, AV_LOG_ERROR, "Invalid parser state\n"); return AVERROR_INVALIDDATA; - if (data->buf_size - data->buf_pos < data->au_headers[data->cur_au_index].size) + } + if (data->buf_size - data->buf_pos < data->au_headers[data->cur_au_index].size) { + av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n"); return AVERROR_INVALIDDATA; - if ((ret = av_new_packet(pkt, data->au_headers[data->cur_au_index].size)) < 0) + } + if ((ret = av_new_packet(pkt, data->au_headers[data->cur_au_index].size)) < 0) { + av_log(ctx, AV_LOG_ERROR, "Out of memory\n"); return ret; + } memcpy(pkt->data, &data->buf[data->buf_pos], data->au_headers[data->cur_au_index].size); data->buf_pos += data->au_headers[data->cur_au_index].size; pkt->stream_index = st->index; data->cur_au_index++; - return data->cur_au_index < data->nb_au_headers; + + if (data->cur_au_index == data->nb_au_headers) { + data->buf_pos = 0; + return 0; + } + + return 1; } - if (rtp_parse_mp4_au(data, buf, len)) + if (rtp_parse_mp4_au(data, buf, len)) { + av_log(ctx, AV_LOG_ERROR, "Error parsing AU headers\n"); return -1; + } buf += data->au_headers_length_bytes + 2; len -= data->au_headers_length_bytes + 2; + if (data->nb_au_headers == 1 && len < data->au_headers[0].size) { + /* Packet is fragmented */ - if (len < data->au_headers[0].size) + if (!data->buf_pos) { + if (data->au_headers[0].size > MAX_AAC_HBR_FRAME_SIZE) { + av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n"); + return AVERROR_INVALIDDATA; + } + + data->buf_size = data->au_headers[0].size; + data->timestamp = *timestamp; + } + + if (data->timestamp != *timestamp + || data->au_headers[0].size != data->buf_size + || data->buf_pos + len > MAX_AAC_HBR_FRAME_SIZE) { + data->buf_pos = 0; + data->buf_size = 0; + av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n"); + return AVERROR_INVALIDDATA; + } + + memcpy(&data->buf[data->buf_pos], buf, len); + data->buf_pos += len; + + if (!(flags & RTP_FLAG_MARKER)) + return AVERROR(EAGAIN); + + if (data->buf_pos != data->buf_size) { + data->buf_pos = 0; + av_log(ctx, AV_LOG_ERROR, "Missed some packets, discarding frame\n"); + return AVERROR_INVALIDDATA; + } + + data->buf_pos = 0; + ret = av_new_packet(pkt, data->buf_size); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Out of memory\n"); + return ret; + } + pkt->stream_index = st->index; + + memcpy(pkt->data, data->buf, data->buf_size); + + return 0; + } + + if (len < data->au_headers[0].size) { + av_log(ctx, AV_LOG_ERROR, "First AU larger than packet size\n"); return AVERROR_INVALIDDATA; - if ((ret = av_new_packet(pkt, data->au_headers[0].size)) < 0) + } + if ((ret = av_new_packet(pkt, data->au_headers[0].size)) < 0) { + av_log(ctx, AV_LOG_ERROR, "Out of memory\n"); return ret; + } memcpy(pkt->data, buf, data->au_headers[0].size); len -= data->au_headers[0].size; buf += data->au_headers[0].size;