CMediaType CLAVAudio::CreateBitstreamMediaType(AVCodecID codec, DWORD dwSampleRate, BOOL bDTSHDOverride) { CMediaType mt; mt.majortype = MEDIATYPE_Audio; mt.subtype = MEDIASUBTYPE_PCM; mt.formattype = FORMAT_WaveFormatEx; WAVEFORMATEXTENSIBLE wfex; memset(&wfex, 0, sizeof(wfex)); WAVEFORMATEX* wfe = &wfex.Format; wfe->nChannels = 2; wfe->wBitsPerSample = 16; GUID subtype = GUID_NULL; switch(codec) { case AV_CODEC_ID_AC3: wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; wfe->nSamplesPerSec = min(dwSampleRate, 48000); break; case AV_CODEC_ID_EAC3: wfe->nSamplesPerSec = 192000; wfe->nChannels = 2; subtype = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS; break; case AV_CODEC_ID_TRUEHD: wfe->nSamplesPerSec = 192000; wfe->nChannels = 8; subtype = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP; break; case AV_CODEC_ID_DTS: if (m_settings.bBitstream[Bitstream_DTSHD] && m_bDTSHD && !bDTSHDOverride) { wfe->nSamplesPerSec = 192000; wfe->nChannels = 8; subtype = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD; } else { wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; // huh? but it works. wfe->nSamplesPerSec = min(dwSampleRate, 48000); } break; default: ASSERT(0); break; } wfe->nBlockAlign = wfe->nChannels * wfe->wBitsPerSample / 8; wfe->nAvgBytesPerSec = wfe->nSamplesPerSec * wfe->nBlockAlign; if (subtype != GUID_NULL) { wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfex.Format.cbSize = sizeof(wfex) - sizeof(wfex.Format); wfex.dwChannelMask = get_channel_mask(wfe->nChannels); wfex.Samples.wValidBitsPerSample = wfex.Format.wBitsPerSample; wfex.SubFormat = subtype; } mt.SetSampleSize(1); mt.SetFormat((BYTE*)&wfex, sizeof(wfex.Format) + wfex.Format.cbSize); return mt; }
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; } } } }