Как мне кодировать сырые 48 кГц / 32-битные PCM в FLAC, используя Microsoft Media Foundation?

Я создал SinkWriter, который может кодировать видео и аудио с помощью платформы Microsoft Media Foundation.

Пока видео работает нормально, но у меня есть проблемы только с аудио.

Мой источник PCM имеет частоту дискретизации 48828 Гц, 32 бита на выборку и является моно.

Пока все работает хорошо, кроме FLAC.

Например, выход MP3 работает более или менее, но имеет неправильный формат. Относительно MSDN (MP3 Audio Encoder) MP3-кодер поддерживает только 16 бит на сэмпл в качестве входа. Мой источник PCM, как описано выше, имеет 32 бита на выборку.

Однако экспорт с MP3 работает, потому что MF Platform, похоже, имеет какой-то запасной вариант и использует аудио уровень MPEG 1/2 (mpga) с 2 каналами, 32 кГц и битрейтом 320 кбит / с.

Все начинает становиться странным, когда я устанавливаю MF_MT_SUBTYPE в MFAudioFormat_FLAC. Экспорт тоже работает, но качество звука ужасное. Там много шума, но я могу распознать звук. Что касается VLC, файл FLAC имеет частоту дискретизации 44,1 кГц, 8 бит на выборку и является монофоническим.

Означает ли это, что кодек FLAC не может работать с PCM, который я предоставляю?

У кого-нибудь была такая же проблема и удалось ее исправить?

Обновить

После более подробного изучения этой проблемы кажется, что мой PCM Audio с разрешением 32 Бита слишком высок. Поэтому в настоящее время я пытаюсь преобразовать 32-битную PCM в 24-битную для FLAC и 16-битную для MP3, но пока безуспешно. Я буду держать вас в курсе, если я добьюсь прогресса.

———

Обновление 2

Я создал минимальный пример приложения, который показывает проблему, с которой я сталкиваюсь.
Он читает файл волны 48 кГц и пытается зашифровать его.

При выполнении hr = pSinkWriter->BeginWriting(); Команда Я получаю ошибку 0xc00d36b4 белое средство The data specified for the media type is invalid, inconsistent, or not supported by this object,

Что я здесь не так делаю?

#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>

#include <comdef.h>

#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <Mferror.h>

#pragma comment(lib, "ole32")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mfuuid")

using namespace System;int main(array<System::String ^> ^args)
{
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);

hr = MFStartup(MF_VERSION);

IMFMediaType *pMediaType;
IMFMediaType *pMediaTypeOut;
IMFSourceReader *pSourceReader;
IMFAttributes *pAttributes;
IMFSinkWriter *pSinkWriter;

hr = MFCreateSourceReaderFromURL(
L"C:\\Temp\\48khz32bit.wav",
NULL,
&pSourceReader
);

hr = MFCreateAttributes(&pAttributes, 1);

hr = pAttributes->SetGUID(
MF_TRANSCODE_CONTAINERTYPE,
MFTranscodeContainerType_WAVE
);

hr = MFCreateSinkWriterFromURL(
L"C:\\Temp\\foo.flac",
NULL,
pAttributes,
&pSinkWriter
);

hr = pSourceReader->GetCurrentMediaType(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
&pMediaType);

hr = MFCreateMediaType(&pMediaTypeOut);

hr = pMediaTypeOut->SetGUID(
MF_MT_MAJOR_TYPE,
MFMediaType_Audio
);

hr = pMediaTypeOut->SetGUID(
MF_MT_SUBTYPE,
MFAudioFormat_FLAC
);

hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND,
48000
);

hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_NUM_CHANNELS,
1
);

hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_BITS_PER_SAMPLE,
32
);

hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_AVG_BYTES_PER_SECOND,
(((32 + 7) / 8) * 1) * 48000
);

hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_BLOCK_ALIGNMENT,
((32 + 7) / 8) * 1
);

DWORD nWriterStreamIndex = -1;

hr = pSinkWriter->AddStream(pMediaTypeOut, &nWriterStreamIndex);

hr = pSinkWriter->BeginWriting();

_com_error err(hr);
LPCTSTR errMsg = err.ErrorMessage();

