qtmux: add ima adpcm support
authorMichael Smith <msmith@songbirdnest.com>
Wed, 9 Dec 2009 01:55:56 +0000 (17:55 -0800)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 12 Apr 2011 19:32:14 +0000 (20:32 +0100)
gst/quicktime/atoms.c
gst/quicktime/atoms.h
gst/quicktime/fourcc.h
gst/quicktime/gstqtmux.c
gst/quicktime/gstqtmuxmap.c

index 5d73ae2..79117cc 100644 (file)
@@ -3337,3 +3337,74 @@ build_SMI_atom (const GstBuffer * seqh)
   gst_buffer_unref (buf);
   return res;
 }
+
+static AtomInfo *
+build_ima_adpcm_atom (gint channels, gint rate, gint blocksize)
+{
+  AtomData *atom_data;
+  GstBuffer *buf;
+  guint8 *data;
+  const gint ima_adpcm_atom_size = 20;
+  guint32 fourcc;
+  gint samplesperblock;
+  gint bytespersec;
+
+  /* The FOURCC for WAV codecs in QT is 'ms' followed by the 16 bit wave codec
+     identifier. Note that the identifier here is big-endian, but when used
+     within the WAVE header (below), it's little endian. */
+  fourcc = MS_WAVE_FOURCC (0x11);
+
+  buf = gst_buffer_new_and_alloc (ima_adpcm_atom_size);
+  data = GST_BUFFER_DATA (buf);
+
+  /* This atom's content is a WAVE header, including 2 bytes of extra data.
+     Note that all of this is little-endian, unlike most stuff in qt. */
+  samplesperblock = 2 * blocksize / channels - 7;
+  bytespersec = rate * blocksize / samplesperblock;
+  GST_WRITE_UINT16_LE (data, 0x11);
+  GST_WRITE_UINT16_LE (data + 2, channels);
+  GST_WRITE_UINT32_LE (data + 4, rate);
+  GST_WRITE_UINT32_LE (data + 8, bytespersec);
+  GST_WRITE_UINT16_LE (data + 12, blocksize);
+  GST_WRITE_UINT16_LE (data + 14, 4);
+  GST_WRITE_UINT16_LE (data + 16, 2);   /* Two extra bytes */
+  GST_WRITE_UINT16_LE (data + 18, samplesperblock);
+
+  atom_data = atom_data_new_from_gst_buffer (fourcc, buf);
+  gst_buffer_unref (buf);
+
+  return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
+      atom_data_free);
+}
+
+AtomInfo *
+build_ima_adpcm_extension (gint channels, gint rate, gint blocksize)
+{
+  AtomWAVE *wave;
+  AtomFRMA *frma;
+  Atom *ext_atom;
+
+  /* Add WAVE atom */
+  wave = atom_wave_new ();
+
+  /* Prepend Terminator atom to the WAVE list first, so it ends up last */
+  ext_atom = (Atom *) atom_data_new (FOURCC_null);
+  wave->extension_atoms =
+      atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) ext_atom,
+      (AtomCopyDataFunc) atom_data_copy_data, (AtomFreeFunc) atom_data_free);
+
+  /* Add wave ima adpcm atom to WAVE */
+  wave->extension_atoms = g_list_prepend (wave->extension_atoms,
+      build_ima_adpcm_atom (channels, rate, blocksize));
+
+  /* Add FRMA to the WAVE */
+  frma = atom_frma_new ();
+  frma->media_type = MS_WAVE_FOURCC (0x11);
+
+  wave->extension_atoms =
+      atom_info_list_prepend_atom (wave->extension_atoms, (Atom *) frma,
+      (AtomCopyDataFunc) atom_frma_copy_data, (AtomFreeFunc) atom_frma_free);
+
+  return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
+      atom_wave_free);
+}
index 87275d8..d9984a0 100644 (file)
@@ -675,6 +675,8 @@ AtomInfo *   build_amr_extension         ();
 AtomInfo *   build_h263_extension        ();
 AtomInfo *   build_gama_atom             (gdouble gamma);
 AtomInfo *   build_SMI_atom              (const GstBuffer *seqh);
+AtomInfo *   build_ima_adpcm_extension   (gint channels, gint rate,
+                                          gint blocksize);
 
 
 /*
index 29c12ee..c78bf80 100644 (file)
@@ -196,6 +196,11 @@ G_BEGIN_DECLS
 #define FOURCC_loci     GST_MAKE_FOURCC('l','o','c','i')
 #define FOURCC_kywd     GST_MAKE_FOURCC('k','y','w','d')
 
+/* For Microsoft Wave formats embedded in quicktime, the FOURCC is
+   'm', 's', then the 16 bit wave codec id */
+#define MS_WAVE_FOURCC(codecid)  GST_MAKE_FOURCC( \
+        'm', 's', ((codecid)>>8)&0xff, ((codecid)&0xff))
+
 G_END_DECLS
 
 #endif /* __FOURCC_H__ */
index cbfac0e..5899d2a 100644 (file)
@@ -1717,6 +1717,19 @@ gst_qt_mux_audio_sink_set_caps (GstPad * pad, GstCaps * caps)
     entry.fourcc = FOURCC_ulaw;
     entry.samples_per_packet = 1023;
     entry.bytes_per_sample = 2;
+  } else if (strcmp (mimetype, "audio/x-adpcm") == 0) {
+    gint blocksize;
+    if (!gst_structure_get_int (structure, "block_align", &blocksize)) {
+      GST_DEBUG_OBJECT (qtmux, "broken caps, block_align missing");
+      goto refuse_caps;
+    }
+    // Currently only supports WAV-style IMA ADPCM, for which the codec id is
+    // 0x11
+    entry.fourcc = MS_WAVE_FOURCC (0x11);
+    entry.samples_per_packet = 2 * blocksize / channels - 7;
+    entry.bytes_per_sample = 2;
+
+    ext_atom = build_ima_adpcm_extension (channels, rate, blocksize);
   }
 
   if (!entry.fourcc)
index 06171e9..a96e5b2 100644 (file)
   "rate = (int) 16000, " \
   "channels = [ 1, 2 ] "
 
+#define ADPCM_CAPS  \
+  "audio/x-adpcm, " \
+  "layout = (string)dvi, " \
+  "block_align = (int)[64, 8096], " \
+  COMMON_AUDIO_CAPS(2, MAX)
+
+
 /* FIXME 0.11 - take a look at bugs #580005 and #340375 */
 GstQTMuxFormatProp gst_qt_mux_format_list[] = {
   /* original QuickTime format; see Apple site (e.g. qtff.pdf) */
@@ -156,6 +163,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
         GST_STATIC_CAPS (PCM_CAPS_FULL "; "
             MP3_CAPS " ; "
             AAC_CAPS " ; "
+            ADPCM_CAPS " ; "
             "audio/x-alaw, " COMMON_AUDIO_CAPS (2, MAX) "; " AMR_CAPS)
       }
   ,