winegstreamer: Also return output with 2 channels for multichannel inputs from AAC...
[wine.git] / dlls / winegstreamer / aac_decoder.c
blob3eb96d0106adc6c4fe5b781f2c33f56bb777d856
1 /* AAC Decoder Transform
3 * Copyright 2022 RĂ©mi Bernon for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "gst_private.h"
22 #include "mfapi.h"
23 #include "mferror.h"
24 #include "mfobjects.h"
25 #include "mftransform.h"
26 #include "wmcodecdsp.h"
27 #include "ks.h"
28 #include "ksmedia.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
33 WINE_DECLARE_DEBUG_CHANNEL(winediag);
35 static struct
37 const GUID *const guid;
38 UINT32 payload_type;
39 } aac_decoder_input_types[] =
41 {&MFAudioFormat_AAC, 0},
42 {&MFAudioFormat_RAW_AAC, -1},
43 {&MFAudioFormat_AAC, 1},
44 {&MFAudioFormat_AAC, 3},
45 {&MFAudioFormat_ADTS, -1},
47 static const GUID *const aac_decoder_output_types[] =
49 &MFAudioFormat_PCM,
50 &MFAudioFormat_Float,
53 static const UINT32 default_channel_mask[7] =
58 SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER,
59 KSAUDIO_SPEAKER_QUAD,
60 KSAUDIO_SPEAKER_QUAD | SPEAKER_FRONT_CENTER,
61 KSAUDIO_SPEAKER_5POINT1,
64 struct aac_decoder
66 IMFTransform IMFTransform_iface;
67 LONG refcount;
68 IMFMediaType *input_type;
69 IMFMediaType *output_type;
71 wg_transform_t wg_transform;
72 struct wg_sample_queue *wg_sample_queue;
75 static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface)
77 return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface);
80 static HRESULT try_create_wg_transform(struct aac_decoder *decoder)
82 struct wg_format input_format, output_format;
83 struct wg_transform_attrs attrs = {0};
85 if (decoder->wg_transform)
86 wg_transform_destroy(decoder->wg_transform);
87 decoder->wg_transform = 0;
89 mf_media_type_to_wg_format(decoder->input_type, &input_format);
90 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
91 return MF_E_INVALIDMEDIATYPE;
93 mf_media_type_to_wg_format(decoder->output_type, &output_format);
94 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
95 return MF_E_INVALIDMEDIATYPE;
97 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs)))
98 return E_FAIL;
100 return S_OK;
103 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
105 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
107 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
109 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform))
110 *out = &decoder->IMFTransform_iface;
111 else
113 *out = NULL;
114 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
115 return E_NOINTERFACE;
118 IUnknown_AddRef((IUnknown *)*out);
119 return S_OK;
122 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
124 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
125 ULONG refcount = InterlockedIncrement(&decoder->refcount);
126 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
127 return refcount;
130 static ULONG WINAPI transform_Release(IMFTransform *iface)
132 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
133 ULONG refcount = InterlockedDecrement(&decoder->refcount);
135 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
137 if (!refcount)
139 if (decoder->wg_transform)
140 wg_transform_destroy(decoder->wg_transform);
141 if (decoder->input_type)
142 IMFMediaType_Release(decoder->input_type);
143 if (decoder->output_type)
144 IMFMediaType_Release(decoder->output_type);
145 wg_sample_queue_destroy(decoder->wg_sample_queue);
146 free(decoder);
149 return refcount;
152 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
153 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
155 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
156 iface, input_minimum, input_maximum, output_minimum, output_maximum);
157 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
158 return S_OK;
161 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
163 TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
164 *inputs = *outputs = 1;
165 return S_OK;
168 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
169 DWORD output_size, DWORD *outputs)
171 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
172 input_size, inputs, output_size, outputs);
173 return E_NOTIMPL;
176 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
178 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
180 if (id)
181 return MF_E_INVALIDSTREAMNUMBER;
183 memset(info, 0, sizeof(*info));
184 info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
185 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_INPUT_STREAM_HOLDS_BUFFERS;
187 return S_OK;
190 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
192 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
194 if (id)
195 return MF_E_INVALIDSTREAMNUMBER;
197 memset(info, 0, sizeof(*info));
198 info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES;
199 info->cbSize = 0xc000;
201 return S_OK;
204 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
206 TRACE("iface %p, attributes %p.\n", iface, attributes);
207 return E_NOTIMPL;
210 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
212 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
213 return E_NOTIMPL;
216 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
218 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
219 return E_NOTIMPL;
222 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
224 TRACE("iface %p, id %#lx.\n", iface, id);
225 return E_NOTIMPL;
228 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
230 TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
231 return E_NOTIMPL;
234 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
235 IMFMediaType **type)
237 IMFMediaType *media_type;
238 const GUID *subtype;
239 HRESULT hr;
241 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
243 if (id)
244 return MF_E_INVALIDSTREAMNUMBER;
246 *type = NULL;
247 if (index >= ARRAY_SIZE(aac_decoder_input_types))
248 return MF_E_NO_MORE_TYPES;
249 subtype = aac_decoder_input_types[index].guid;
251 if (FAILED(hr = MFCreateMediaType(&media_type)))
252 return hr;
254 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
255 goto done;
256 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
257 goto done;
259 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 32)))
260 goto done;
261 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, 6)))
262 goto done;
263 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, 24)))
264 goto done;
265 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000)))
266 goto done;
267 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 1152000)))
268 goto done;
269 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
270 goto done;
271 if (IsEqualGUID(subtype, &MFAudioFormat_AAC))
273 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0)))
274 goto done;
275 if (aac_decoder_input_types[index].payload_type != -1
276 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_PAYLOAD_TYPE,
277 aac_decoder_input_types[index].payload_type)))
278 goto done;
281 done:
282 if (SUCCEEDED(hr))
283 IMFMediaType_AddRef((*type = media_type));
285 IMFMediaType_Release(media_type);
286 return hr;
289 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
290 IMFMediaType **type)
292 UINT32 channel_count, sample_size, sample_rate, block_alignment;
293 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
294 IMFMediaType *media_type;
295 const GUID *output_type;
296 HRESULT hr;
298 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
300 if (id)
301 return MF_E_INVALIDSTREAMNUMBER;
302 if (!decoder->input_type)
303 return MF_E_TRANSFORM_TYPE_NOT_SET;
305 *type = NULL;
307 if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))
308 || !channel_count)
309 channel_count = 2;
311 if (channel_count >= ARRAY_SIZE(default_channel_mask))
312 return MF_E_INVALIDMEDIATYPE;
314 if (channel_count > 2 && index >= ARRAY_SIZE(aac_decoder_output_types))
316 /* If there are more than two channels in the input type GetOutputAvailableType additionally lists
317 * types with 2 channels. */
318 index -= ARRAY_SIZE(aac_decoder_output_types);
319 channel_count = 2;
322 if (index >= ARRAY_SIZE(aac_decoder_output_types))
323 return MF_E_NO_MORE_TYPES;
324 index = ARRAY_SIZE(aac_decoder_output_types) - index - 1;
325 output_type = aac_decoder_output_types[index];
327 if (FAILED(hr = MFCreateMediaType(&media_type)))
328 return hr;
330 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
331 goto done;
332 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
333 goto done;
335 if (IsEqualGUID(output_type, &MFAudioFormat_Float))
336 sample_size = 32;
337 else if (IsEqualGUID(output_type, &MFAudioFormat_PCM))
338 sample_size = 16;
339 else
341 FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type));
342 hr = E_NOTIMPL;
343 goto done;
346 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size)))
347 goto done;
349 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count)))
350 goto done;
352 if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate)))
353 goto done;
354 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate)))
355 goto done;
357 block_alignment = sample_size * channel_count / 8;
358 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment)))
359 goto done;
360 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, sample_rate * block_alignment)))
361 goto done;
363 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1)))
364 goto done;
365 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1)))
366 goto done;
367 if (channel_count < 3 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
368 goto done;
369 if (channel_count >= 3 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK,
370 default_channel_mask[channel_count])))
371 goto done;
373 done:
374 if (SUCCEEDED(hr))
375 IMFMediaType_AddRef((*type = media_type));
377 IMFMediaType_Release(media_type);
378 return hr;
381 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
383 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
384 MF_ATTRIBUTE_TYPE item_type;
385 UINT32 channel_count;
386 GUID major, subtype;
387 HRESULT hr;
388 ULONG i;
390 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
392 if (id)
393 return MF_E_INVALIDSTREAMNUMBER;
395 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)))
396 return E_INVALIDARG;
398 if (!IsEqualGUID(&major, &MFMediaType_Audio)
399 || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
400 return MF_E_INVALIDMEDIATYPE;
402 for (i = 0; i < ARRAY_SIZE(aac_decoder_input_types); ++i)
403 if (IsEqualGUID(&subtype, aac_decoder_input_types[i].guid))
404 break;
405 if (i == ARRAY_SIZE(aac_decoder_input_types))
406 return MF_E_INVALIDMEDIATYPE;
408 if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))
409 && channel_count >= ARRAY_SIZE(default_channel_mask))
410 return MF_E_INVALIDMEDIATYPE;
412 if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type))
413 || item_type != MF_ATTRIBUTE_UINT32)
414 return MF_E_INVALIDMEDIATYPE;
415 if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_USER_DATA, &item_type))
416 || item_type != MF_ATTRIBUTE_BLOB)
417 return MF_E_INVALIDMEDIATYPE;
418 if (flags & MFT_SET_TYPE_TEST_ONLY)
419 return S_OK;
421 if (!decoder->input_type && FAILED(hr = MFCreateMediaType(&decoder->input_type)))
422 return hr;
424 if (decoder->output_type)
426 IMFMediaType_Release(decoder->output_type);
427 decoder->output_type = NULL;
430 return IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type);
433 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
435 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
436 MF_ATTRIBUTE_TYPE item_type;
437 GUID major, subtype;
438 HRESULT hr;
439 ULONG i;
441 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
443 if (id)
444 return MF_E_INVALIDSTREAMNUMBER;
445 if (!decoder->input_type)
446 return MF_E_TRANSFORM_TYPE_NOT_SET;
448 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major))
449 || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
450 return hr;
452 if (!IsEqualGUID(&major, &MFMediaType_Audio))
453 return MF_E_INVALIDMEDIATYPE;
455 for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i)
456 if (IsEqualGUID(&subtype, aac_decoder_output_types[i]))
457 break;
458 if (i == ARRAY_SIZE(aac_decoder_output_types))
459 return MF_E_INVALIDMEDIATYPE;
461 if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type))
462 || item_type != MF_ATTRIBUTE_UINT32)
463 return MF_E_INVALIDMEDIATYPE;
464 if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type))
465 || item_type != MF_ATTRIBUTE_UINT32)
466 return MF_E_INVALIDMEDIATYPE;
467 if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type))
468 || item_type != MF_ATTRIBUTE_UINT32)
469 return MF_E_INVALIDMEDIATYPE;
470 if (flags & MFT_SET_TYPE_TEST_ONLY)
471 return S_OK;
473 if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type)))
474 return hr;
476 if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type)))
477 return hr;
479 if (FAILED(hr = try_create_wg_transform(decoder)))
480 goto failed;
482 return S_OK;
484 failed:
485 IMFMediaType_Release(decoder->output_type);
486 decoder->output_type = NULL;
487 return hr;
490 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out)
492 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
493 IMFMediaType *type;
494 HRESULT hr;
496 TRACE("iface %p, id %#lx, out %p.\n", iface, id, out);
498 if (id)
499 return MF_E_INVALIDSTREAMNUMBER;
500 if (!decoder->input_type)
501 return MF_E_TRANSFORM_TYPE_NOT_SET;
503 if (FAILED(hr = MFCreateMediaType(&type)))
504 return hr;
505 if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(decoder->input_type, (IMFAttributes *)type)))
506 IMFMediaType_AddRef(*out = type);
507 IMFMediaType_Release(type);
509 return hr;
512 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out)
514 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
515 IMFMediaType *type;
516 HRESULT hr;
518 TRACE("iface %p, id %#lx, out %p.\n", iface, id, out);
520 if (id)
521 return MF_E_INVALIDSTREAMNUMBER;
522 if (!decoder->output_type)
523 return MF_E_TRANSFORM_TYPE_NOT_SET;
525 if (FAILED(hr = MFCreateMediaType(&type)))
526 return hr;
527 if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)type)))
528 IMFMediaType_AddRef(*out = type);
529 IMFMediaType_Release(type);
531 return hr;
534 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
536 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
537 bool accepts_input;
538 HRESULT hr;
540 TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags);
542 if (!decoder->wg_transform)
543 return MF_E_TRANSFORM_TYPE_NOT_SET;
545 if (FAILED(hr = wg_transform_get_status(decoder->wg_transform, &accepts_input)))
546 return hr;
548 *flags = accepts_input ? MFT_INPUT_STATUS_ACCEPT_DATA : 0;
549 return S_OK;
552 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
554 FIXME("iface %p, flags %p stub!\n", iface, flags);
555 return E_NOTIMPL;
558 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
560 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
561 return E_NOTIMPL;
564 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
566 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
567 return E_NOTIMPL;
570 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
572 FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param);
573 return S_OK;
576 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
578 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
580 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
582 if (!decoder->wg_transform)
583 return MF_E_TRANSFORM_TYPE_NOT_SET;
585 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
588 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
589 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
591 struct aac_decoder *decoder = impl_from_IMFTransform(iface);
592 MFT_OUTPUT_STREAM_INFO info;
593 HRESULT hr;
595 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
597 if (count != 1)
598 return E_INVALIDARG;
600 if (!decoder->wg_transform)
601 return MF_E_TRANSFORM_TYPE_NOT_SET;
603 *status = samples->dwStatus = 0;
604 if (!samples->pSample)
605 return E_INVALIDARG;
607 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info)))
608 return hr;
610 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample,
611 info.cbSize, NULL, &samples->dwStatus)))
612 wg_sample_queue_flush(decoder->wg_sample_queue, false);
613 else
614 samples->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;
616 return hr;
619 static const IMFTransformVtbl transform_vtbl =
621 transform_QueryInterface,
622 transform_AddRef,
623 transform_Release,
624 transform_GetStreamLimits,
625 transform_GetStreamCount,
626 transform_GetStreamIDs,
627 transform_GetInputStreamInfo,
628 transform_GetOutputStreamInfo,
629 transform_GetAttributes,
630 transform_GetInputStreamAttributes,
631 transform_GetOutputStreamAttributes,
632 transform_DeleteInputStream,
633 transform_AddInputStreams,
634 transform_GetInputAvailableType,
635 transform_GetOutputAvailableType,
636 transform_SetInputType,
637 transform_SetOutputType,
638 transform_GetInputCurrentType,
639 transform_GetOutputCurrentType,
640 transform_GetInputStatus,
641 transform_GetOutputStatus,
642 transform_SetOutputBounds,
643 transform_ProcessEvent,
644 transform_ProcessMessage,
645 transform_ProcessInput,
646 transform_ProcessOutput,
649 HRESULT aac_decoder_create(REFIID riid, void **ret)
651 static const struct wg_format output_format =
653 .major_type = WG_MAJOR_TYPE_AUDIO,
654 .u.audio =
656 .format = WG_AUDIO_FORMAT_F32LE,
657 .channel_mask = 1,
658 .channels = 1,
659 .rate = 44100,
662 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_MPEG4};
663 struct wg_transform_attrs attrs = {0};
664 wg_transform_t transform;
665 struct aac_decoder *decoder;
666 HRESULT hr;
668 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
670 if (!(transform = wg_transform_create(&input_format, &output_format, &attrs)))
672 ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n");
673 return E_FAIL;
675 wg_transform_destroy(transform);
677 if (!(decoder = calloc(1, sizeof(*decoder))))
678 return E_OUTOFMEMORY;
680 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
682 free(decoder);
683 return hr;
686 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
687 decoder->refcount = 1;
689 *ret = &decoder->IMFTransform_iface;
690 TRACE("Created decoder %p\n", *ret);
691 return S_OK;