// This function calculates the Root mean square (RMS) of all samples in the buffer, // converts the result into a reference dB value, and adds it to the volume floating average void CLAVAudio::UpdateVolumeStats(const BufferDetails &buffer) { const BYTE bSampleSize = get_byte_per_sample(buffer.sfFormat); const DWORD dwSamplesPerChannel = buffer.nSamples; const BYTE *pBuffer = buffer.bBuffer->Ptr(); float * const fChAvg = (float *)calloc(buffer.wChannels, sizeof(float)); for (DWORD i = 0; i < dwSamplesPerChannel; ++i) { for (WORD ch = 0; ch < buffer.wChannels; ++ch) { const float fSample = get_sample_from_buffer<float>(pBuffer, buffer.sfFormat); fChAvg[ch] += fSample * fSample; pBuffer += bSampleSize; } } for (int ch = 0; ch < buffer.wChannels; ++ch) { if (fChAvg[ch] > FLT_EPSILON) { const float fAvgSqrt = sqrt(fChAvg[ch] / dwSamplesPerChannel); const float fDb = 20.0f * log10(fAvgSqrt); m_faVolume[ch].Sample(fDb); } else { m_faVolume[ch].Sample(-100.0f); } } free(fChAvg); }
LAVAudioSampleFormat CLAVAudio::GetBestAvailableSampleFormat(LAVAudioSampleFormat inFormat, int *bits, BOOL bNoFallback) { ASSERT(inFormat >= 0 && inFormat < SampleFormat_Bitstream); if (m_FallbackFormat != SampleFormat_None && !bNoFallback) return m_FallbackFormat; LAVAudioSampleFormat outFormat = sampleFormatMapping[inFormat][0]; for(int i = 0; i < 5; i++) { if (GetSampleFormat(sampleFormatMapping[inFormat][i])) { outFormat = sampleFormatMapping[inFormat][i]; break; } } if (bits && outFormat != inFormat) *bits = get_byte_per_sample(outFormat) << 3; return outFormat; }
HRESULT CLAVAudio::DecodeDTS(const BYTE * pDataBuffer, int buffsize, int &consumed, HRESULT *hrDeliver) { HRESULT hr = S_FALSE; int nPCMLength = 0; BOOL bFlush = (pDataBuffer == nullptr); BufferDetails out; consumed = 0; while (buffsize > 0) { nPCMLength = 0; if (bFlush) buffsize = 0; ASSERT(m_pParser); BYTE *pOut = nullptr; int pOut_size = 0; int used_bytes = av_parser_parse2(m_pParser, m_pAVCtx, &pOut, &pOut_size, pDataBuffer, buffsize, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); if (used_bytes < 0) { return E_FAIL; } else if(used_bytes == 0 && pOut_size == 0) { DbgLog((LOG_TRACE, 50, L"::Decode() - could not process buffer, starving?")); break; } // Timestamp cache to compensate for one frame delay the parser might introduce, in case the frames were already perfectly sliced apart // If we used more (or equal) bytes then was output again, we encountered a new frame, update timestamps if (used_bytes >= pOut_size && m_bUpdateTimeCache) { m_rtStartInputCache = m_rtStartInput; m_rtStopInputCache = m_rtStopInput; m_rtStartInput = m_rtStopInput = AV_NOPTS_VALUE; m_bUpdateTimeCache = FALSE; } if (!bFlush && used_bytes > 0) { buffsize -= used_bytes; pDataBuffer += used_bytes; consumed += used_bytes; } if (pOut && pOut_size > 0) { // Parse DTS headers m_bsParser.Parse(AV_CODEC_ID_DTS, pOut, pOut_size, nullptr); unsigned decode_channels = dts_determine_decode_channels(m_bsParser.m_DTSHeader); // Init Decoder with new Parameters, if required if (m_DTSDecodeChannels != decode_channels) { DbgLog((LOG_TRACE, 20, L"::Decode(): Switching to %d channel decoding", decode_channels)); m_DTSDecodeChannels = decode_channels; FlushDTSDecoder(); } int bitdepth = 0, channels = 0, CoreSampleRate = 0, HDSampleRate = 0, profile = 0; int unk4 = 0, unk5 = 0; nPCMLength = SafeDTSDecode(pOut, pOut_size, m_pDTSDecoderContext->dtsPCMBuffer, 0, 8, &bitdepth, &channels, &CoreSampleRate, &unk4, &HDSampleRate, &unk5, &profile); if (nPCMLength > 0 && bitdepth != m_DTSBitDepth) { int decodeBits = bitdepth > 16 ? 24 : 16; // If the bit-depth changed, instruct the DTS Decoder to decode to the new bit depth, and decode the previous sample again. if (decodeBits != m_DTSBitDepth && out.bBuffer->GetCount() == 0) { DbgLog((LOG_TRACE, 20, L"::Decode(): The DTS decoder indicated that it outputs %d bits, changing config to %d bits to compensate", bitdepth, decodeBits)); m_DTSBitDepth = decodeBits; FlushDTSDecoder(); nPCMLength = SafeDTSDecode(pOut, pOut_size, m_pDTSDecoderContext->dtsPCMBuffer, 0, 2, &bitdepth, &channels, &CoreSampleRate, &unk4, &HDSampleRate, &unk5, &profile); } } if (nPCMLength <= 0) { DbgLog((LOG_TRACE, 50, L"::Decode() - DTS decoding failed")); FlushDTSDecoder(TRUE); m_bQueueResync = TRUE; continue; } out.wChannels = channels; out.dwSamplesPerSec = HDSampleRate; out.sfFormat = m_DTSBitDepth == 24 ? SampleFormat_24 : SampleFormat_16; out.dwChannelMask = get_channel_mask(channels); // TODO out.wBitsPerSample = bitdepth; int profile_index = 0; while(profile >>= 1) profile_index++; if (profile_index > 7) m_pAVCtx->profile = FF_PROFILE_UNKNOWN; else if (profile == 0 && !m_bsParser.m_DTSHeader.HasCore) m_pAVCtx->profile = FF_PROFILE_DTS_EXPRESS; else m_pAVCtx->profile = DTSProfiles[profile_index]; // TODO: get rid of these m_pAVCtx->sample_rate = HDSampleRate; m_pAVCtx->bits_per_raw_sample = bitdepth; // Send current input time to the delivery function out.rtStart = m_rtStartInputCache; m_rtStartInputCache = AV_NOPTS_VALUE; m_bUpdateTimeCache = TRUE; } // Send to Output if (nPCMLength > 0) { hr = S_OK; out.bBuffer->Append(m_pDTSDecoderContext->dtsPCMBuffer, nPCMLength); out.nSamples = out.bBuffer->GetCount() / get_byte_per_sample(out.sfFormat) / out.wChannels; if (m_pAVCtx->profile != (1 << 7)) { DTSRemapOutputChannels(&out, m_bsParser.m_DTSHeader); } m_pAVCtx->channels = out.wChannels; m_DecodeFormat = out.sfFormat; m_DecodeLayout = out.dwChannelMask; if (SUCCEEDED(PostProcess(&out))) { *hrDeliver = QueueOutput(out); if (FAILED(*hrDeliver)) { return S_FALSE; } } } }