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+ " \t bitrate: %d\n "
181+ " \t channels: %d\n "
182+ " \t sample rate: %d\n "
183+ " \t bits-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 (¤tLength));
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