diff options
author | Hendrik Leppkes <h.leppkes@gmail.com> | 2012-07-14 12:32:57 +0400 |
---|---|---|
committer | Hendrik Leppkes <h.leppkes@gmail.com> | 2012-07-14 12:32:57 +0400 |
commit | 34bbf4259fab58f19039ccfa398f5a5044956e3a (patch) | |
tree | 5d06a68aec51cdad4a0735723c8e6a811ed31987 /decoder/LAVAudio | |
parent | 1007411f99d58cf6504fc8cdb7450cd8c183ab48 (diff) |
Introduce a fallback override mixer mode.
The fallback override mixer will only engage in case the channel layout changes mid-stream and the new layout is not being accepted by the audio renderer. This is typically the case with WMP/WMC, because they do not like channel re-configurations mid-stream.
When the override mixer is activated, it'll mix the audio to the previous channel layout to ensure playback continues.
Fixes issue 50.
Diffstat (limited to 'decoder/LAVAudio')
-rw-r--r-- | decoder/LAVAudio/LAVAudio.cpp | 60 | ||||
-rw-r--r-- | decoder/LAVAudio/LAVAudio.h | 1 | ||||
-rw-r--r-- | decoder/LAVAudio/PostProcessor.cpp | 22 |
3 files changed, 66 insertions, 17 deletions
diff --git a/decoder/LAVAudio/LAVAudio.cpp b/decoder/LAVAudio/LAVAudio.cpp index ed36bba5..ed975428 100644 --- a/decoder/LAVAudio/LAVAudio.cpp +++ b/decoder/LAVAudio/LAVAudio.cpp @@ -80,6 +80,7 @@ CLAVAudio::CLAVAudio(LPUNKNOWN pUnk, HRESULT* phr) , m_bChannelMappingRequired(FALSE) , m_bFindDTSInPCM(FALSE) , m_bFallback16Int(FALSE) + , m_dwOverrideMixer(0) , m_bNeedSyncpoint(FALSE) , m_dRate(1.0) , m_bInputPadded(FALSE) @@ -88,6 +89,7 @@ CLAVAudio::CLAVAudio(LPUNKNOWN pUnk, HRESULT* phr) , m_bMixingSettingsChanged(FALSE) , m_fMixingClipThreshold(0.0f) , m_bHasVideo(TRUE) + , m_dwRemixLayout(0) { #ifdef DEBUG DbgSetModuleLevel (LOG_CUSTOM1, DWORD_MAX); // FFMPEG messages use custom1 @@ -1260,6 +1262,8 @@ HRESULT CLAVAudio::ffmpeg_init(CodecID codec, const void *format, const GUID for m_bFindDTSInPCM = (codec == CODEC_ID_PCM_S16LE && m_settings.bFormats[Codec_DTS]); m_bFallback16Int = FALSE; + m_dwOverrideMixer = 0; + m_bMixingSettingsChanged = TRUE; return S_OK; } @@ -2083,13 +2087,55 @@ HRESULT CLAVAudio::Deliver(BufferDetails &buffer) if(hr == S_OK) { hr = m_pOutput->GetConnected()->QueryAccept(&mt); DbgLog((LOG_TRACE, 1, L"Sending new Media Type (QueryAccept: %0#.8x)", hr)); - if (hr != S_OK && buffer.sfFormat != SampleFormat_16) { - mt = CreateMediaType(SampleFormat_16, buffer.dwSamplesPerSec, buffer.wChannels, buffer.dwChannelMask, 16); - hr = m_pOutput->GetConnected()->QueryAccept(&mt); - if (hr == S_OK) { - DbgLog((LOG_TRACE, 1, L"-> 16-bit fallback type accepted")); - ConvertSampleFormat(&buffer, SampleFormat_16); - m_bFallback16Int = TRUE; + if (hr != S_OK) { + if (buffer.sfFormat != SampleFormat_16) { + mt = CreateMediaType(SampleFormat_16, buffer.dwSamplesPerSec, buffer.wChannels, buffer.dwChannelMask, 16); + hr = m_pOutput->GetConnected()->QueryAccept(&mt); + if (hr == S_OK) { + DbgLog((LOG_TRACE, 1, L"-> 16-bit fallback type accepted")); + ConvertSampleFormat(&buffer, SampleFormat_16); + m_bFallback16Int = TRUE; + } + } + // If a 16-bit fallback isn't enough, try to retain current channel layout + if (hr != S_OK) { + WAVEFORMATEX* wfeCurrent = (WAVEFORMATEX*)m_pOutput->CurrentMediaType().Format(); + WORD wChannels = wfeCurrent->nChannels; + DWORD dwChannelMask = 0; + if (wfeCurrent->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)wfeCurrent; + dwChannelMask = wfex->dwChannelMask; + } else { + dwChannelMask = wChannels == 2 ? (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) : SPEAKER_FRONT_CENTER; + } + mt = CreateMediaType(buffer.sfFormat, buffer.dwSamplesPerSec, wChannels, dwChannelMask, buffer.wBitsPerSample); + hr = m_pOutput->GetConnected()->QueryAccept(&mt); + if (hr == S_OK) { + DbgLog((LOG_TRACE, 1, L"-> Override Mixing to layout 0x%x", dwChannelMask)); + m_dwOverrideMixer = dwChannelMask; + m_bMixingSettingsChanged = TRUE; + LAVAudioSampleFormat sf = buffer.sfFormat; + // Mix to the new layout + PerformMixing(&buffer); + // Convert to old sample format, if required + if (buffer.sfFormat != sf) { + ConvertSampleFormat(&buffer, sf); + } + } else { + // If current channel layout alone wasn't enough, also go 16-bit + mt = CreateMediaType(SampleFormat_16, buffer.dwSamplesPerSec, wChannels, dwChannelMask, 16); + hr = m_pOutput->GetConnected()->QueryAccept(&mt); + if (hr == S_OK) { + DbgLog((LOG_TRACE, 1, L"-> Override Mixing to layout 0x%x with 16-bit fallback type", dwChannelMask)); + m_dwOverrideMixer = dwChannelMask; + m_bMixingSettingsChanged = TRUE; + // Mix to new layout + PerformMixing(&buffer); + // Convert to 16-bit + ConvertSampleFormat(&buffer, SampleFormat_16); + m_bFallback16Int = TRUE; + } + } } } m_pOutput->SetMediaType(&mt); diff --git a/decoder/LAVAudio/LAVAudio.h b/decoder/LAVAudio/LAVAudio.h index 38b3b199..68ac5879 100644 --- a/decoder/LAVAudio/LAVAudio.h +++ b/decoder/LAVAudio/LAVAudio.h @@ -263,6 +263,7 @@ private: GrowableArray<BYTE> m_buff; // Input Buffer LAVAudioSampleFormat m_DecodeFormat; // Number of bits in the samples BOOL m_bFallback16Int; + DWORD m_dwOverrideMixer; BOOL m_bSampleSupport[SampleFormat_NB]; diff --git a/decoder/LAVAudio/PostProcessor.cpp b/decoder/LAVAudio/PostProcessor.cpp index c3103736..87947c8b 100644 --- a/decoder/LAVAudio/PostProcessor.cpp +++ b/decoder/LAVAudio/PostProcessor.cpp @@ -554,8 +554,10 @@ HRESULT CLAVAudio::PerformMixing(BufferDetails *buffer) { int ret = 0; + DWORD dwMixingLayout = m_dwOverrideMixer ? m_dwOverrideMixer : m_settings.MixingLayout; + // Check if we need mixing, either already in target mask or in stereo (no downmixing from stereo) - if (buffer->dwChannelMask == m_settings.MixingLayout || (buffer->wChannels <= 2 && (m_settings.MixingFlags & LAV_MIXING_FLAG_UNTOUCHED_STEREO))) + if (buffer->dwChannelMask == dwMixingLayout || (buffer->wChannels <= 2 && (m_settings.MixingFlags & LAV_MIXING_FLAG_UNTOUCHED_STEREO) && !m_dwOverrideMixer)) return S_FALSE; // Sadly, we need to convert this, avresample has no 24-bit mode @@ -563,7 +565,7 @@ HRESULT CLAVAudio::PerformMixing(BufferDetails *buffer) ConvertSampleFormat(buffer, SampleFormat_32); } - if (buffer->dwChannelMask != m_DecodeLayoutSanified || (!m_avrContext && !m_bAVResampleFailed) || m_bMixingSettingsChanged) { + if (buffer->dwChannelMask != m_DecodeLayoutSanified || (!m_avrContext && !m_bAVResampleFailed) || m_bMixingSettingsChanged || m_dwRemixLayout != dwMixingLayout) { m_bAVResampleFailed = FALSE; m_bMixingSettingsChanged = FALSE; if (m_avrContext) { @@ -587,20 +589,20 @@ HRESULT CLAVAudio::PerformMixing(BufferDetails *buffer) av_opt_set_int(m_avrContext, "in_channel_layout", buffer->dwChannelMask, 0); av_opt_set_int(m_avrContext, "in_sample_fmt", get_ff_sample_fmt(buffer->sfFormat), 0); - av_opt_set_int(m_avrContext, "out_channel_layout", m_settings.MixingLayout, 0); + av_opt_set_int(m_avrContext, "out_channel_layout", dwMixingLayout, 0); av_opt_set_int(m_avrContext, "out_sample_fmt", get_ff_sample_fmt(m_sfRemixFormat), 0); // Create Matrix int in_ch = buffer->wChannels; - int out_ch = av_get_channel_layout_nb_channels(m_settings.MixingLayout); + int out_ch = av_get_channel_layout_nb_channels(dwMixingLayout); double *matrix_dbl = (double *)av_mallocz(in_ch * out_ch * sizeof(*matrix_dbl)); const double center_mix_level = (double)m_settings.MixingCenterLevel / 10000.0 / M_SQRT1_2; const double surround_mix_level = (double)m_settings.MixingSurroundLevel / 10000.0; const double lfe_mix_level = (double)m_settings.MixingLFELevel / 10000.0; - ret = avresample_build_matrix(buffer->dwChannelMask, m_settings.MixingLayout, center_mix_level, surround_mix_level, lfe_mix_level, bNormalize, matrix_dbl, in_ch, (AVMatrixEncoding)m_settings.MixingMode); + ret = avresample_build_matrix(buffer->dwChannelMask, dwMixingLayout, center_mix_level, surround_mix_level, lfe_mix_level, bNormalize, matrix_dbl, in_ch, (AVMatrixEncoding)m_settings.MixingMode); if (ret < 0) { - DbgLog((LOG_ERROR, 10, L"avresample_build_matrix failed, layout in: %x, out: %x, sample fmt in: %d, out: %d", buffer->dwChannelMask, m_settings.MixingLayout, buffer->sfFormat, m_sfRemixFormat)); + DbgLog((LOG_ERROR, 10, L"avresample_build_matrix failed, layout in: %x, out: %x, sample fmt in: %d, out: %d", buffer->dwChannelMask, dwMixingLayout, buffer->sfFormat, m_sfRemixFormat)); av_free(matrix_dbl); goto setuperr; } @@ -609,18 +611,18 @@ HRESULT CLAVAudio::PerformMixing(BufferDetails *buffer) ret = avresample_set_matrix(m_avrContext, matrix_dbl, in_ch); av_free(matrix_dbl); if (ret < 0) { - DbgLog((LOG_ERROR, 10, L"avresample_set_matrix failed, layout in: %x, out: %x, sample fmt in: %d, out: %d", buffer->dwChannelMask, m_settings.MixingLayout, buffer->sfFormat, m_sfRemixFormat)); + DbgLog((LOG_ERROR, 10, L"avresample_set_matrix failed, layout in: %x, out: %x, sample fmt in: %d, out: %d", buffer->dwChannelMask, dwMixingLayout, buffer->sfFormat, m_sfRemixFormat)); goto setuperr; } // Open Resample Context ret = avresample_open(m_avrContext); if (ret < 0) { - DbgLog((LOG_ERROR, 10, L"avresample_open failed, layout in: %x, out: %x, sample fmt in: %d, out: %d", buffer->dwChannelMask, m_settings.MixingLayout, buffer->sfFormat, m_sfRemixFormat)); + DbgLog((LOG_ERROR, 10, L"avresample_open failed, layout in: %x, out: %x, sample fmt in: %d, out: %d", buffer->dwChannelMask, dwMixingLayout, buffer->sfFormat, m_sfRemixFormat)); goto setuperr; } - m_dwRemixLayout = m_settings.MixingLayout; + m_dwRemixLayout = dwMixingLayout; } if (!m_avrContext) @@ -683,7 +685,7 @@ HRESULT CLAVAudio::PostProcess(BufferDetails *buffer) buffer->dwChannelMask = get_channel_mask(buffer->wChannels); } - if (m_settings.MixingEnabled) { + if (m_settings.MixingEnabled || m_dwOverrideMixer) { PerformMixing(buffer); } // Remap to standard configurations, if requested |