1 /* GStreamer Audio Converter
3 * Copyright 2020 Derek Lesho
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"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
31 struct audio_converter
33 IMFTransform IMFTransform_iface
;
35 IMFMediaType
*input_type
;
36 IMFMediaType
*output_type
;
40 static struct audio_converter
*impl_audio_converter_from_IMFTransform(IMFTransform
*iface
)
42 return CONTAINING_RECORD(iface
, struct audio_converter
, IMFTransform_iface
);
45 static HRESULT WINAPI
audio_converter_QueryInterface(IMFTransform
*iface
, REFIID riid
, void **obj
)
47 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
49 if (IsEqualIID(riid
, &IID_IMFTransform
) ||
50 IsEqualIID(riid
, &IID_IUnknown
))
53 IMFTransform_AddRef(iface
);
57 WARN("Unsupported %s.\n", debugstr_guid(riid
));
62 static ULONG WINAPI
audio_converter_AddRef(IMFTransform
*iface
)
64 struct audio_converter
*transform
= impl_audio_converter_from_IMFTransform(iface
);
65 ULONG refcount
= InterlockedIncrement(&transform
->refcount
);
67 TRACE("%p, refcount %u.\n", iface
, refcount
);
72 static ULONG WINAPI
audio_converter_Release(IMFTransform
*iface
)
74 struct audio_converter
*transform
= impl_audio_converter_from_IMFTransform(iface
);
75 ULONG refcount
= InterlockedDecrement(&transform
->refcount
);
77 TRACE("%p, refcount %u.\n", iface
, refcount
);
81 transform
->cs
.DebugInfo
->Spare
[0] = 0;
82 DeleteCriticalSection(&transform
->cs
);
89 static HRESULT WINAPI
audio_converter_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
, DWORD
*input_maximum
,
90 DWORD
*output_minimum
, DWORD
*output_maximum
)
92 TRACE("%p, %p, %p, %p, %p.\n", iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
94 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
99 static HRESULT WINAPI
audio_converter_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
101 TRACE("%p, %p, %p.\n", iface
, inputs
, outputs
);
103 *inputs
= *outputs
= 1;
108 static HRESULT WINAPI
audio_converter_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
109 DWORD output_size
, DWORD
*outputs
)
111 TRACE("%p %u %p %u %p.\n", iface
, input_size
, inputs
, output_size
, outputs
);
116 static HRESULT WINAPI
audio_converter_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
118 FIXME("%p %u %p.\n", iface
, id
, info
);
123 static HRESULT WINAPI
audio_converter_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
125 FIXME("%p %u %p.\n", iface
, id
, info
);
130 static HRESULT WINAPI
audio_converter_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
132 FIXME("%p, %p.\n", iface
, attributes
);
137 static HRESULT WINAPI
audio_converter_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
,
138 IMFAttributes
**attributes
)
140 FIXME("%p, %u, %p.\n", iface
, id
, attributes
);
145 static HRESULT WINAPI
audio_converter_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
,
146 IMFAttributes
**attributes
)
148 FIXME("%p, %u, %p.\n", iface
, id
, attributes
);
153 static HRESULT WINAPI
audio_converter_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
155 TRACE("%p, %u.\n", iface
, id
);
160 static HRESULT WINAPI
audio_converter_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
162 TRACE("%p, %u, %p.\n", iface
, streams
, ids
);
167 static HRESULT WINAPI
audio_converter_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
173 TRACE("%p, %u, %u, %p.\n", iface
, id
, index
, type
);
176 return MF_E_INVALIDSTREAMNUMBER
;
179 return MF_E_NO_MORE_TYPES
;
181 if (FAILED(hr
= MFCreateMediaType(&ret
)))
184 if (FAILED(hr
= IMFMediaType_SetGUID(ret
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Audio
)))
186 IMFMediaType_Release(ret
);
190 if (FAILED(hr
= IMFMediaType_SetGUID(ret
, &MF_MT_SUBTYPE
, index
? &MFAudioFormat_Float
: &MFAudioFormat_PCM
)))
192 IMFMediaType_Release(ret
);
201 static HRESULT WINAPI
audio_converter_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
204 IMFMediaType
*output_type
;
214 {&MFAudioFormat_PCM
, 16},
215 {&MFAudioFormat_PCM
, 24},
216 {&MFAudioFormat_PCM
, 32},
217 {&MFAudioFormat_Float
, 32},
220 static const DWORD rates
[] = {44100, 48000};
221 static const DWORD channel_cnts
[] = {1, 2, 6};
223 DWORD rate
, channels
, bps
;
225 TRACE("%p, %u, %u, %p.\n", iface
, id
, index
, type
);
228 return MF_E_INVALIDSTREAMNUMBER
;
230 if (index
>= ARRAY_SIZE(formats
) * 2/*rates*/ * 3/*layouts*/)
231 return MF_E_NO_MORE_TYPES
;
233 if (FAILED(hr
= MFCreateMediaType(&output_type
)))
236 subtype
= formats
[index
/ 6].subtype
;
237 bps
= formats
[index
/ 6].depth
;
238 rate
= rates
[index
% 2];
239 channels
= channel_cnts
[(index
/ 2) % 3];
241 if (FAILED(hr
= IMFMediaType_SetGUID(output_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Audio
)))
243 if (FAILED(hr
= IMFMediaType_SetGUID(output_type
, &MF_MT_SUBTYPE
, subtype
)))
245 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, rate
)))
247 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_AUDIO_NUM_CHANNELS
, channels
)))
249 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, bps
)))
252 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, channels
* bps
/ 8)))
254 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, rate
* channels
* bps
/ 8)))
256 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_AUDIO_CHANNEL_MASK
,
257 channels
== 1 ? KSAUDIO_SPEAKER_MONO
:
258 channels
== 2 ? KSAUDIO_SPEAKER_STEREO
:
259 /*channels == 6*/ KSAUDIO_SPEAKER_5POINT1
)))
261 if (FAILED(hr
= IMFMediaType_SetUINT32(output_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, TRUE
)))
268 IMFMediaType_Release(output_type
);
272 static HRESULT WINAPI
audio_converter_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
274 GUID major_type
, subtype
;
278 struct audio_converter
*converter
= impl_audio_converter_from_IMFTransform(iface
);
280 TRACE("%p, %u, %p, %#x.\n", iface
, id
, type
, flags
);
283 return MF_E_INVALIDSTREAMNUMBER
;
287 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
290 EnterCriticalSection(&converter
->cs
);
292 if (converter
->input_type
)
294 IMFMediaType_Release(converter
->input_type
);
295 converter
->input_type
= NULL
;
298 LeaveCriticalSection(&converter
->cs
);
303 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major_type
)))
304 return MF_E_INVALIDTYPE
;
305 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
306 return MF_E_INVALIDTYPE
;
307 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &unused
)))
308 return MF_E_INVALIDTYPE
;
309 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_NUM_CHANNELS
, &unused
)))
310 return MF_E_INVALIDTYPE
;
311 if (IsEqualGUID(&subtype
, &MFAudioFormat_PCM
) && FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &unused
)))
312 return MF_E_INVALIDTYPE
;
314 if (!(IsEqualGUID(&major_type
, &MFMediaType_Audio
)))
315 return MF_E_INVALIDTYPE
;
317 if (!IsEqualGUID(&subtype
, &MFAudioFormat_PCM
) && !IsEqualGUID(&subtype
, &MFAudioFormat_Float
))
318 return MF_E_INVALIDTYPE
;
320 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
323 EnterCriticalSection(&converter
->cs
);
327 if (!converter
->input_type
)
328 hr
= MFCreateMediaType(&converter
->input_type
);
331 hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*) converter
->input_type
);
335 IMFMediaType_Release(converter
->input_type
);
336 converter
->input_type
= NULL
;
339 LeaveCriticalSection(&converter
->cs
);
344 static HRESULT WINAPI
audio_converter_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
346 struct audio_converter
*converter
= impl_audio_converter_from_IMFTransform(iface
);
347 GUID major_type
, subtype
;
351 TRACE("%p, %u, %p, %#x.\n", iface
, id
, type
, flags
);
354 return MF_E_INVALIDSTREAMNUMBER
;
356 if (!converter
->input_type
)
357 return MF_E_TRANSFORM_TYPE_NOT_SET
;
361 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
364 EnterCriticalSection(&converter
->cs
);
366 if (converter
->output_type
)
368 IMFMediaType_Release(converter
->output_type
);
369 converter
->output_type
= NULL
;
372 LeaveCriticalSection(&converter
->cs
);
377 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major_type
)))
378 return MF_E_INVALIDTYPE
;
379 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
380 return MF_E_INVALIDTYPE
;
381 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_NUM_CHANNELS
, &unused
)))
382 return MF_E_INVALIDTYPE
;
383 if (IsEqualGUID(&subtype
, &MFAudioFormat_PCM
) && FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &unused
)))
384 return MF_E_INVALIDTYPE
;
385 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &unused
)))
386 return MF_E_INVALIDTYPE
;
388 if (!(IsEqualGUID(&major_type
, &MFMediaType_Audio
)))
389 return MF_E_INVALIDTYPE
;
391 if (!IsEqualGUID(&subtype
, &MFAudioFormat_PCM
) && !IsEqualGUID(&subtype
, &MFAudioFormat_Float
))
392 return MF_E_INVALIDTYPE
;
394 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
397 EnterCriticalSection(&converter
->cs
);
401 if (!converter
->output_type
)
402 hr
= MFCreateMediaType(&converter
->output_type
);
405 hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*) converter
->output_type
);
409 IMFMediaType_Release(converter
->output_type
);
410 converter
->output_type
= NULL
;
413 LeaveCriticalSection(&converter
->cs
);
418 static HRESULT WINAPI
audio_converter_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
420 struct audio_converter
*converter
= impl_audio_converter_from_IMFTransform(iface
);
424 TRACE("%p, %u, %p.\n", converter
, id
, type
);
427 return MF_E_INVALIDSTREAMNUMBER
;
429 if (FAILED(hr
= MFCreateMediaType(&ret
)))
432 EnterCriticalSection(&converter
->cs
);
434 if (converter
->input_type
)
435 hr
= IMFMediaType_CopyAllItems(converter
->input_type
, (IMFAttributes
*)ret
);
437 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
439 LeaveCriticalSection(&converter
->cs
);
444 IMFMediaType_Release(ret
);
449 static HRESULT WINAPI
audio_converter_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
451 struct audio_converter
*converter
= impl_audio_converter_from_IMFTransform(iface
);
455 TRACE("%p, %u, %p.\n", converter
, id
, type
);
458 return MF_E_INVALIDSTREAMNUMBER
;
460 if (FAILED(hr
= MFCreateMediaType(&ret
)))
463 EnterCriticalSection(&converter
->cs
);
465 if (converter
->output_type
)
466 hr
= IMFMediaType_CopyAllItems(converter
->output_type
, (IMFAttributes
*)ret
);
468 hr
= MF_E_TRANSFORM_TYPE_NOT_SET
;
470 LeaveCriticalSection(&converter
->cs
);
475 IMFMediaType_Release(ret
);
480 static HRESULT WINAPI
audio_converter_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
482 FIXME("%p, %u, %p.\n", iface
, id
, flags
);
487 static HRESULT WINAPI
audio_converter_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
489 FIXME("%p, %p.\n", iface
, flags
);
494 static HRESULT WINAPI
audio_converter_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
496 FIXME("%p, %s, %s.\n", iface
, wine_dbgstr_longlong(lower
), wine_dbgstr_longlong(upper
));
501 static HRESULT WINAPI
audio_converter_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
503 TRACE("%p, %u, %p.\n", iface
, id
, event
);
508 static HRESULT WINAPI
audio_converter_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
510 TRACE("%p, %u %lu.\n", iface
, message
, param
);
514 case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
:
517 FIXME("Unhandled message type %x.\n", message
);
522 static HRESULT WINAPI
audio_converter_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
524 FIXME("%p, %u, %p, %#x.\n", iface
, id
, sample
, flags
);
529 static HRESULT WINAPI
audio_converter_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
530 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
532 FIXME("%p, %#x, %u, %p, %p.\n", iface
, flags
, count
, samples
, status
);
537 static const IMFTransformVtbl audio_converter_vtbl
=
539 audio_converter_QueryInterface
,
540 audio_converter_AddRef
,
541 audio_converter_Release
,
542 audio_converter_GetStreamLimits
,
543 audio_converter_GetStreamCount
,
544 audio_converter_GetStreamIDs
,
545 audio_converter_GetInputStreamInfo
,
546 audio_converter_GetOutputStreamInfo
,
547 audio_converter_GetAttributes
,
548 audio_converter_GetInputStreamAttributes
,
549 audio_converter_GetOutputStreamAttributes
,
550 audio_converter_DeleteInputStream
,
551 audio_converter_AddInputStreams
,
552 audio_converter_GetInputAvailableType
,
553 audio_converter_GetOutputAvailableType
,
554 audio_converter_SetInputType
,
555 audio_converter_SetOutputType
,
556 audio_converter_GetInputCurrentType
,
557 audio_converter_GetOutputCurrentType
,
558 audio_converter_GetInputStatus
,
559 audio_converter_GetOutputStatus
,
560 audio_converter_SetOutputBounds
,
561 audio_converter_ProcessEvent
,
562 audio_converter_ProcessMessage
,
563 audio_converter_ProcessInput
,
564 audio_converter_ProcessOutput
,
567 HRESULT
audio_converter_create(REFIID riid
, void **ret
)
569 struct audio_converter
*object
;
571 TRACE("%s %p\n", debugstr_guid(riid
), ret
);
573 if (!(object
= calloc(1, sizeof(*object
))))
574 return E_OUTOFMEMORY
;
576 object
->IMFTransform_iface
.lpVtbl
= &audio_converter_vtbl
;
577 object
->refcount
= 1;
579 InitializeCriticalSection(&object
->cs
);
580 object
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": audio_converter_lock");
582 *ret
= &object
->IMFTransform_iface
;