From d74567ca949658a0d75353abaff1805b8e4d0a30 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 8 Dec 2009 17:55:56 -0800 Subject: [PATCH] qtmux: add ima adpcm support --- gst/quicktime/atoms.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ gst/quicktime/atoms.h | 2 ++ gst/quicktime/fourcc.h | 5 ++++ gst/quicktime/gstqtmux.c | 13 +++++++++ gst/quicktime/gstqtmuxmap.c | 8 +++++ 5 files changed, 99 insertions(+) diff --git a/gst/quicktime/atoms.c b/gst/quicktime/atoms.c index 5d73ae2..79117cc 100644 --- a/gst/quicktime/atoms.c +++ b/gst/quicktime/atoms.c @@ -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); +} diff --git a/gst/quicktime/atoms.h b/gst/quicktime/atoms.h index 87275d8..d9984a0 100644 --- a/gst/quicktime/atoms.h +++ b/gst/quicktime/atoms.h @@ -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); /* diff --git a/gst/quicktime/fourcc.h b/gst/quicktime/fourcc.h index 29c12ee..c78bf80 100644 --- a/gst/quicktime/fourcc.h +++ b/gst/quicktime/fourcc.h @@ -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__ */ diff --git a/gst/quicktime/gstqtmux.c b/gst/quicktime/gstqtmux.c index cbfac0e..5899d2a 100644 --- a/gst/quicktime/gstqtmux.c +++ b/gst/quicktime/gstqtmux.c @@ -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) diff --git a/gst/quicktime/gstqtmuxmap.c b/gst/quicktime/gstqtmuxmap.c index 06171e9..a96e5b2 100644 --- a/gst/quicktime/gstqtmuxmap.c +++ b/gst/quicktime/gstqtmuxmap.c @@ -129,6 +129,13 @@ "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) } , -- 2.7.4