[英]No Sound When Playing Back PCM-Decoded Audio
我正在讀取 AAC 音頻幀,然后使用 Media Foundation 將其解碼為 PCM,並嘗試通過 WASAPI 播放。 特別是 48000khz 2 通道,16 位。 我能夠解碼幀,將它們寫入文件full.pcm
,然后在 Audacity 中成功打開並播放該 PCM 文件。 但是,我通過設備揚聲器播放的代碼什么也沒給我。 我嘗試播放的源是默認源,即我的 DAC。 我沒有從任何與 WASAPI 相關的代碼中得到任何不好的 HRESULTS,所以我很困惑。 WASAPI 對我來說是新的,所以也許我缺少一些明顯的東西。
#include "AudioDecoder.h"
#include <vector>
#include <__msvc_chrono.hpp>
#include <string>
#include <fstream>
#include <cassert>
#include <filesystem>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <functiondiscoverykeys.h>
#include <audioclient.h>
int fps_counter = 0;
int frame_index = 0;
IAudioClient* audio_client;
IAudioRenderClient* render_client = nullptr;
int setup_audio_playback()
{
HRESULT hr = S_OK;
IMMDeviceEnumerator* pEnumerator = nullptr;
IMMDevice* pDevice = nullptr;
ATLENSURE_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator));
ATLENSURE_SUCCEEDED(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice));
IPropertyStore* ips;
ATLENSURE_SUCCEEDED(pDevice->OpenPropertyStore(STGM_READ, &ips));
PROPVARIANT varName;
// Initialize container for property value.
PropVariantInit(&varName);
ATLENSURE_SUCCEEDED(ips->GetValue(PKEY_Device_FriendlyName, &varName));
std::wcout << L"Device name: " << varName.pwszVal << std::endl;
ATLENSURE_SUCCEEDED(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void**)&audio_client));
WAVEFORMATEX* format;
ATLENSURE_SUCCEEDED(audio_client->GetMixFormat(&format));
ATLENSURE_SUCCEEDED(audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 10000000, 0, format, NULL));
uint32_t bufferFrameCount;
ATLENSURE_SUCCEEDED(audio_client->GetBufferSize(&bufferFrameCount));
ATLENSURE_SUCCEEDED(audio_client->GetService(__uuidof(IAudioRenderClient), (void**)&render_client));
ATLENSURE_SUCCEEDED(audio_client->Start());
return hr;
}
int main()
{
HRESULT hr = S_OK;
std::ofstream fout_all_frames_pcm;
std::filesystem::remove(std::filesystem::current_path() / "full.pcm");
fout_all_frames_pcm.open("full.pcm", std::ios::binary | std::ios::out);
if (FAILED(hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
return hr;
if (FAILED(hr = MFStartup(MF_VERSION)))
return hr;
setup_audio_playback();
AudioDecoder* ad = new AudioDecoder();
std::vector<uint8_t> data;
while (true)
{
std::chrono::time_point<std::chrono::steady_clock> iteration_time = std::chrono::high_resolution_clock::now();
// Read frame data
std::ifstream fin("Encoded Audio Frames\\frame" + std::to_string(frame_index) + ".aac", std::ios::binary | std::ios::in);
if (fin.fail())
{
//throw std::runtime_error("Invalid file path specified");
break;
}
// Get file length
fin.seekg(0, std::ios::end);
size_t const length = fin.tellg();
fin.seekg(0, std::ios::beg);
if (length > data.size())
{
static size_t constexpr const granularity = 64 << 10;
data.resize((length + (granularity - 1)) & ~(granularity - 1));
assert(length <= data.size());
}
// Copy frame data from file to array;
fin.read(reinterpret_cast<char*>(data.data()), length);
fin.close();
CComPtr<IMFSample> pcm_sample;
while (!ad->decode_sync(data.data(), length, &pcm_sample))
{
if (pcm_sample == nullptr) // This will happen if the color converter isn't able to produce output, so we will continue in that case
continue;
CComPtr<IMFMediaBuffer> buffer;
if (FAILED(hr = pcm_sample->ConvertToContiguousBuffer(&buffer)))
return hr;
unsigned char* datas;
DWORD length;
if (FAILED(hr = buffer->GetCurrentLength(&length)))
return hr;
if (FAILED(hr = buffer->Lock(&datas, nullptr, &length)))
return hr;
fout_all_frames_pcm.write((char*)datas, length);
// Does nothing
//Sleep(120);
// Grab all the available space in the shared buffer.
uint8_t* pData;
ATLENSURE_SUCCEEDED(render_client->GetBuffer(1, &pData));
memcpy(pData, datas, length);
DWORD flags = 0;
ATLENSURE_SUCCEEDED(render_client->ReleaseBuffer(1, flags));
pcm_sample.Release();
}
frame_index++;
}
audio_client->Stop();
return 0;
}
正在做
render_client->GetBuffer(1, ...
不會給您任何穩定的行為,因為您正在嘗試逐個樣本提交數據。 從字面上看,每秒 48000 個樣本中的一個 PCM 樣本。 當然,代碼可能會被破壞更多,因為您似乎只是丟失了大部分數據,從解碼器獲得了更多數據,並且只向設備提供了一個樣本。
您可能希望在代碼確定GetBuffer
將攜帶多少樣本的部分中查看這篇文章,然后循環准確地填充這些緩沖區,直到您使用您的IMFsample
數據。
這些緩沖區有多大,您使用GetBuffer
獲得的緩沖區有多大? 對於非常典型的 10 ms 緩沖區和 48 kHz 采樣率,每個緩沖區將有 480 個樣本。 使用立體聲和 16 位 PCM,每個樣本有 4 個字節,因此每次GetBuffer
/ ReleaseBuffer
迭代將提供大約 2K 字節。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.