for (;;)
{
DWORD nStreamIndex, nStreamFlags;
LONGLONG nTime;
IMFSample *pSample;

hr = pSourceReader->ReadSample(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0,
&nStreamIndex,
&nStreamFlags,
&nTime,
&pSample);

if (pSample)
{
OutputDebugString(L"Write sample...\n");

hr = pSinkWriter->WriteSample(
nWriterStreamIndex,
pSample
);
}

if (nStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
break;
}
}

hr = pSinkWriter->Finalize();

return 0;
}

———

Обновление 3

Я добавил решение как ответ.

———

Инициализировать SinkWriter

HRESULT SinkWriter::InitializeSinkWriter(IMFSinkWriter **ppWriter, DWORD *pStreamIndex, DWORD *pAudioStreamIndex, LPCWSTR filename)
{
*ppWriter = NULL;
*pStreamIndex = NULL;
*pAudioStreamIndex = NULL;

IMFSinkWriter   *pSinkWriter = NULL;

// Attributes
IMFAttributes   *pAttributes;

HRESULT hr = S_OK;

DX::ThrowIfFailed(
MFCreateAttributes(
&pAttributes,
3
)
);

#if defined(ENABLE_HW_ACCELERATION)
CComPtr<ID3D11Device> device;
D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 };

#if defined(ENABLE_HW_DRIVER)
DX::ThrowIfFailed(
D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
(0 * D3D11_CREATE_DEVICE_SINGLETHREADED) | D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
levels,
ARRAYSIZE(levels),
D3D11_SDK_VERSION,
&device,
nullptr,
nullptr
)
);

const CComQIPtr<ID3D10Multithread> pMultithread = device;
pMultithread->SetMultithreadProtected(TRUE);
#else
DX::ThrowIfFailed(
D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_NULL,
nullptr,
D3D11_CREATE_DEVICE_SINGLETHREADED,
levels,
ARRAYSIZE(levels),
D3D11_SDK_VERSION,
&device,
nullptr,
nullptr)
);
#endif

UINT token;
CComPtr<IMFDXGIDeviceManager> pManager;

DX::ThrowIfFailed(
MFCreateDXGIDeviceManager(
&token,
&pManager
)
);

DX::ThrowIfFailed(
pManager->ResetDevice(
device,
token
)
);

DX::ThrowIfFailed(
pAttributes->SetUnknown(
MF_SOURCE_READER_D3D_MANAGER,
pManager
)
);

DX::ThrowIfFailed(
pAttributes->SetUINT32(
MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS,
TRUE
)
);

#if (WINVER >= 0x0602)
DX::ThrowIfFailed(
pAttributes->SetUINT32(
MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING,
TRUE
)
);
#endif
#else
DX::ThrowIfFailed(
pAttributes->SetUINT32(
MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS,
TRUE
)
);

DX::ThrowIfFailed(
pAttributes->SetUINT32(
MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING,
TRUE
)
);
#endif

DX::ThrowIfFailed(
MFCreateSinkWriterFromURL(
filename,
NULL,
pAttributes,
&pSinkWriter
)
);

if (m_vFormat != VideoFormat::SWFV_NONE)
{
DX::ThrowIfFailed(
InitializeVideoCodec(
pSinkWriter,
pStreamIndex
)
);
}

if (m_audFormat != AudioFormat::SWAF_NONE)
{
DX::ThrowIfFailed(
InitializeAudioCodec(
pSinkWriter,
pAudioStreamIndex
)
);
}

// Tell the sink writer to start accepting data.
DX::ThrowIfFailed(
pSinkWriter->BeginWriting()
);

// Return the pointer to the caller.
*ppWriter = pSinkWriter;
(*ppWriter)->AddRef();

SAFE_RELEASE(pSinkWriter);
return hr;
}

Инициализировать аудио кодек

