[FFmpeg-devel] [PATCH 2/3] avformat/rtpdec_mpeg12: add robust MPEG audio depacketization (RFC 5219)
Thomas Volkert
silvo at gmx.net
Sat Feb 14 17:56:49 CET 2015
On 02/13/2015 10:51 PM, Gilles Chanteperdrix wrote:
> Signed-off-by: Gilles Chanteperdrix <gilles.chanteperdrix at xenomai.org>
> ---
> Changelog | 1 +
> libavcodec/mpegaudio_parser.c | 14 ++-
> libavcodec/mpegaudiodecheader.c | 3 +-
> libavformat/rtpdec.c | 1 +
> libavformat/rtpdec_formats.h | 1 +
> libavformat/rtpdec_mpeg12.c | 204 ++++++++++++++++++++++++++++++++++++++++
> libavformat/version.h | 4 +-
> 7 files changed, 223 insertions(+), 5 deletions(-)
>
> diff --git a/Changelog b/Changelog
> index c663d5e..775fc79 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -23,6 +23,7 @@ version <next>:
> - Changed default DNxHD colour range in QuickTime .mov derivatives to mpeg range
> - ported softpulldown filter from libmpcodecs as repeatfields filter
> - dcshift filter
> +- RTP parser for loss tolerant payload format for MP3 audio (RFC 5219)
>
>
> version 2.5:
> diff --git a/libavcodec/mpegaudio_parser.c b/libavcodec/mpegaudio_parser.c
> index 79dbf63..42f4706 100644
> --- a/libavcodec/mpegaudio_parser.c
> +++ b/libavcodec/mpegaudio_parser.c
> @@ -64,7 +64,7 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
> }else{
> while(i<buf_size){
> int ret, sr, channels, bit_rate, frame_size;
> - enum AVCodecID codec_id;
> + enum AVCodecID codec_id = avctx->codec_id;
>
> state= (state<<8) + buf[i++];
>
> @@ -90,6 +90,16 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
> avctx->bit_rate += (bit_rate - avctx->bit_rate) / (s->header_count - header_threshold);
> }
> }
> +
> + if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) {
> + s->frame_size = 0;
> + next = buf_size;
> + } else if (codec_id == AV_CODEC_ID_MP3ADU) {
> + av_log(avctx, AV_LOG_ERROR,
> + "MP3ADU full parser not implemented");
> + return AVERROR_PATCHWELCOME;
> + }
> +
> break;
> }
> }
> @@ -110,7 +120,7 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
>
>
> AVCodecParser ff_mpegaudio_parser = {
> - .codec_ids = { AV_CODEC_ID_MP1, AV_CODEC_ID_MP2, AV_CODEC_ID_MP3 },
> + .codec_ids = { AV_CODEC_ID_MP1, AV_CODEC_ID_MP2, AV_CODEC_ID_MP3, AV_CODEC_ID_MP3ADU },
> .priv_data_size = sizeof(MpegAudioParseContext),
> .parser_parse = mpegaudio_parse,
> .parser_close = ff_parse_close,
> diff --git a/libavcodec/mpegaudiodecheader.c b/libavcodec/mpegaudiodecheader.c
> index 5db1957..6af6e4b 100644
> --- a/libavcodec/mpegaudiodecheader.c
> +++ b/libavcodec/mpegaudiodecheader.c
> @@ -134,7 +134,8 @@ int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, in
> break;
> default:
> case 3:
> - *codec_id = AV_CODEC_ID_MP3;
> + if (*codec_id != AV_CODEC_ID_MP3ADU)
> + *codec_id = AV_CODEC_ID_MP3;
> if (s->lsf)
> *frame_size = 576;
> else
> diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
> index 4ff209c..c632340 100644
> --- a/libavformat/rtpdec.c
> +++ b/libavformat/rtpdec.c
> @@ -89,6 +89,7 @@ void ff_register_rtp_dynamic_payload_handlers(void)
> ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler);
> ff_register_dynamic_payload_handler(&ff_mp4v_es_dynamic_handler);
> ff_register_dynamic_payload_handler(&ff_mpeg_audio_dynamic_handler);
> + ff_register_dynamic_payload_handler(&ff_mpeg_audio_robust_dynamic_handler);
> ff_register_dynamic_payload_handler(&ff_mpeg_video_dynamic_handler);
> ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler);
> ff_register_dynamic_payload_handler(&ff_mpegts_dynamic_handler);
> diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
> index 87e316f..da22d70 100644
> --- a/libavformat/rtpdec_formats.h
> +++ b/libavformat/rtpdec_formats.h
> @@ -52,6 +52,7 @@ extern RTPDynamicProtocolHandler ff_jpeg_dynamic_handler;
> extern RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler;
> extern RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler;
> extern RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler;
> +extern RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler;
> extern RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler;
> extern RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler;
> extern RTPDynamicProtocolHandler ff_mpegts_dynamic_handler;
> diff --git a/libavformat/rtpdec_mpeg12.c b/libavformat/rtpdec_mpeg12.c
> index d73ff1e..d99c507 100644
> --- a/libavformat/rtpdec_mpeg12.c
> +++ b/libavformat/rtpdec_mpeg12.c
> @@ -2,6 +2,9 @@
> * Common code for the RTP depacketization of MPEG-1/2 formats.
> * Copyright (c) 2002 Fabrice Bellard
> *
> + * RTP parser for loss tolerant payload format for MP3 audio (RFC 5219)
> + * Copyright (c) 2015 Gilles Chanteperdrix <gch at xenomai.org>
> + *
> * This file is part of FFmpeg.
> *
> * FFmpeg is free software; you can redistribute it and/or
> @@ -23,6 +26,8 @@
> #include "libavutil/intreadwrite.h"
> #include "rtpdec_formats.h"
>
> +#define RTP_MPA_PAYLOAD_HEADER_SIZE 1
> +
> static av_cold int mpeg_init(AVFormatContext *ctx, int st_index, PayloadContext *data)
> {
> if (st_index < 0)
> @@ -71,3 +76,202 @@ RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler = {
> .parse_packet = mpeg_parse_packet,
> .static_payload_id = 32,
> };
> +
> +/* MPA-ROBUST, RFC 5219 */
> +struct PayloadContext {
> + unsigned adu_size;
> + unsigned cur_size;
> + uint32_t timestamp;
> + uint8_t *split_buf;
> + int split_pos, split_buf_size, split_pkts;
> + AVIOContext *fragment;
> +};
> +
> +static av_cold int mpa_robust_init(AVFormatContext *ctx, int st_index,
> + PayloadContext *data)
> +{
> + if (st_index < 0)
> + return 0;
> + ctx->streams[st_index]->need_parsing = AVSTREAM_PARSE_HEADERS;
> + return 0;
> +}
> +
> +static PayloadContext *mpa_robust_new_context(void)
> +{
> + return av_mallocz(sizeof(PayloadContext));
> +}
> +
> +static inline void free_fragment_if_needed(PayloadContext *data)
> +{
> + if (data->fragment) {
> + uint8_t *p;
> + avio_close_dyn_buf(data->fragment, &p);
> + av_free(p);
> + data->fragment = NULL;
> + }
> +}
> +
> +static void mpa_robust_free_context(PayloadContext *data)
> +{
> + free_fragment_if_needed(data);
> + av_free(data);
> +}
> +
> +static int mpa_robust_parse_rtp_header(AVFormatContext *ctx,
> + const uint8_t *buf, int len,
> + unsigned *adu_size, unsigned *cont)
> +{
> + unsigned header_size;
> +
> + if (len < RTP_MPA_PAYLOAD_HEADER_SIZE + 1) {
> + av_log(ctx, AV_LOG_ERROR, "Invalid %d bytes packet\n", len);
> + return AVERROR_INVALIDDATA;
> + }
> +
> + *cont = !!(buf[0] & 0x80);
> + if (!(buf[0] & 0x40)) {
> + header_size = 1;
> + *adu_size = buf[0] & ~0xc0;
> + } else {
> + header_size = 2;
> + *adu_size = AV_RB16(buf) & ~0xc000;
> + }
> +
> + return header_size;
> +}
> +
> +static int mpa_robust_parse_packet(AVFormatContext *ctx, PayloadContext *data,
> + AVStream *st, AVPacket *pkt,
> + uint32_t *timestamp, const uint8_t *buf,
> + int len, uint16_t seq, int flags)
> +{
> + unsigned adu_size, continuation;
> + int err, header_size;
> +
> + if (!buf) {
> + buf = &data->split_buf[data->split_pos];
> + len = data->split_buf_size - data->split_pos;
> +
> + header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size,
> + &continuation);
> + if (header_size < 0) {
> + av_freep(&data->split_buf);
> + return header_size;
> + }
> + buf += header_size;
> + len -= header_size;
> +
> + if (continuation || adu_size > len) {
> + av_freep(&data->split_buf);
> + av_log(ctx, AV_LOG_ERROR, "Invalid frame\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + if (av_new_packet(pkt, adu_size)) {
> + av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
> + return AVERROR(ENOMEM);
> + }
> +
> + pkt->stream_index = st->index;
> + memcpy(pkt->data, buf, adu_size);
> +
> + data->split_pos = (buf - data->split_buf) + adu_size;
> +
> + if (data->split_pos == data->split_buf_size) {
> + av_freep(&data->split_buf);
> + return 0;
> + }
> +
> + return 1;
> + }
> +
> +
> + header_size = mpa_robust_parse_rtp_header(ctx, buf, len, &adu_size,
> + &continuation);
> + if (header_size < 0)
> + return header_size;
> +
> + buf += header_size;
> + len -= header_size;
> +
> + if (!continuation && adu_size <= len) {
> + /* One or more complete frames */
> +
> + if (av_new_packet(pkt, adu_size)) {
> + av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
> + return AVERROR(ENOMEM);
> + }
> +
> + pkt->stream_index = st->index;
> + memcpy(pkt->data, buf, adu_size);
> +
> + buf += adu_size;
> + len -= adu_size;
> + if (len) {
> + data->split_buf_size = len;
> + data->split_buf = av_malloc(data->split_buf_size);
> + data->split_pos = 0;
> + if (!data->split_buf) {
> + av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
> + av_free_packet(pkt);
> + return AVERROR(ENOMEM);
> + }
> + memcpy(data->split_buf, buf, data->split_buf_size);
> + return 1;
> + }
> + return 0;
> + } else if (!continuation) { /* && adu_size > len */
> + /* First fragment */
> + free_fragment_if_needed(data);
> +
> + data->adu_size = adu_size;
> + data->cur_size = len;
> + data->timestamp = *timestamp;
> +
> + err = avio_open_dyn_buf(&data->fragment);
> + if (err < 0)
> + return err;
> +
> + avio_write(data->fragment, buf, len);
> + return AVERROR(EAGAIN);
> + }
> + /* else continuation == 1 */
> +
> + /* Fragment other than first */
> + if (!data->fragment) {
> + av_log(ctx, AV_LOG_WARNING,
> + "Received packet without a start fragment; dropping.\n");
> + return AVERROR(EAGAIN);
> + }
> + if (adu_size = data->adu_size ||
> + data->timestamp != *timestamp) {
> + free_fragment_if_needed(data);
> + av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + avio_write(data->fragment, buf, len);
> + data->cur_size += len;
> +
> + if (data->cur_size < data->adu_size)
> + return AVERROR(EAGAIN);
> +
> + err = ff_rtp_finalize_packet(pkt, &data->fragment, st->index);
> + if (err < 0) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Error occurred when getting fragment buffer.");
> + return err;
> + }
> +
> + return 0;
> +}
> +
> +RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler = {
> + .codec_type = AVMEDIA_TYPE_AUDIO,
> + .codec_id = AV_CODEC_ID_MP3ADU,
> + .init = mpa_robust_init,
> + .alloc = mpa_robust_new_context,
> + .free = mpa_robust_free_context,
> + .parse_packet = mpa_robust_parse_packet,
> + .enc_name = "mpa-robust",
> +};
> diff --git a/libavformat/version.h b/libavformat/version.h
> index edad275..84749ec 100644
> --- a/libavformat/version.h
> +++ b/libavformat/version.h
> @@ -30,8 +30,8 @@
> #include "libavutil/version.h"
>
Okay.
> #define LIBAVFORMAT_VERSION_MAJOR 56
> -#define LIBAVFORMAT_VERSION_MINOR 19
> -#define LIBAVFORMAT_VERSION_MICRO 101
> +#define LIBAVFORMAT_VERSION_MINOR 20
> +#define LIBAVFORMAT_VERSION_MICRO 102
In this case it should be:
+#define LIBAVFORMAT_VERSION_MINOR 20
+#define LIBAVFORMAT_VERSION_MICRO 100
My comment was maybe a bit misleading. But I think this can be fixed when the patch gets committed.
>
> #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
> LIBAVFORMAT_VERSION_MINOR, \
Best regards,
Thomas.
More information about the ffmpeg-devel
mailing list