diff mbox series

[FFmpeg-devel,v2] libavformat/rtpdec_mpeg: handle bare ADTS packets with explicit decoder config

Message ID 20211019210244.4130-1-jeffm@jeffm.io
State New
Headers show
Series [FFmpeg-devel,v2] libavformat/rtpdec_mpeg: handle bare ADTS packets with explicit decoder config
Related show

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished

Commit Message

Jeff Mahoney Oct. 19, 2021, 9:02 p.m. UTC
When SDP specifies a decoder config, there may not be any AU headers
provided by the sender.  This can result in rtp_parse_mp4_au failing
and aac_parse_packet reporting "Error parsing AU headers." and no audio
is recovered from the stream.

This commit modifies aac_parse_header to check for an explicit decoder config
set by the sdp parser (e.g. a:fmtp # config=hexvalue). If it has and there
is an ADTS header present, it skips the header and copies the RTP
payload directly as an AAC packet.

This resolves an issue observed with some inexpensive IP cameras.

Signed-off-by: Jeff Mahoney <jeffm@jeffm.io>
---
 libavformat/rtpdec_mpeg4.c | 37 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

Comments

Limin Wang Oct. 20, 2021, 3:05 p.m. UTC | #1
On Tue, Oct 19, 2021 at 05:02:44PM -0400, Jeff Mahoney wrote:

The title should be "avformat/rtpdec_mpeg4: ..." 

> When SDP specifies a decoder config, there may not be any AU headers
> provided by the sender.  This can result in rtp_parse_mp4_au failing
> and aac_parse_packet reporting "Error parsing AU headers." and no audio
> is recovered from the stream.
> 
> This commit modifies aac_parse_header to check for an explicit decoder config
> set by the sdp parser (e.g. a:fmtp # config=hexvalue). If it has and there
> is an ADTS header present, it skips the header and copies the RTP
> payload directly as an AAC packet.
> 
> This resolves an issue observed with some inexpensive IP cameras.

How to test the issue without such IP cameras? 

> 
> Signed-off-by: Jeff Mahoney <jeffm@jeffm.io>
> ---
>  libavformat/rtpdec_mpeg4.c | 37 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 36 insertions(+), 1 deletion(-)
> 
> diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c
> index 34c7950bcc..13d0770dd6 100644
> --- a/libavformat/rtpdec_mpeg4.c
> +++ b/libavformat/rtpdec_mpeg4.c
> @@ -32,6 +32,8 @@
>  #include "libavutil/attributes.h"
>  #include "libavutil/avstring.h"
>  #include "libavcodec/get_bits.h"
> +#include "libavcodec/adts_header.h"
> +#include "libavcodec/adts_parser.h"
>  
>  #define MAX_AAC_HBR_FRAME_SIZE 8191
>  
> @@ -176,7 +178,7 @@ static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
>                              int flags)
>  {
>      int ret;
> -
> +    AVCodecParameters *par = st->codecpar;
>  
>      if (!buf) {
>          if (data->cur_au_index > data->nb_au_headers) {
> @@ -204,6 +206,39 @@ static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
>          return 1;
>      }
>  
> +    /* Check for an explicit decoder config (e.g. SDP a:fmtp... config=) */
> +    if (par->extradata && len > 7) {

7 is better to use AV_AAC_ADTS_HEADER_SIZE like the following.

> +        AACADTSHeaderInfo *header;
> +
> +        /*
> +         * Check for ADTS header
> +         * If present skip the header and copy the entire payload as AAC data
> +         */
> +        ret = avpriv_adts_header_parse(&header, buf, len);

need add adts_header dependency for rtp demuer. 


> +        if (!ret) {
> +            buf += AV_AAC_ADTS_HEADER_SIZE;
> +            len -= AV_AAC_ADTS_HEADER_SIZE;
> +
> +            /* Skip 16-bit CRC if present */
> +            if (!header->crc_absent) {
> +                buf += 2;
> +                len -= 2;
> +            }
> +            av_free(header);
> +
> +            ret = av_new_packet(pkt, len);
> +            if (ret < 0) {
> +                av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
> +                return ret;
> +            }
> +
> +            memcpy(pkt->data, buf, len);
> +            pkt->stream_index = st->index;
> +
> +            return 0;
> +        }
> +    }
> +
>      if (rtp_parse_mp4_au(data, buf, len)) {
>          av_log(ctx, AV_LOG_ERROR, "Error parsing AU headers\n");
>          return -1;
> -- 
> 2.33.1
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c
index 34c7950bcc..13d0770dd6 100644
--- a/libavformat/rtpdec_mpeg4.c
+++ b/libavformat/rtpdec_mpeg4.c
@@ -32,6 +32,8 @@ 
 #include "libavutil/attributes.h"
 #include "libavutil/avstring.h"
 #include "libavcodec/get_bits.h"
+#include "libavcodec/adts_header.h"
+#include "libavcodec/adts_parser.h"
 
 #define MAX_AAC_HBR_FRAME_SIZE 8191
 
@@ -176,7 +178,7 @@  static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
                             int flags)
 {
     int ret;
-
+    AVCodecParameters *par = st->codecpar;
 
     if (!buf) {
         if (data->cur_au_index > data->nb_au_headers) {
@@ -204,6 +206,39 @@  static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
         return 1;
     }
 
+    /* Check for an explicit decoder config (e.g. SDP a:fmtp... config=) */
+    if (par->extradata && len > 7) {
+        AACADTSHeaderInfo *header;
+
+        /*
+         * Check for ADTS header
+         * If present skip the header and copy the entire payload as AAC data
+         */
+        ret = avpriv_adts_header_parse(&header, buf, len);
+        if (!ret) {
+            buf += AV_AAC_ADTS_HEADER_SIZE;
+            len -= AV_AAC_ADTS_HEADER_SIZE;
+
+            /* Skip 16-bit CRC if present */
+            if (!header->crc_absent) {
+                buf += 2;
+                len -= 2;
+            }
+            av_free(header);
+
+            ret = av_new_packet(pkt, len);
+            if (ret < 0) {
+                av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
+                return ret;
+            }
+
+            memcpy(pkt->data, buf, len);
+            pkt->stream_index = st->index;
+
+            return 0;
+        }
+    }
+
     if (rtp_parse_mp4_au(data, buf, len)) {
         av_log(ctx, AV_LOG_ERROR, "Error parsing AU headers\n");
         return -1;