HRESULT SinkWriter::InitializeAudioCodec(IMFSinkWriter *pSinkWriter, DWORD *pStreamIndex)
{
// Audio media types
IMFMediaType    *pAudioTypeOut = NULL;
IMFMediaType    *pAudioTypeIn = NULL;

DWORD           audioStreamIndex;

HRESULT hr = S_OK;

// Set the output audio type.
DX::ThrowIfFailed(
MFCreateMediaType(
&pAudioTypeOut
)
);

DX::ThrowIfFailed(
pAudioTypeOut->SetGUID(
MF_MT_MAJOR_TYPE,
MFMediaType_Audio
)
);

DX::ThrowIfFailed(
pAudioTypeOut->SetGUID(
MF_MT_SUBTYPE,
AUDIO_SUBTYPE
)
);

DX::ThrowIfFailed(
pSinkWriter->AddStream(
pAudioTypeOut,
&audioStreamIndex
)
);

// Set the input audio type
DX::ThrowIfFailed(
MFCreateMediaType(
&pAudioTypeIn
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetGUID(
MF_MT_MAJOR_TYPE,
AUDIO_MAJOR_TYPE
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetGUID(
MF_MT_SUBTYPE,
MFAudioFormat_PCM
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetUINT32(
MF_MT_AUDIO_NUM_CHANNELS,
AUDIO_NUM_CHANNELS
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetUINT32(
MF_MT_AUDIO_BITS_PER_SAMPLE,
AUDIO_BITS_PER_SAMPLE
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetUINT32(
MF_MT_AUDIO_BLOCK_ALIGNMENT,
AUDIO_BLOCK_ALIGNMENT
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND,
AUDIO_SAMPLES_PER_SECOND
)
);

DX::ThrowIfFailed(
pAudioTypeIn->SetUINT32(
MF_MT_AUDIO_AVG_BYTES_PER_SECOND,
AUDIO_AVG_BYTES_PER_SECOND
)
);

DX::ThrowIfFailed(
pSinkWriter->SetInputMediaType(
audioStreamIndex,
pAudioTypeIn,
NULL
)
);

*pStreamIndex = audioStreamIndex;

SAFE_RELEASE(pAudioTypeOut);
SAFE_RELEASE(pAudioTypeIn);

return hr;
}

Нажмите аудио данные

HRESULT SinkWriter::PushAudio(UINT32* data)
{
HRESULT hr = S_FALSE;

if (m_isInitializing)
{
return hr;
}

IMFSample *pSample = NULL;
IMFMediaBuffer *pBuffer = NULL;
BYTE *pMem = NULL;

size_t cbBuffer = m_bufferLength * sizeof(short);

// Create a new memory buffer.
hr = MFCreateMemoryBuffer(cbBuffer, &pBuffer);

// Lock the buffer and copy the audio frame to the buffer.
if (SUCCEEDED(hr))
{
hr = pBuffer->Lock(&pMem, NULL, NULL);
}

if (SUCCEEDED(hr))
{
CopyMemory(pMem, data, cbBuffer);
}

if (pBuffer)
{
pBuffer->Unlock();
}

if (m_vFormat == VideoFormat::SWFV_NONE && m_audFormat == AudioFormat::SWAF_WAV)
{
DWORD cbWritten = 0;

if (SUCCEEDED(hr))
{
hr = m_pByteStream->Write(pMem, cbBuffer, &cbWritten);
}

if (SUCCEEDED(hr))
{
m_cbWrittenByteStream += cbWritten;
}
}
else
{
// Set the data length of the buffer.
if (SUCCEEDED(hr))
{
hr = pBuffer->SetCurrentLength(cbBuffer);
}

// Create media sample and add the buffer to the sample.
if (SUCCEEDED(hr))
{
hr = MFCreateSample(&pSample);
}

if (SUCCEEDED(hr))
{
hr = pSample->AddBuffer(pBuffer);
}

// Set the timestamp and the duration.
if (SUCCEEDED(hr))
{
hr = pSample->SetSampleTime(m_cbRtStartVideo);
}

if (SUCCEEDED(hr))
{
hr = pSample->SetSampleDuration(m_cbRtDurationVideo);
}

// Send the sample to the Sink Writer
if (SUCCEEDED(hr))
{
hr = m_pSinkWriter->WriteSample(m_audioStreamIndex, pSample);
}

/*if (SUCCEEDED(hr))
{
m_cbRtStartAudio += m_cbRtDurationAudio;
}*/

SAFE_RELEASE(pSample);
SAFE_RELEASE(pBuffer);
}

return hr;
}

1

Решение

Итак, Microsoft представила кодер FLAC Media Foundation Transform (MFT) CLSID_CMSFLACEncMFT в Windows 10, но кодек остается недокументированным на данный момент.

Поддерживаемые форматы медиа в Media Foundation аналогично устарела и не отражает наличие последних дополнений.

Я не знаю ни одного комментария по этому поводу, и я считаю, что кодек добавлен для внутреннего использования, но реализация является просто стандартными компонентами Media Foundation без лицензионных ограничений, поэтому кодеки тоже не ограничены, например, область использования ограничения.

Этот стандартный кодек, по-видимому, ограничен 8, 16 и 24-битными вариантами ввода PCM (то есть не 32-битным / семплом — вам нужно Resample соответственно). Кодек способен принимать до 8 каналов и гибких выборок в секунду (допустимо 48828 Гц).

Хотя кодек (преобразование), кажется, работает, если вы хотите создать файл, вам также нужен подходящий формат контейнера (мультиплексор), который совместим с MFAudioFormat_FLAC (идентификатор имеет 7 результатов в Поиске Google на момент публикации, что в основном означает, что никто даже не знает о кодеке). Устаревшая документация не отражает фактическую поддержку FLAC в стоковых накопителях.

Я позаимствовал пользовательский приемник мультимедиа, который записывает исходную полезную нагрузку MFT-файла в файл, и такой вывод FLAC может воспроизводиться, поскольку кадры FLAC содержат необходимую информацию для анализа потока битов для воспроизведения.

введите описание изображения здесь

Для справки, сам файл: 20180224-175524.flac.

Очевидный кандидат среди стоковых СМИ WAVE Media Sink не может принять ввод FLAC. Тем не менее, это потенциально может, реализация предположительно ограничена более простыми аудиоформатами.

Медиапоток AVI может принимать аудио FLAC, но кажется, что невозможно создать аудио только AVI.

Среди других медиа-приемников, однако, есть медиа-приемник, который может обрабатывать FLAC: MPEG-4 File Sink. Опять же, несмотря на устаревшую документацию, приемник мультимедиа принимает ввод FLAC, поэтому вы должны иметь возможность создавать файлы .MP4 с аудиодорожкой FLAC.

Образец файла: 20180224-184012.mp4. «FLAC (в рамке)»

введите описание изображения здесь

Подвести итог:

  • FLAC кодировщик MFT присутствует в Windows 10 и доступен для использования; не хватает надлежащей документации, хотя
  • Нужно позаботиться о преобразовании ввода в совместимый формат (без прямой поддержки 32-битного PCM)
  • Можно напрямую управлять MFT и потреблять вывод MFT, а затем получать битовый поток FLAC.
  • В качестве альтернативы, можно использовать стандартный мультимедийный приемник MP4 для создания выходных данных с аудиодорожкой FLAC.
  • В качестве альтернативы, можно разработать собственный приемник мультимедиа и использовать битовый поток FLAC из восходящего соединения кодера

Потенциально, кодек совместим с Transcode API, однако вышеупомянутые ограничения применяются. Тип контейнера должен быть MFTranscodeContainerType_MPEG4 особенно.

Кодек, очевидно, совместим с Медиа сессия API, вероятно, это хорошо для использования с Раковина Писатель API тоже.

В вашем коде, когда вы пытаетесь использовать Sink Writer API, вы также должны иметь выход MP4 с входом, возможно преобразованным в совместимый формат в вашем коде (совместимый PCM или совместимый FLAC с кодировщиком MFT, управляемым на вашей стороне). Зная, что медиа-приемник MP4 в целом способен создавать звуковую дорожку FLAC, вы должны иметь возможность отлаживать мелкие детали в вашем коде и настраивать компоненты для совместной работы.

2

Другие решения

Наконец я смог решить проблему. Это было не так сложно, чтобы быть честным. Но это всегда так, если вы знаете, как чего-то достичь;).

Я создал пример копирования и вставки ниже, чтобы дать представление о том, как реализовать кодирование FLAC с помощью Microsoft Media Foundation.

Недостающий кусок головоломки был MFTranscodeGetAudioOutputAvailableTypes. Эта функция выводит список всех доступных форматов вывода из аудиокодера.

Если вы не уверены, какие MFT поддерживаются операционной системой, вы можете позвонить Функция MFTEnumEx первый. Это дает вам список всех доступных MFT. В моем случае с windows 10 есть FLAC MFT, который определяется следующим образом.

Name: Microsoft FLAC Audio Encoder MFT
Input Types: 1 items:
Audio-PCM
Class identifier: 128509e9-c44e-45dc-95e9-c255b8f466a6
Output Types: 1 items:
Audio-0000f1ac-0000-0010-8000-00aa00389b71
Transform Flags: 1
Transform Category: Audio Encoder

Поэтому следующее, что я сделал, — создал программу чтения исходного кода и получил текущий тип носителя. Важными значениями для меня являются частота дискретизации, битрейт и каналы.

Затем я создал GetOutputMediaTypes функция, которая требует запрошенный аудиоформат, частоту дискретизации, битрейт, каналы и ссылку на IMFMediaType.

MFTranscodeGetAudioOutputAvailableTypes Функция возвращает все доступные типы для GUID MFAudioFormat_flac.

После подсчета доступных типов медиа с hr = pAvailableTypes->GetElementCount(&dwMTCount); Я могу перебирать их и проверять, поддерживает ли тип мой запрос. Если это так, я возвращаю тип носителя.

Последняя часть самая простая.

Сначала добавьте тип выходного носителя в приемник, чтобы получить индекс потока.

DWORD dwWriterStreamIndex = -1;

// Add the stream
hr = pSinkWriter->AddStream(
pOuputMediaType,
&dwWriterStreamIndex
);

Затем установите тип ввода и вызовите pSinkWriter->BeginWriting(); поэтому приемник начинает принимать данные.

// Set input media type
hr = pSinkWriter->SetInputMediaType(
dwWriterStreamIndex,
pInputType,
NULL
);

// Tell the sink writer to accept data
hr = pSinkWriter->BeginWriting();

Если тип носителя вывода и ввода задан правильно, BeginWriting должен вернуть 0 как HRESULT.

Мы не должны получить ошибку, потому что мы используем тип носителя функцию MFTranscodeGetAudioOutputAvailableTypes обеспечивает.

Последний шаг — прочитать все образцы из читателя-источника и записать его через приемник в контейнер flac.

Готово 🙂

Я надеюсь, что смогу помочь с этим ответом.

Также благодаря Роману Р.

Обновить

Этот пример работает только с форматами Audio-PCM от 4 до 24 бит. Если вы хотите кодировать 32-битный Audio-PCM, вы должны сначала повторно сэмплировать его, а затем кодировать.

———

Вот минимальный пример приложения.

#include <windows.h>
#include <windowsx.h>

#include <atlstr.h>
#include <comdef.h>
#include <exception>

#include <mfapi.h>
#include <mfplay.h>
#include <mfreadwrite.h>
#include <mmdeviceapi.h>
#include <Audioclient.h>
#include <mferror.h>
#include <Wmcodecdsp.h>

#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfplay.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")
#pragma comment(lib, "wmcodecdspuuid")inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Get the error message
_com_error err(hr);
LPCTSTR errMsg = err.ErrorMessage();

OutputDebugString(L"################################## ERROR ##################################\n");
OutputDebugString(errMsg);
OutputDebugString(L"\n################################## ----- ##################################\n");

CStringA sb(errMsg);
// Set a breakpoint on this line to catch DirectX API errors
throw std::exception(sb);
}
}

template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = nullptr;
}
}

