rtpmp4gdepay: detect broken senders who send AAC with ADTS frames
authorTim-Philipp Müller <tim@centricular.com>
Fri, 21 Sep 2018 18:47:44 +0000 (19:47 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Wed, 26 Sep 2018 11:25:24 +0000 (12:25 +0100)
Strip ADTS headers if we detect any, apparently some Sony cameras
send AAC with ADTS headers. We could also change the stream-format
in the output caps, but that would be unexpected to pipeline builders
and would not exactly be backwards compatible.

gst/rtp/gstrtpmp4gdepay.c
gst/rtp/gstrtpmp4gdepay.h

index 1709010..5d9d2cd 100644 (file)
@@ -233,11 +233,14 @@ gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
     clock_rate = 90000;         /* default */
   depayload->clock_rate = clock_rate;
 
+  rtpmp4gdepay->check_adts = FALSE;
+
   if ((str = gst_structure_get_string (structure, "media"))) {
     if (strcmp (str, "audio") == 0) {
       srccaps = gst_caps_new_simple ("audio/mpeg",
           "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, "raw",
           NULL);
+      rtpmp4gdepay->check_adts = TRUE;
     } else if (strcmp (str, "video") == 0) {
       srccaps = gst_caps_new_simple ("video/mpeg",
           "mpegversion", G_TYPE_INT, 4,
@@ -664,11 +667,30 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
         gst_adapter_push (rtpmp4gdepay->adapter, outbuf);
 
         if (M) {
+          guint32 v = 0;
           guint avail;
 
           /* packet is complete, flush */
           avail = gst_adapter_available (rtpmp4gdepay->adapter);
 
+          /* Some broken senders send ADTS headers (e.g. some Sony cameras).
+           * Try to detect those and skip them (still needs config set), but
+           * don't check every frame, only the first (unless we detect ADTS) */
+          if (rtpmp4gdepay->check_adts && avail >= 7) {
+            if (gst_adapter_masked_scan_uint32_peek (rtpmp4gdepay->adapter,
+                    0xfffe0000, 0xfff00000, 0, 4, &v) == 0) {
+              guint adts_hdr_len = (((v >> 16) & 0x1) == 0) ? 9 : 7;
+              if (avail > adts_hdr_len) {
+                GST_WARNING_OBJECT (rtpmp4gdepay, "Detected ADTS header of "
+                    "%u bytes, skipping", adts_hdr_len);
+                gst_adapter_flush (rtpmp4gdepay->adapter, adts_hdr_len);
+                avail -= adts_hdr_len;
+              }
+            } else {
+              rtpmp4gdepay->check_adts = FALSE;
+            }
+          }
+
           outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail);
 
           /* copy some of the fields we calculated above on the buffer. We also
index 5d5997a..d4d9330 100644 (file)
@@ -67,6 +67,8 @@ struct _GstRtpMP4GDepay
   guint32 prev_rtptime;
   guint prev_AU_num;
 
+  gboolean check_adts; /* check for ADTS headers */
+
   GQueue *packets;
   
   GstAdapter *adapter;