From 9490d413c0ecf3a1604675cd69b7e01e0c95c8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 16 Feb 2006 19:18:46 +0000 Subject: [PATCH] gst-libs/gst/audio/multichannel.c: Minor docs fix. Original commit message from CVS: * gst-libs/gst/audio/multichannel.c: Minor docs fix. * gst-libs/gst/riff/Makefile.am: * gst-libs/gst/riff/riff-ids.h: * gst-libs/gst/riff/riff-media.c: (gst_riff_wavext_add_channel_layout), (gst_riff_create_audio_caps): Add support for WAVEFORMATEX, eg. PCM audio with more than two channels and a channel layout map. --- ChangeLog | 12 +++ gst-libs/gst/audio/multichannel.c | 2 +- gst-libs/gst/riff/Makefile.am | 5 +- gst-libs/gst/riff/riff-ids.h | 1 + gst-libs/gst/riff/riff-media.c | 150 ++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 01da4b04ee..7c950733df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-02-16 Tim-Philipp Müller + + * gst-libs/gst/audio/multichannel.c: + Minor docs fix. + + * gst-libs/gst/riff/Makefile.am: + * gst-libs/gst/riff/riff-ids.h: + * gst-libs/gst/riff/riff-media.c: + (gst_riff_wavext_add_channel_layout), (gst_riff_create_audio_caps): + Add support for WAVEFORMATEX, eg. PCM audio with more than two + channels and a channel layout map. + 2006-02-16 Mathieu Garcia Reviewed by Edward Hervey diff --git a/gst-libs/gst/audio/multichannel.c b/gst-libs/gst/audio/multichannel.c index fee9bc2448..c3d8a7391e 100644 --- a/gst-libs/gst/audio/multichannel.c +++ b/gst-libs/gst/audio/multichannel.c @@ -265,7 +265,7 @@ gst_audio_get_channel_positions (GstStructure * str) /** * gst_audio_set_channel_positions: - * @str: A #GstStructure to retrieve channel positions from. + * @str: A #GstStructure to set channel positions on. * @pos: an array of channel positions. The number of members * in this array should be equal to the (fixed!) number * of the "channels" property in the given #GstStructure. diff --git a/gst-libs/gst/riff/Makefile.am b/gst-libs/gst/riff/Makefile.am index 67f8253e49..b1a11727dc 100644 --- a/gst-libs/gst/riff/Makefile.am +++ b/gst-libs/gst/riff/Makefile.am @@ -11,6 +11,7 @@ libgstriff_@GST_MAJORMINOR@include_HEADERS = \ riff-media.h \ riff-read.h -libgstriff_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS) -libgstriff_@GST_MAJORMINOR@_la_CFLAGS = $(GST_CFLAGS) +libgstriff_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) \ + $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la +libgstriff_@GST_MAJORMINOR@_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstriff_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) diff --git a/gst-libs/gst/riff/riff-ids.h b/gst-libs/gst/riff/riff-ids.h index dfe1f13cd0..810a52f8c4 100644 --- a/gst-libs/gst/riff/riff-ids.h +++ b/gst-libs/gst/riff/riff-ids.h @@ -298,6 +298,7 @@ typedef struct _gst_riff_strf_auds { /* == WaveHeader (?) */ #define GST_RIFF_WAVE_FORMAT_VORBIS3PLUS (0x6771) #define GST_RIFF_WAVE_FORMAT_GSM_AMR_CBR (0x7A21) #define GST_RIFF_WAVE_FORMAT_GSM_AMR_VBR (0x7A22) +#define GST_RIFF_WAVE_FORMAT_EXTENSIBLE (0xFFFE) guint16 channels; guint32 rate; guint32 av_bps; diff --git a/gst-libs/gst/riff/riff-media.c b/gst-libs/gst/riff/riff-media.c index 6b231c162d..5a27b54e15 100644 --- a/gst-libs/gst/riff/riff-media.c +++ b/gst-libs/gst/riff/riff-media.c @@ -26,6 +26,13 @@ #include "riff-ids.h" #include "riff-media.h" +#include + +#include + +GST_DEBUG_CATEGORY_EXTERN (riff_debug); +#define GST_CAT_DEFAULT riff_debug + /** * gst_riff_create_video_caps_with_data: * @codec_fcc: fourCC codec for this codec. @@ -550,6 +557,85 @@ gst_riff_create_video_caps (guint32 codec_fcc, return caps; } +static const struct +{ + const guint32 ms_mask; + const GstAudioChannelPosition gst_pos; +} layout_mapping[] = { + { + 0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, { + 0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { + 0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, { + 0x00008, GST_AUDIO_CHANNEL_POSITION_LFE}, { + 0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, { + 0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { + 0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, { + 0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, { + 0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, { + 0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, { + 0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, { + 0x00800, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_CENTER */ + { + 0x01000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_LEFT */ + { + 0x02000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_CENTER */ + { + 0x04000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_RIGHT */ + { + 0x08000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_LEFT */ + { + 0x10000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_CENTER */ + { + 0x20000, GST_AUDIO_CHANNEL_POSITION_INVALID} /* TOP_BACK_RIGHT */ +}; + +#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping) + +static gboolean +gst_riff_wavext_add_channel_layout (GstCaps * caps, guint32 layout) +{ + GstAudioChannelPosition pos[MAX_CHANNEL_POSITIONS]; + GstStructure *s; + gint num_channels, i, p; + + s = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (s, "channels", &num_channels)) + g_return_val_if_reached (FALSE); + + if (num_channels < 2 || num_channels > MAX_CHANNEL_POSITIONS) { + GST_DEBUG ("invalid number of channels: %d", num_channels); + return FALSE; + } + + p = 0; + for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) { + if ((layout & layout_mapping[i].ms_mask) != 0) { + if (p >= num_channels) { + GST_WARNING ("More bits set in the channel layout map than there " + "are channels! Broken file"); + return FALSE; + } + if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) { + GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel " + "layout map - ignoring those channels", layout_mapping[i].ms_mask); + /* what to do? just ignore it and let downstream deal with a channel + * layout that has INVALID positions in it for now ... */ + } + pos[p] = layout_mapping[i].gst_pos; + ++p; + } + } + + if (p != num_channels) { + GST_WARNING ("Only %d bits set in the channel layout map, but there are " + "supposed to be %d channels! Broken file", p, num_channels); + return FALSE; + } + + gst_audio_set_channel_positions (s, pos); + return TRUE; +} + GstCaps * gst_riff_create_audio_caps (guint16 codec_id, gst_riff_strh * strh, gst_riff_strf_auds * strf, @@ -586,6 +672,7 @@ gst_riff_create_audio_caps (guint16 codec_id, "width", G_TYPE_INT, (int) (ba * 8 / ch), "depth", G_TYPE_INT, ws, "signed", G_TYPE_BOOLEAN, ws != 8, NULL); } else { + /* FIXME: this is pretty useless - we need fixed caps */ caps = gst_caps_from_string ("audio/x-raw-int, " "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) { true, false }, " @@ -699,6 +786,69 @@ gst_riff_create_audio_caps (guint16 codec_id, *codec_name = g_strdup ("Sony ATRAC3"); break; + case GST_RIFF_WAVE_FORMAT_EXTENSIBLE:{ + guint16 valid_bits_per_sample; + guint32 channel_mask; + guint32 subformat_guid[4]; + const guint8 *data; + + if (GST_BUFFER_SIZE (strf_data) != 22) { + GST_WARNING ("WAVE_FORMAT_EXTENSIBLE data size is %d (expected: 22)", + GST_BUFFER_SIZE (strf_data)); + return NULL; + } + + data = GST_BUFFER_DATA (strf_data); + valid_bits_per_sample = GST_READ_UINT16_LE (data); + channel_mask = GST_READ_UINT32_LE (data + 2); + subformat_guid[0] = GST_READ_UINT32_LE (data + 6); + subformat_guid[1] = GST_READ_UINT32_LE (data + 10); + subformat_guid[2] = GST_READ_UINT32_LE (data + 14); + subformat_guid[3] = GST_READ_UINT32_LE (data + 18); + + GST_DEBUG ("valid bps = %u", valid_bits_per_sample); + GST_DEBUG ("channel mask = 0x%08x", channel_mask); + GST_DEBUG ("GUID = %08x-%08x-%08x-%08x", subformat_guid[0], + subformat_guid[1], subformat_guid[2], subformat_guid[3]); + + if (subformat_guid[1] == 0x00100000 && + subformat_guid[2] == 0xaa000080 && subformat_guid[3] == 0x719b3800) { + if (subformat_guid[0] == 0x00000001) { + GST_DEBUG ("PCM"); + if (strf != NULL) { + gint ba = strf->blockalign; + gint ws = strf->size; + gint depth = ws; + + if (valid_bits_per_sample != 0) + depth = valid_bits_per_sample; + + caps = gst_caps_new_simple ("audio/x-raw-int", + "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, + "channels", G_TYPE_INT, strf->channels, + "width", G_TYPE_INT, (int) (ba * 8 / strf->channels), + "depth", G_TYPE_INT, depth, + "rate", G_TYPE_INT, strf->rate, + "signed", G_TYPE_BOOLEAN, (depth > 8) ? TRUE : FALSE, NULL); + + if (!gst_riff_wavext_add_channel_layout (caps, channel_mask)) { + GST_WARNING ("failed to add channel layout"); + gst_caps_unref (caps); + caps = NULL; + } + rate_chan = FALSE; + } + } else if (subformat_guid[0] == 0x00000003) { + GST_DEBUG ("FIXME: handle IEEE float format"); + } + + if (caps == NULL) { + GST_WARNING ("Unknown WAVE_FORMAT_EXTENSIBLE audio format"); + return NULL; + } + } + break; + } default: GST_WARNING ("Unknown audio tag 0x%04x", codec_id); return NULL;