using namespace System;

HRESULT GetOutputMediaTypes(
GUID cAudioFormat,
UINT32 cSampleRate,
UINT32 cBitPerSample,
UINT32 cChannels,
IMFMediaType **ppType
)
{
// Enumerate all codecs except for codecs with field-of-use restrictions.
// Sort the results.
DWORD dwFlags =
(MFT_ENUM_FLAG_ALL & (~MFT_ENUM_FLAG_FIELDOFUSE)) |
MFT_ENUM_FLAG_SORTANDFILTER;

IMFCollection   *pAvailableTypes = NULL;    // List of audio media types.
IMFMediaType    *pAudioType = NULL;         // Corresponding codec.

HRESULT hr = MFTranscodeGetAudioOutputAvailableTypes(
cAudioFormat,
dwFlags,
NULL,
&pAvailableTypes
);

// Get the element count.
DWORD dwMTCount;
hr = pAvailableTypes->GetElementCount(&dwMTCount);

// Iterate through the results and check for the corresponding codec.
for (DWORD i = 0; i < dwMTCount; i++)
{
hr = pAvailableTypes->GetElement(i, (IUnknown**)&pAudioType);

GUID majorType;
hr = pAudioType->GetMajorType(&majorType);

GUID subType;
hr = pAudioType->GetGUID(MF_MT_SUBTYPE, &subType);

if (majorType != MFMediaType_Audio || subType != MFAudioFormat_FLAC)
{
continue;
}

UINT32 sampleRate = NULL;
hr = pAudioType->GetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND,
&sampleRate
);

UINT32 bitRate = NULL;
hr = pAudioType->GetUINT32(
MF_MT_AUDIO_BITS_PER_SAMPLE,
&bitRate
);

UINT32 channels = NULL;
hr = pAudioType->GetUINT32(
MF_MT_AUDIO_NUM_CHANNELS,
&channels
);

if (sampleRate == cSampleRate
&& bitRate == cBitPerSample
&& channels == cChannels)
{
// Found the codec.
// Jump out!
break;
}
}

// Add the media type to the caller
*ppType = pAudioType;
(*ppType)->AddRef();
SafeRelease(&pAudioType);

return hr;
}

int main(array<System::String ^> ^args)
{
HRESULT hr = S_OK;

// Initialize com interface
ThrowIfFailed(
CoInitializeEx(0, COINIT_MULTITHREADED)
);

// Start media foundation
ThrowIfFailed(
MFStartup(MF_VERSION)
);

IMFMediaType        *pInputType = NULL;
IMFSourceReader     *pSourceReader = NULL;
IMFMediaType        *pOuputMediaType = NULL;
IMFSinkWriter       *pSinkWriter = NULL;

// Create source reader
hr = MFCreateSourceReaderFromURL(
L"C:\\Temp\\48khz24bit.wav",
NULL,
&pSourceReader
);

// Create sink writer
hr = MFCreateSinkWriterFromURL(
L"C:\\Temp\\foo.flac",
NULL,
NULL,
&pSinkWriter
);

// Get media type from source reader
hr = pSourceReader->GetCurrentMediaType(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
&pInputType
);

// Get sample rate, bit rate and channels
UINT32 sampleRate = NULL;
hr = pInputType->GetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND,
&sampleRate
);

UINT32 bitRate = NULL;
hr = pInputType->GetUINT32(
MF_MT_AUDIO_BITS_PER_SAMPLE,
&bitRate
);

