mirror of https://github.com/mpv-player/mpv
ao/wasapi: revamp set_waveformatex
* bits instead of bytes * add valid_bits argument * just pass in the mp_chmap and get the number and wavext channel map from that * indicate valid bits in waveformat_to_str * make appropriate accomodations in try_format
This commit is contained in:
parent
121352cd95
commit
81948634ca
|
@ -149,27 +149,37 @@ const char *wasapi_explain_err(const HRESULT hr)
|
||||||
#undef E
|
#undef E
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_waveformat(WAVEFORMATEXTENSIBLE *wformat, WORD bytepersample,
|
static void set_waveformat(WAVEFORMATEXTENSIBLE *wformat,
|
||||||
bool is_float, DWORD samplerate, WORD channels,
|
WORD bits, WORD valid_bits, bool is_float,
|
||||||
DWORD chanmask)
|
DWORD samplerate, struct mp_chmap *channels)
|
||||||
{
|
{
|
||||||
int block_align = channels * bytepersample;
|
int block_align = channels->num * bits / 8;
|
||||||
wformat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
wformat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||||
wformat->Format.nChannels = channels;
|
wformat->Format.nChannels = channels->num;
|
||||||
wformat->Format.nSamplesPerSec = samplerate;
|
wformat->Format.nSamplesPerSec = samplerate;
|
||||||
wformat->Format.nAvgBytesPerSec = samplerate * block_align;
|
wformat->Format.nAvgBytesPerSec = samplerate * block_align;
|
||||||
wformat->Format.nBlockAlign = block_align;
|
wformat->Format.nBlockAlign = block_align;
|
||||||
wformat->Format.wBitsPerSample = bytepersample * 8;
|
wformat->Format.wBitsPerSample = bits;
|
||||||
wformat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
wformat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
||||||
if (is_float)
|
if (is_float)
|
||||||
wformat->SubFormat = mp_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
wformat->SubFormat = mp_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||||
else
|
else
|
||||||
wformat->SubFormat = mp_KSDATAFORMAT_SUBTYPE_PCM;
|
wformat->SubFormat = mp_KSDATAFORMAT_SUBTYPE_PCM;
|
||||||
wformat->Samples.wValidBitsPerSample = wformat->Format.wBitsPerSample;
|
wformat->Samples.wValidBitsPerSample = valid_bits;
|
||||||
wformat->dwChannelMask = chanmask;
|
wformat->dwChannelMask = mp_chmap_to_waveext(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *waveformat_to_str_buf(char *buf, size_t buf_size, const WAVEFORMATEX *wf)
|
static WORD waveformat_valid_bits(const WAVEFORMATEX *wf)
|
||||||
|
{
|
||||||
|
if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||||
|
WAVEFORMATEXTENSIBLE *wformat = (WAVEFORMATEXTENSIBLE *)wf;
|
||||||
|
return wformat->Samples.wValidBitsPerSample;
|
||||||
|
} else {
|
||||||
|
return wf->wBitsPerSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *waveformat_to_str_buf(char *buf, size_t buf_size, WAVEFORMATEX *wf)
|
||||||
{
|
{
|
||||||
char* type = "?";
|
char* type = "?";
|
||||||
switch(wf->wFormatTag) {
|
switch(wf->wFormatTag) {
|
||||||
|
@ -191,11 +201,18 @@ static char *waveformat_to_str_buf(char *buf, size_t buf_size, const WAVEFORMATE
|
||||||
type = "s";
|
type = "s";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snprintf(buf, buf_size, "%"PRIu16"ch %s%"PRIu16" @ %"PRIu32"hz",
|
int valid_bits = waveformat_valid_bits(wf);
|
||||||
wf->nChannels, type, wf->wBitsPerSample, (unsigned)wf->nSamplesPerSec);
|
if (valid_bits == wf->wBitsPerSample){
|
||||||
|
snprintf(buf, buf_size, "%"PRIu16"ch %s%"PRIu16" @ %"PRIu32"hz",
|
||||||
|
wf->nChannels, type, valid_bits, (unsigned)wf->nSamplesPerSec);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "%"PRIu16"ch %s%"PRIu16" (in %s%"PRIu16") @ %"PRIu32"hz",
|
||||||
|
wf->nChannels, type, valid_bits, type, wf->wBitsPerSample,
|
||||||
|
(unsigned)wf->nSamplesPerSec);
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
#define waveformat_to_str(wf) waveformat_to_str_buf((char[32]){0}, 32, (wf))
|
#define waveformat_to_str(wf) waveformat_to_str_buf((char[40]){0}, 40, (wf))
|
||||||
|
|
||||||
static bool waveformat_is_float(WAVEFORMATEX *wf)
|
static bool waveformat_is_float(WAVEFORMATEX *wf)
|
||||||
{
|
{
|
||||||
|
@ -279,8 +296,8 @@ static bool set_ao_format(struct ao *ao, WAVEFORMATEX *wf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool try_format(struct ao *ao,
|
static bool try_format(struct ao *ao,
|
||||||
int bits, bool is_float, int samplerate,
|
int bits, int valid_bits, bool is_float,
|
||||||
const struct mp_chmap channels)
|
int samplerate, struct mp_chmap *channels)
|
||||||
{
|
{
|
||||||
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
|
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
|
||||||
/* If for some reason we get 8-bits, try 16-bit equivalent instead.
|
/* If for some reason we get 8-bits, try 16-bit equivalent instead.
|
||||||
|
@ -291,8 +308,7 @@ static bool try_format(struct ao *ao,
|
||||||
bits = FFMAX(16, bits);
|
bits = FFMAX(16, bits);
|
||||||
|
|
||||||
WAVEFORMATEXTENSIBLE wformat;
|
WAVEFORMATEXTENSIBLE wformat;
|
||||||
set_waveformat(&wformat, bits / 8, is_float, samplerate, channels.num,
|
set_waveformat(&wformat, bits, valid_bits, is_float, samplerate, channels);
|
||||||
mp_chmap_to_waveext(&channels));
|
|
||||||
MP_VERBOSE(ao, "Trying %s\n", waveformat_to_str(&wformat.Format));
|
MP_VERBOSE(ao, "Trying %s\n", waveformat_to_str(&wformat.Format));
|
||||||
|
|
||||||
WAVEFORMATEX *closestMatch;
|
WAVEFORMATEX *closestMatch;
|
||||||
|
@ -309,7 +325,6 @@ static bool try_format(struct ao *ao,
|
||||||
if (set_ao_format(ao, &wformat.Format)) {
|
if (set_ao_format(ao, &wformat.Format)) {
|
||||||
MP_VERBOSE(ao, "Accepted as %dch %s @ %dhz\n",
|
MP_VERBOSE(ao, "Accepted as %dch %s @ %dhz\n",
|
||||||
ao->channels.num, af_fmt_to_str(ao->format), ao->samplerate);
|
ao->channels.num, af_fmt_to_str(ao->format), ao->samplerate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} if (hr == S_OK || (!state->opt_exclusive && hr == AUDCLNT_E_UNSUPPORTED_FORMAT)) {
|
} if (hr == S_OK || (!state->opt_exclusive && hr == AUDCLNT_E_UNSUPPORTED_FORMAT)) {
|
||||||
|
@ -330,8 +345,8 @@ static bool try_mix_format(struct ao *ao)
|
||||||
HRESULT hr = IAudioClient_GetMixFormat(state->pAudioClient, &wf);
|
HRESULT hr = IAudioClient_GetMixFormat(state->pAudioClient, &wf);
|
||||||
EXIT_ON_ERROR(hr);
|
EXIT_ON_ERROR(hr);
|
||||||
|
|
||||||
bool ret = try_format(ao, wf->wBitsPerSample, waveformat_is_float(wf),
|
bool ret = try_format(ao, wf->wBitsPerSample, waveformat_valid_bits(wf),
|
||||||
wf->nSamplesPerSec, ao->channels);
|
waveformat_is_float(wf), wf->nSamplesPerSec, &ao->channels);
|
||||||
|
|
||||||
SAFE_RELEASE(wf, CoTaskMemFree(wf));
|
SAFE_RELEASE(wf, CoTaskMemFree(wf));
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -390,8 +405,9 @@ static bool find_formats(struct ao *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if the format works as-is */
|
/* See if the format works as-is */
|
||||||
if (try_format(ao, af_fmt2bits(ao->format),
|
int bits = af_fmt2bits(ao->format);
|
||||||
af_fmt_is_float(ao->format), ao->samplerate, ao->channels))
|
if (try_format(ao, bits, bits, af_fmt_is_float(ao->format),
|
||||||
|
ao->samplerate, &ao->channels))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!state->opt_exclusive) {
|
if (!state->opt_exclusive) {
|
||||||
|
@ -406,10 +422,10 @@ static bool find_formats(struct ao *ao)
|
||||||
/* fixme: try float first */
|
/* fixme: try float first */
|
||||||
bool is_float = false;
|
bool is_float = false;
|
||||||
while (1) { // not infinite -- returns at bottom
|
while (1) { // not infinite -- returns at bottom
|
||||||
int bits = start_bits;
|
bits = start_bits;
|
||||||
for (; bits > 8; bits -= 8) {
|
for (; bits > 8; bits -= 8) {
|
||||||
int samplerate = ao->samplerate;
|
int samplerate = ao->samplerate;
|
||||||
if (try_format(ao, bits, is_float, samplerate, ao->channels))
|
if (try_format(ao, bits, bits, is_float, samplerate, &ao->channels))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// make samplerate fit in [44100 192000]
|
// make samplerate fit in [44100 192000]
|
||||||
|
@ -419,28 +435,28 @@ static bool find_formats(struct ao *ao)
|
||||||
samplerate = 44100;
|
samplerate = 44100;
|
||||||
if (samplerate > 96000)
|
if (samplerate > 96000)
|
||||||
samplerate = 192000;
|
samplerate = 192000;
|
||||||
if (try_format(ao, bits, is_float, samplerate, ao->channels))
|
if (try_format(ao, bits, bits, is_float, samplerate, &ao->channels))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try bounding to 96kHz
|
// try bounding to 96kHz
|
||||||
if (samplerate > 48000) {
|
if (samplerate > 48000) {
|
||||||
samplerate = 96000;
|
samplerate = 96000;
|
||||||
if (try_format(ao, bits, is_float, samplerate, ao->channels))
|
if (try_format(ao, bits, bits, is_float, samplerate, &ao->channels))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try bounding to 48kHz
|
// try bounding to 48kHz
|
||||||
if (samplerate > 44100) {
|
if (samplerate > 44100) {
|
||||||
samplerate = 48000;
|
samplerate = 48000;
|
||||||
if (try_format(ao, bits, is_float, samplerate, ao->channels))
|
if (try_format(ao, bits, bits, is_float, samplerate, &ao->channels))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* How bad is this? try 44100hz, but only on 16bit */
|
/* How bad is this? try 44100hz, but only on 16bit */
|
||||||
if (bits == 16 && samplerate != 44100) {
|
if (bits == 16 && samplerate != 44100) {
|
||||||
samplerate = 44100;
|
samplerate = 44100;
|
||||||
if (try_format(ao, bits, is_float, samplerate, ao->channels))
|
if (try_format(ao, bits, bits, is_float, samplerate, &ao->channels))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue