Skip to content

Commit 7319ec6

Browse files
author
thirumalai-qcom
committed
win-mf: Add Media Foundation ACC encoder for WoA
This commit introduces AAC encoder support using the Media Foundation Transform (MFT) interface, specifically targeting Windows on ARM (WoA) devices with Qualcomm hardware. It adds mf-aac.cpp and mf-aac-encoder.cpp/.hpp to implement the encoding logic. Additionally, CMakeLists.txt is updated to include the new source and header files for proper integration into the win-mf plugin
1 parent 57e8999 commit 7319ec6

File tree

4 files changed

+572
-0
lines changed

4 files changed

+572
-0
lines changed

plugins/win-mf/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ set(
99
mf-h264-encoder.cpp
1010
mf-hevc.cpp
1111
mf-hevc-encoder.cpp
12+
mf-aac.cpp
13+
mf-aac-encoder.cpp
1214
)
1315

1416
set(
@@ -17,6 +19,7 @@ set(
1719
mf-encoder-descriptor.hpp
1820
mf-h264-encoder.hpp
1921
mf-hevc-encoder.hpp
22+
mf-aac-encoder.hpp
2023
)
2124

2225
add_library(win-mf MODULE ${win-mf_SOURCES} ${win-mf_HEADERS})

plugins/win-mf/mf-aac-encoder.cpp

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
#include <obs-module.h>
2+
3+
#include "mf-aac-encoder.hpp"
4+
5+
#include <mferror.h>
6+
#include <mftransform.h>
7+
#include <wmcodecdsp.h>
8+
#include <comdef.h>
9+
10+
#define MF_LOG_AAC(level, format, ...) MF_LOG_ENCODER("AAC", ObsEncoder(), level, format, ##__VA_ARGS__)
11+
12+
#define MF_LOG_COM(msg, hr) MF_LOG_AAC(LOG_ERROR, msg " failed, %S (0x%08lx)", _com_error(hr).ErrorMessage(), hr)
13+
14+
#define HRC(r) \
15+
if (FAILED(hr = (r))) { \
16+
MF_LOG_COM(#r, hr); \
17+
goto fail; \
18+
}
19+
20+
using namespace MFAAC;
21+
22+
#define CONST_ARRAY(name, ...) static const UINT32 name[] = {__VA_ARGS__};
23+
24+
CONST_ARRAY(VALID_BITRATES, 96, 128, 160, 192);
25+
CONST_ARRAY(VALID_CHANNELS, 1, 2);
26+
CONST_ARRAY(VALID_BITS_PER_SAMPLE, 16);
27+
CONST_ARRAY(VALID_SAMPLERATES, 44100, 48000);
28+
29+
#undef CONST_ARRAY
30+
31+
template<int N> static UINT32 FindBestMatch(const UINT32 (&validValues)[N], UINT32 value)
32+
{
33+
for (UINT32 val : validValues) {
34+
if (val >= value)
35+
return val;
36+
}
37+
38+
// Only downgrade if no values are better
39+
return validValues[N - 1];
40+
}
41+
42+
template<int N> static bool IsValid(const UINT32 (&validValues)[N], UINT32 value)
43+
{
44+
for (UINT32 val : validValues) {
45+
if (val == value)
46+
return true;
47+
}
48+
49+
return false;
50+
};
51+
52+
UINT32 MFAAC::FindBestBitrateMatch(UINT32 value)
53+
{
54+
return FindBestMatch(VALID_BITRATES, value);
55+
}
56+
57+
UINT32 MFAAC::FindBestChannelsMatch(UINT32 value)
58+
{
59+
return FindBestMatch(VALID_CHANNELS, value);
60+
}
61+
62+
UINT32 MFAAC::FindBestBitsPerSampleMatch(UINT32 value)
63+
{
64+
return FindBestMatch(VALID_BITS_PER_SAMPLE, value);
65+
}
66+
67+
UINT32 MFAAC::FindBestSamplerateMatch(UINT32 value)
68+
{
69+
return FindBestMatch(VALID_SAMPLERATES, value);
70+
}
71+
72+
bool MFAAC::BitrateValid(UINT32 value)
73+
{
74+
return IsValid(VALID_BITRATES, value);
75+
}
76+
77+
bool MFAAC::ChannelsValid(UINT32 value)
78+
{
79+
return IsValid(VALID_CHANNELS, value);
80+
}
81+
82+
bool MFAAC::BitsPerSampleValid(UINT32 value)
83+
{
84+
return IsValid(VALID_BITS_PER_SAMPLE, value);
85+
}
86+
87+
bool MFAAC::SamplerateValid(UINT32 value)
88+
{
89+
return IsValid(VALID_SAMPLERATES, value);
90+
}
91+
92+
HRESULT MFAAC::Encoder::CreateMediaTypes(ComPtr<IMFMediaType> &i, ComPtr<IMFMediaType> &o)
93+
{
94+
HRESULT hr;
95+
HRC(MFCreateMediaType(&i));
96+
HRC(MFCreateMediaType(&o));
97+
98+
HRC(i->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
99+
HRC(i->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM));
100+
HRC(i->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample));
101+
HRC(i->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, sampleRate));
102+
HRC(i->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, channels));
103+
104+
HRC(o->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
105+
HRC(o->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC));
106+
HRC(o->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample));
107+
HRC(o->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, sampleRate));
108+
HRC(o->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, channels));
109+
HRC(o->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, (bitrate * 1000) / 8));
110+
111+
return S_OK;
112+
fail:
113+
return hr;
114+
}
115+
116+
void MFAAC::Encoder::InitializeExtraData()
117+
{
118+
UINT16 *extraData16 = (UINT16 *)extraData;
119+
UINT16 profile = 2; //Low Complexity
120+
#define SWAPU16(x) (x >> 8) | (x << 8)
121+
// Profile
122+
// XXXX X... .... ....
123+
*extraData16 = profile << 11;
124+
// Sample Index (3=48, 4=44.1)
125+
// .... .XXX X... ....
126+
*extraData16 |= (sampleRate == 48000 ? 3 : 4) << 7;
127+
// Channels
128+
// .... .... .XXX X...
129+
*extraData16 |= channels << 3;
130+
*extraData16 = SWAPU16(*extraData16);
131+
132+
// Extensions
133+
extraData16++;
134+
*extraData16 = 0x2b7 << 5;
135+
// Profile
136+
*extraData16 |= profile;
137+
*extraData16 = SWAPU16(*extraData16);
138+
139+
extraData[4] = 0;
140+
#undef SWAPU16
141+
}
142+
143+
bool MFAAC::Encoder::Initialize()
144+
{
145+
HRESULT hr;
146+
147+
ComPtr<IMFTransform> transform_;
148+
ComPtr<IMFMediaType> inputType, outputType;
149+
150+
if (!BitrateValid(bitrate)) {
151+
MF_LOG_AAC(LOG_WARNING, "invalid bitrate (kbps) '%d'", bitrate);
152+
return false;
153+
}
154+
if (!ChannelsValid(channels)) {
155+
MF_LOG_AAC(LOG_WARNING, "invalid channel count '%d", channels);
156+
return false;
157+
}
158+
if (!SamplerateValid(sampleRate)) {
159+
MF_LOG_AAC(LOG_WARNING, "invalid sample rate (hz) '%d", sampleRate);
160+
return false;
161+
}
162+
if (!BitsPerSampleValid(bitsPerSample)) {
163+
MF_LOG_AAC(LOG_WARNING, "invalid bits-per-sample (bits) '%d'", bitsPerSample);
164+
return false;
165+
}
166+
167+
InitializeExtraData();
168+
169+
HRC(CoCreateInstance(CLSID_AACMFTEncoder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&transform_)));
170+
HRC(CreateMediaTypes(inputType, outputType));
171+
172+
HRC(transform_->SetInputType(0, inputType.Get(), 0));
173+
HRC(transform_->SetOutputType(0, outputType.Get(), 0));
174+
175+
HRC(transform_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL));
176+
HRC(transform_->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL));
177+
178+
MF_LOG_AAC(LOG_INFO,
179+
"encoder created\n"
180+
"\tbitrate: %d\n"
181+
"\tchannels: %d\n"
182+
"\tsample rate: %d\n"
183+
"\tbits-per-sample: %d\n",
184+
bitrate, channels, sampleRate, bitsPerSample);
185+
186+
transform = transform_;
187+
return true;
188+
189+
fail:
190+
return false;
191+
}
192+
193+
HRESULT MFAAC::Encoder::CreateEmptySample(ComPtr<IMFSample> &sample, ComPtr<IMFMediaBuffer> &buffer, DWORD length)
194+
{
195+
HRESULT hr;
196+
197+
HRC(MFCreateSample(&sample));
198+
HRC(MFCreateMemoryBuffer(length, &buffer));
199+
HRC(sample->AddBuffer(buffer.Get()));
200+
return S_OK;
201+
202+
fail:
203+
return hr;
204+
}
205+
206+
HRESULT MFAAC::Encoder::EnsureCapacity(ComPtr<IMFSample> &sample, DWORD length)
207+
{
208+
HRESULT hr;
209+
ComPtr<IMFMediaBuffer> buffer;
210+
DWORD currentLength;
211+
212+
if (!sample) {
213+
HRC(CreateEmptySample(sample, buffer, length));
214+
} else {
215+
HRC(sample->GetBufferByIndex(0, &buffer));
216+
}
217+
218+
HRC(buffer->GetMaxLength(&currentLength));
219+
if (currentLength < length) {
220+
HRC(sample->RemoveAllBuffers());
221+
HRC(MFCreateMemoryBuffer(length, &buffer));
222+
HRC(sample->AddBuffer(buffer));
223+
} else {
224+
buffer->SetCurrentLength(0);
225+
}
226+
227+
packetBuffer.reserve(length);
228+
229+
return S_OK;
230+
231+
fail:
232+
return hr;
233+
}
234+
235+
bool MFAAC::Encoder::ProcessInput(UINT8 *data, UINT32 data_length, UINT64 pts, Status *status)
236+
{
237+
HRESULT hr;
238+
ComPtr<IMFSample> sample;
239+
ComPtr<IMFMediaBuffer> buffer;
240+
BYTE *bufferData;
241+
INT64 samplePts;
242+
UINT32 samples;
243+
UINT64 sampleDur;
244+
245+
HRC(CreateEmptySample(sample, buffer, data_length));
246+
247+
HRC(buffer->Lock(&bufferData, NULL, NULL));
248+
memcpy(bufferData, data, data_length);
249+
HRC(buffer->Unlock());
250+
HRC(buffer->SetCurrentLength(data_length));
251+
252+
samples = data_length / channels / (bitsPerSample / 8);
253+
sampleDur = (UINT64)(((float)sampleRate / channels / samples) * 10000);
254+
samplePts = pts / 100;
255+
256+
HRC(sample->SetSampleTime(samplePts));
257+
HRC(sample->SetSampleDuration(sampleDur));
258+
259+
hr = transform->ProcessInput(0, sample, 0);
260+
if (hr == MF_E_NOTACCEPTING) {
261+
*status = NOT_ACCEPTING;
262+
return true;
263+
} else if (FAILED(hr)) {
264+
MF_LOG_COM("process input", hr);
265+
return false;
266+
}
267+
268+
*status = SUCCESS;
269+
return true;
270+
271+
fail:
272+
*status = FAILURE;
273+
return false;
274+
}
275+
276+
bool MFAAC::Encoder::ProcessOutput(UINT8 **data, UINT32 *dataLength, UINT64 *pts, Status *status)
277+
{
278+
HRESULT hr;
279+
280+
DWORD outputFlags, outputStatus;
281+
MFT_OUTPUT_STREAM_INFO outputInfo = {0};
282+
MFT_OUTPUT_DATA_BUFFER output = {0};
283+
ComPtr<IMFMediaBuffer> outputBuffer;
284+
BYTE *bufferData;
285+
DWORD bufferLength;
286+
INT64 samplePts;
287+
288+
HRC(transform->GetOutputStatus(&outputFlags));
289+
if (outputFlags != MFT_OUTPUT_STATUS_SAMPLE_READY) {
290+
*status = NEED_MORE_INPUT;
291+
return true;
292+
}
293+
294+
HRC(transform->GetOutputStreamInfo(0, &outputInfo));
295+
EnsureCapacity(outputSample, outputInfo.cbSize);
296+
297+
output.pSample = outputSample.Get();
298+
299+
hr = transform->ProcessOutput(0, 1, &output, &outputStatus);
300+
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
301+
*status = NEED_MORE_INPUT;
302+
return true;
303+
} else if (FAILED(hr)) {
304+
MF_LOG_COM("process output", hr);
305+
return false;
306+
}
307+
308+
HRC(outputSample->GetBufferByIndex(0, &outputBuffer));
309+
310+
HRC(outputBuffer->Lock(&bufferData, NULL, &bufferLength));
311+
packetBuffer.assign(bufferData, bufferData + bufferLength);
312+
HRC(outputBuffer->Unlock());
313+
314+
HRC(outputSample->GetSampleTime(&samplePts));
315+
316+
*pts = samplePts * 100;
317+
*data = &packetBuffer[0];
318+
*dataLength = bufferLength;
319+
*status = SUCCESS;
320+
return true;
321+
322+
fail:
323+
*status = FAILURE;
324+
return false;
325+
}
326+
327+
bool MFAAC::Encoder::ExtraData(UINT8 **extraData_, UINT32 *extraDataLength)
328+
{
329+
*extraData_ = extraData;
330+
*extraDataLength = sizeof(extraData);
331+
return true;
332+
}

0 commit comments

Comments
 (0)