UINT32 channels = NULL;
hr = pInputType->GetUINT32(
MF_MT_AUDIO_NUM_CHANNELS,
&channels
);

// Try to find a media type that is fitting.
hr = GetOutputMediaTypes(
MFAudioFormat_FLAC,
sampleRate,
bitRate,
channels,
&pOuputMediaType);

DWORD dwWriterStreamIndex = -1;

// Add the stream
hr = pSinkWriter->AddStream(
pOuputMediaType,
&dwWriterStreamIndex
);

// Set input media type
hr = pSinkWriter->SetInputMediaType(
dwWriterStreamIndex,
pInputType,
NULL
);

// Tell the sink writer to accept data
hr = pSinkWriter->BeginWriting();

// Forever alone loop
for (;;)
{
DWORD nStreamIndex, nStreamFlags;
LONGLONG nTime;
IMFSample *pSample;

// Read through the samples until...
hr = pSourceReader->ReadSample(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0,
&nStreamIndex,
&nStreamFlags,
&nTime,
&pSample);

if (pSample)
{
OutputDebugString(L"Write sample...\n");

hr = pSinkWriter->WriteSample(
dwWriterStreamIndex,
pSample
);
}

// ... we are at the end of the stream...
if (nStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
// ... and jump out.
break;
}
}

// Call finalize to finish writing.
hr = pSinkWriter->Finalize();

// Done :D
return 0;
}
1

По вопросам рекламы [email protected]