mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
winegstreamer: Explicitly translate the channel mask.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b44d3a3908
commit
8697c6c0db
3 changed files with 129 additions and 16 deletions
|
@ -128,6 +128,7 @@ struct wg_format
|
|||
} format;
|
||||
|
||||
uint32_t channels;
|
||||
uint32_t channel_mask; /* In WinMM format. */
|
||||
uint32_t rate;
|
||||
} audio;
|
||||
} u;
|
||||
|
|
|
@ -102,20 +102,6 @@ static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface);
|
|||
static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface);
|
||||
static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface);
|
||||
|
||||
static DWORD channel_mask_from_count(uint32_t count)
|
||||
{
|
||||
switch (count)
|
||||
{
|
||||
case 1: return KSAUDIO_SPEAKER_MONO;
|
||||
case 2: return KSAUDIO_SPEAKER_STEREO;
|
||||
case 4: return KSAUDIO_SPEAKER_SURROUND;
|
||||
case 5: return KSAUDIO_SPEAKER_5POINT1 & ~SPEAKER_LOW_FREQUENCY;
|
||||
case 6: return KSAUDIO_SPEAKER_5POINT1;
|
||||
case 8: return KSAUDIO_SPEAKER_7POINT1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format *format)
|
||||
{
|
||||
mt->majortype = MEDIATYPE_Audio;
|
||||
|
@ -220,7 +206,7 @@ static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format *
|
|||
wave_format->Format.wBitsPerSample = depth;
|
||||
wave_format->Format.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX);
|
||||
wave_format->Samples.wValidBitsPerSample = depth;
|
||||
wave_format->dwChannelMask = channel_mask_from_count(format->u.audio.channels);
|
||||
wave_format->dwChannelMask = format->u.audio.channel_mask;
|
||||
wave_format->SubFormat = is_float ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
|
||||
mt->lSampleSize = wave_format->Format.nBlockAlign;
|
||||
}
|
||||
|
@ -423,6 +409,25 @@ static bool amt_to_wg_format_audio(const AM_MEDIA_TYPE *mt, struct wg_format *fo
|
|||
format->u.audio.channels = audio_format->nChannels;
|
||||
format->u.audio.rate = audio_format->nSamplesPerSec;
|
||||
|
||||
if (audio_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
||||
{
|
||||
const WAVEFORMATEXTENSIBLE *ext_format = (const WAVEFORMATEXTENSIBLE *)mt->pbFormat;
|
||||
|
||||
format->u.audio.channel_mask = ext_format->dwChannelMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (audio_format->nChannels == 1)
|
||||
format->u.audio.channel_mask = KSAUDIO_SPEAKER_MONO;
|
||||
else if (audio_format->nChannels == 2)
|
||||
format->u.audio.channel_mask = KSAUDIO_SPEAKER_STEREO;
|
||||
else
|
||||
{
|
||||
ERR("Unexpected channel count %u.\n", audio_format->nChannels);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(format_map); ++i)
|
||||
{
|
||||
if (IsEqualGUID(&mt->subtype, format_map[i].subtype)
|
||||
|
|
|
@ -109,11 +109,70 @@ static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position)
|
||||
{
|
||||
static const uint32_t position_map[] =
|
||||
{
|
||||
SPEAKER_FRONT_LEFT,
|
||||
SPEAKER_FRONT_RIGHT,
|
||||
SPEAKER_FRONT_CENTER,
|
||||
SPEAKER_LOW_FREQUENCY,
|
||||
SPEAKER_BACK_LEFT,
|
||||
SPEAKER_BACK_RIGHT,
|
||||
SPEAKER_FRONT_LEFT_OF_CENTER,
|
||||
SPEAKER_FRONT_RIGHT_OF_CENTER,
|
||||
SPEAKER_BACK_CENTER,
|
||||
0,
|
||||
SPEAKER_SIDE_LEFT,
|
||||
SPEAKER_SIDE_RIGHT,
|
||||
SPEAKER_TOP_FRONT_LEFT,
|
||||
SPEAKER_TOP_FRONT_RIGHT,
|
||||
SPEAKER_TOP_FRONT_CENTER,
|
||||
SPEAKER_TOP_CENTER,
|
||||
SPEAKER_TOP_BACK_LEFT,
|
||||
SPEAKER_TOP_BACK_RIGHT,
|
||||
0,
|
||||
0,
|
||||
SPEAKER_TOP_BACK_CENTER,
|
||||
};
|
||||
|
||||
if (position < ARRAY_SIZE(position_map))
|
||||
return position_map[position];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info)
|
||||
{
|
||||
uint32_t mask = 0, position;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i)
|
||||
{
|
||||
if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i))))
|
||||
{
|
||||
GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i));
|
||||
return 0;
|
||||
}
|
||||
/* Make sure it's also in WinMM order. WinMM mandates that channels be
|
||||
* ordered, as it were, from least to most significant SPEAKER_* bit.
|
||||
* Hence we fail if the current channel was already specified, or if any
|
||||
* higher bit was already specified. */
|
||||
if (mask & ~(position - 1))
|
||||
{
|
||||
GST_WARNING("Unsupported channel order.");
|
||||
return 0;
|
||||
}
|
||||
mask |= position;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info)
|
||||
{
|
||||
format->major_type = WG_MAJOR_TYPE_AUDIO;
|
||||
format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info));
|
||||
format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info);
|
||||
format->u.audio.channel_mask = wg_channel_mask_from_gst(info);
|
||||
format->u.audio.rate = GST_AUDIO_INFO_RATE(info);
|
||||
}
|
||||
|
||||
|
@ -273,15 +332,63 @@ static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
|
|||
}
|
||||
}
|
||||
|
||||
static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count)
|
||||
{
|
||||
const uint32_t orig_mask = mask;
|
||||
unsigned int i;
|
||||
DWORD bit;
|
||||
|
||||
static const GstAudioChannelPosition position_map[] =
|
||||
{
|
||||
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
||||
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_LFE1,
|
||||
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
|
||||
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
||||
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
|
||||
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
|
||||
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
|
||||
};
|
||||
|
||||
for (i = 0; i < channel_count; ++i)
|
||||
{
|
||||
positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
|
||||
if (BitScanForward(&bit, mask))
|
||||
{
|
||||
if (bit < ARRAY_SIZE(position_map))
|
||||
positions[i] = position_map[bit];
|
||||
else
|
||||
GST_WARNING("Invalid channel mask %#x.\n", orig_mask);
|
||||
mask &= ~(1 << bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
GST_WARNING("Incomplete channel mask %#x.\n", orig_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *wg_format_to_caps_audio(const struct wg_format *format)
|
||||
{
|
||||
GstAudioChannelPosition positions[32];
|
||||
GstAudioFormat audio_format;
|
||||
GstAudioInfo info;
|
||||
|
||||
if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN)
|
||||
return NULL;
|
||||
|
||||
gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, NULL);
|
||||
wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels);
|
||||
gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions);
|
||||
return gst_audio_info_to_caps(&info);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue