mp4adepay: improve timestamps on outgoing packets
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 31 Dec 2010 12:57:05 +0000 (13:57 +0100)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 31 Dec 2010 12:57:05 +0000 (13:57 +0100)
Improve parsing of the samplerate.
Parse the framelen so that we can calculate timestamps.
When interpollate the incomming timestamp on outgoing buffers when there are
multiple subframes.

fixes #625825

gst/rtp/gstrtpmp4adepay.c
gst/rtp/gstrtpmp4adepay.h

index 836ff9f095d0eb0f00bc97442e2dbbbe625a45d6..394fc0d288b7f0e66001100997cf2708cee079ee 100644 (file)
@@ -21,6 +21,7 @@
 #  include "config.h"
 #endif
 
+#include <gst/base/gstbitreader.h>
 #include <gst/rtp/gstrtpbuffer.h>
 
 #include <string.h>
@@ -128,6 +129,10 @@ gst_rtp_mp4a_depay_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000,
+  44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
+};
+
 static gboolean
 gst_rtp_mp4a_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
 {
@@ -165,10 +170,9 @@ gst_rtp_mp4a_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
       guint8 *data;
       guint size;
       gint i;
-      guint sr_idx;
-      static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000,
-        44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
-      };
+      guint32 rate;
+      guint8 obj_type, sr_idx, channels;
+      GstBitReader br;
 
       buffer = gst_value_get_buffer (&v);
       gst_buffer_ref (buffer);
@@ -210,22 +214,68 @@ gst_rtp_mp4a_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
       for (i = 0; i < size; i++) {
         data[i] = ((data[i + 1] & 1) << 7) | ((data[i + 2] & 0xfe) >> 1);
       }
+      /* ignore remaining bit, we're only interested in full bytes */
+      GST_BUFFER_SIZE (buffer) = size;
+
+      gst_bit_reader_init (&br, data, size);
+
+      /* any object type is fine, we need to copy it to the profile-level-id field. */
+      if (!gst_bit_reader_get_bits_uint8 (&br, &obj_type, 5))
+        goto bad_config;
+      if (obj_type == 0) {
+        GST_WARNING_OBJECT (depayload, "invalid object type 0");
+        goto bad_config;
+      }
+
+      if (!gst_bit_reader_get_bits_uint8 (&br, &sr_idx, 4))
+        goto bad_config;
+      if (sr_idx > 12 && sr_idx != 15) {
+        GST_WARNING_OBJECT (depayload, "invalid sample rate index %d", sr_idx);
+        goto bad_config;
+      }
+      GST_LOG_OBJECT (rtpmp4adepay, "sample rate index %u", sr_idx);
 
-      /* grab and set sampling rate */
-      sr_idx = ((data[0] & 0x07) << 1) | ((data[1] & 0x80) >> 7);
-      if (sr_idx < G_N_ELEMENTS (aac_sample_rates)) {
-        gst_caps_set_simple (srccaps,
-            "rate", G_TYPE_INT, (gint) aac_sample_rates[sr_idx], NULL);
-        GST_DEBUG_OBJECT (depayload, "sampling rate from stream-config %u",
-            aac_sample_rates[sr_idx]);
+      if (!gst_bit_reader_get_bits_uint8 (&br, &channels, 4))
+        goto bad_config;
+      if (channels > 7) {
+        GST_WARNING_OBJECT (depayload, "invalid channels %u", (guint) channels);
+        goto bad_config;
+      }
+
+      /* rtp rate depends on sampling rate of the audio */
+      if (sr_idx == 15) {
+        /* index of 15 means we get the rate in the next 24 bits */
+        if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
+          goto bad_config;
       } else {
-        GST_WARNING_OBJECT (depayload, "Invalid sample rate index %u", sr_idx);
+        /* else use the rate from the table */
+        rate = aac_sample_rates[sr_idx];
       }
 
-      /* ignore remaining bit, we're only interested in full bytes */
-      GST_BUFFER_SIZE (buffer) = size;
+      rtpmp4adepay->frame_len = 1024;
+
+      switch (obj_type) {
+        case 1:
+        case 2:
+        case 3:
+        case 4:
+        case 6:
+        case 7:
+        {
+          guint8 frameLenFlag = 0;
+
+          if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
+            if (frameLenFlag)
+              rtpmp4adepay->frame_len = 960;
+          break;
+        }
+        default:
+          break;
+      }
 
       gst_caps_set_simple (srccaps,
+          "channels", G_TYPE_INT, (gint) channels,
+          "rate", G_TYPE_INT, (gint) rate,
           "codec_data", GST_TYPE_BUFFER, buffer, NULL);
       gst_buffer_unref (buffer);
     } else {
@@ -254,6 +304,7 @@ gst_rtp_mp4a_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
   outbuf = gst_rtp_buffer_get_payload_buffer (buf);
 
+  gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS);
   gst_adapter_push (rtpmp4adepay->adapter, outbuf);
 
   /* RTP marker bit indicates the last packet of the AudioMuxElement => create
@@ -315,11 +366,19 @@ gst_rtp_mp4a_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
       data += skip;
       avail -= skip;
 
+      if (offset > 0 && timestamp != -1 && depayload->clock_rate != 0) {
+        timestamp +=
+            gst_util_uint64_scale_int (offset, GST_SECOND,
+            depayload->clock_rate);
+      }
+
       GST_BUFFER_TIMESTAMP (tmp) = timestamp;
       gst_base_rtp_depayload_push (depayload, tmp);
 
-      /* only apply the timestamp for the first buffer */
-      timestamp = -1;
+      /* calculate offsets for next buffers */
+      if (rtpmp4adepay->frame_len) {
+        offset += rtpmp4adepay->frame_len;
+      }
     }
 
     /* just a check that lengths match */
@@ -355,6 +414,8 @@ gst_rtp_mp4a_depay_change_state (GstElement * element,
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       gst_adapter_clear (rtpmp4adepay->adapter);
+      rtpmp4adepay->frame_len = 0;
+      rtpmp4adepay->numSubFrames = 0;
       break;
     default:
       break;
index 16c20b7f7ab5c25510c1edcad918f3247e4da1b5..33622fcaed59f6546e1be53ee70e3e841af0348f 100644 (file)
@@ -44,6 +44,7 @@ struct _GstRtpMP4ADepay
   GstBaseRTPDepayload depayload;
   GstAdapter *adapter;
   guint8 numSubFrames;
+  guint frame_len;
 };
 
 struct _GstRtpMP4ADepayClass