1 /* WMA Decoder DMO / MF 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"
24 #include "mfobjects.h"
25 #include "mftransform.h"
26 #include "wmcodecdsp.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wmadec
);
32 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
34 static const GUID
*const wma_decoder_input_types
[] =
36 &MEDIASUBTYPE_MSAUDIO1
,
37 &MFAudioFormat_WMAudioV8
,
38 &MFAudioFormat_WMAudioV9
,
39 &MFAudioFormat_WMAudio_Lossless
,
41 static const GUID
*const wma_decoder_output_types
[] =
49 IUnknown IUnknown_inner
;
50 IMFTransform IMFTransform_iface
;
51 IMediaObject IMediaObject_iface
;
52 IPropertyBag IPropertyBag_iface
;
56 struct wg_format input_format
;
57 struct wg_format output_format
;
60 DWORD output_buf_size
;
62 wg_transform_t wg_transform
;
63 struct wg_sample_queue
*wg_sample_queue
;
66 static inline struct wma_decoder
*impl_from_IUnknown(IUnknown
*iface
)
68 return CONTAINING_RECORD(iface
, struct wma_decoder
, IUnknown_inner
);
71 static HRESULT
try_create_wg_transform(struct wma_decoder
*decoder
)
73 struct wg_transform_attrs attrs
= {0};
75 if (decoder
->wg_transform
)
76 wg_transform_destroy(decoder
->wg_transform
);
77 decoder
->wg_transform
= 0;
79 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
80 return MF_E_INVALIDMEDIATYPE
;
82 if (decoder
->output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
83 return MF_E_INVALIDMEDIATYPE
;
85 if (!(decoder
->wg_transform
= wg_transform_create(&decoder
->input_format
, &decoder
->output_format
, &attrs
)))
91 static HRESULT WINAPI
unknown_QueryInterface(IUnknown
*iface
, REFIID iid
, void **out
)
93 struct wma_decoder
*decoder
= impl_from_IUnknown(iface
);
95 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
97 if (IsEqualGUID(iid
, &IID_IUnknown
))
98 *out
= &decoder
->IUnknown_inner
;
99 else if (IsEqualGUID(iid
, &IID_IMFTransform
))
100 *out
= &decoder
->IMFTransform_iface
;
101 else if (IsEqualGUID(iid
, &IID_IMediaObject
))
102 *out
= &decoder
->IMediaObject_iface
;
103 else if (IsEqualIID(iid
, &IID_IPropertyBag
))
104 *out
= &decoder
->IPropertyBag_iface
;
108 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
109 return E_NOINTERFACE
;
112 IUnknown_AddRef((IUnknown
*)*out
);
116 static ULONG WINAPI
unknown_AddRef(IUnknown
*iface
)
118 struct wma_decoder
*decoder
= impl_from_IUnknown(iface
);
119 ULONG refcount
= InterlockedIncrement(&decoder
->refcount
);
121 TRACE("iface %p increasing refcount to %lu.\n", decoder
, refcount
);
126 static ULONG WINAPI
unknown_Release(IUnknown
*iface
)
128 struct wma_decoder
*decoder
= impl_from_IUnknown(iface
);
129 ULONG refcount
= InterlockedDecrement(&decoder
->refcount
);
131 TRACE("iface %p decreasing refcount to %lu.\n", decoder
, refcount
);
135 if (decoder
->wg_transform
)
136 wg_transform_destroy(decoder
->wg_transform
);
138 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
145 static const IUnknownVtbl unknown_vtbl
=
147 unknown_QueryInterface
,
152 static struct wma_decoder
*impl_from_IMFTransform(IMFTransform
*iface
)
154 return CONTAINING_RECORD(iface
, struct wma_decoder
, IMFTransform_iface
);
157 static HRESULT WINAPI
transform_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
159 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
160 return IUnknown_QueryInterface(decoder
->outer
, iid
, out
);
163 static ULONG WINAPI
transform_AddRef(IMFTransform
*iface
)
165 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
166 return IUnknown_AddRef(decoder
->outer
);
169 static ULONG WINAPI
transform_Release(IMFTransform
*iface
)
171 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
172 return IUnknown_Release(decoder
->outer
);
175 static HRESULT WINAPI
transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
176 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
178 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
179 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
180 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
184 static HRESULT WINAPI
transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
186 TRACE("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
187 *inputs
= *outputs
= 1;
191 static HRESULT WINAPI
transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
192 DWORD output_size
, DWORD
*outputs
)
194 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface
,
195 input_size
, inputs
, output_size
, outputs
);
199 static HRESULT WINAPI
transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
201 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
203 TRACE("iface %p, id %lu, info %p.\n", iface
, id
, info
);
205 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
206 || decoder
->output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
208 memset(info
, 0, sizeof(*info
));
209 return MF_E_TRANSFORM_TYPE_NOT_SET
;
212 info
->hnsMaxLatency
= 0;
214 info
->cbSize
= decoder
->input_buf_size
;
215 info
->cbMaxLookahead
= 0;
216 info
->cbAlignment
= 1;
220 static HRESULT WINAPI
transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
222 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
224 TRACE("iface %p, id %lu, info %p.\n", iface
, id
, info
);
226 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
227 || decoder
->output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
229 memset(info
, 0, sizeof(*info
));
230 return MF_E_TRANSFORM_TYPE_NOT_SET
;
234 info
->cbSize
= decoder
->output_buf_size
;
235 info
->cbAlignment
= 1;
239 static HRESULT WINAPI
transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
241 TRACE("iface %p, attributes %p.\n", iface
, attributes
);
245 static HRESULT WINAPI
transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
247 TRACE("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
251 static HRESULT WINAPI
transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
253 TRACE("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
257 static HRESULT WINAPI
transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
259 TRACE("iface %p, id %#lx.\n", iface
, id
);
263 static HRESULT WINAPI
transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
265 TRACE("iface %p, streams %lu, ids %p.\n", iface
, streams
, ids
);
269 static HRESULT WINAPI
transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
272 FIXME("iface %p, id %lu, index %lu, type %p stub!\n", iface
, id
, index
, type
);
276 static HRESULT WINAPI
transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
279 UINT32 sample_size
, block_alignment
;
280 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
281 IMFMediaType
*media_type
;
282 const GUID
*output_type
;
285 TRACE("iface %p, id %lu, index %lu, type %p.\n", iface
, id
, index
, type
);
287 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
288 return MF_E_TRANSFORM_TYPE_NOT_SET
;
292 if (index
>= ARRAY_SIZE(wma_decoder_output_types
))
293 return MF_E_NO_MORE_TYPES
;
294 output_type
= wma_decoder_output_types
[index
];
296 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
299 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Audio
)))
301 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, output_type
)))
304 if (IsEqualGUID(output_type
, &MFAudioFormat_Float
))
306 else if (IsEqualGUID(output_type
, &MFAudioFormat_PCM
))
310 FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type
));
315 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
,
319 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_AUDIO_NUM_CHANNELS
,
320 decoder
->input_format
.u
.audio_wma
.channels
)))
323 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
,
324 decoder
->input_format
.u
.audio_wma
.rate
)))
327 block_alignment
= sample_size
* decoder
->input_format
.u
.audio_wma
.channels
/ 8;
328 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
,
331 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
,
332 decoder
->input_format
.u
.audio_wma
.rate
* block_alignment
)))
335 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, 1)))
337 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, 1)))
339 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_AUDIO_PREFER_WAVEFORMATEX
, 1)))
344 IMFMediaType_AddRef((*type
= media_type
));
346 IMFMediaType_Release(media_type
);
350 static HRESULT WINAPI
transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
352 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
353 MF_ATTRIBUTE_TYPE item_type
;
354 UINT32 block_alignment
;
359 TRACE("iface %p, id %lu, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
361 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
362 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
365 if (!IsEqualGUID(&major
, &MFMediaType_Audio
))
366 return MF_E_INVALIDMEDIATYPE
;
368 for (i
= 0; i
< ARRAY_SIZE(wma_decoder_input_types
); ++i
)
369 if (IsEqualGUID(&subtype
, wma_decoder_input_types
[i
]))
371 if (i
== ARRAY_SIZE(wma_decoder_input_types
))
372 return MF_E_INVALIDMEDIATYPE
;
374 if (FAILED(IMFMediaType_GetItemType(type
, &MF_MT_USER_DATA
, &item_type
)) ||
375 item_type
!= MF_ATTRIBUTE_BLOB
)
376 return MF_E_INVALIDMEDIATYPE
;
377 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
378 return MF_E_INVALIDMEDIATYPE
;
379 if (FAILED(IMFMediaType_GetItemType(type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &item_type
)) ||
380 item_type
!= MF_ATTRIBUTE_UINT32
)
381 return MF_E_INVALIDMEDIATYPE
;
382 if (FAILED(IMFMediaType_GetItemType(type
, &MF_MT_AUDIO_NUM_CHANNELS
, &item_type
)) ||
383 item_type
!= MF_ATTRIBUTE_UINT32
)
384 return MF_E_INVALIDMEDIATYPE
;
385 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
388 mf_media_type_to_wg_format(type
, &decoder
->input_format
);
389 decoder
->input_buf_size
= block_alignment
;
390 decoder
->output_format
.major_type
= WG_MAJOR_TYPE_UNKNOWN
;
395 static HRESULT WINAPI
transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
397 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
398 UINT32 channel_count
, block_alignment
;
399 MF_ATTRIBUTE_TYPE item_type
;
400 ULONG i
, sample_size
;
404 TRACE("iface %p, id %lu, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
406 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
407 return MF_E_TRANSFORM_TYPE_NOT_SET
;
409 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
410 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
413 if (!IsEqualGUID(&major
, &MFMediaType_Audio
))
414 return MF_E_INVALIDMEDIATYPE
;
416 for (i
= 0; i
< ARRAY_SIZE(wma_decoder_output_types
); ++i
)
417 if (IsEqualGUID(&subtype
, wma_decoder_output_types
[i
]))
419 if (i
== ARRAY_SIZE(wma_decoder_output_types
))
420 return MF_E_INVALIDMEDIATYPE
;
422 if (IsEqualGUID(&subtype
, &MFAudioFormat_Float
))
424 else if (IsEqualGUID(&subtype
, &MFAudioFormat_PCM
))
428 FIXME("Subtype %s not implemented!\n", debugstr_guid(&subtype
));
433 if (FAILED(IMFMediaType_GetItemType(type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &item_type
)) ||
434 item_type
!= MF_ATTRIBUTE_UINT32
)
435 return MF_E_INVALIDMEDIATYPE
;
436 if (FAILED(IMFMediaType_GetItemType(type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &item_type
)) ||
437 item_type
!= MF_ATTRIBUTE_UINT32
)
438 return MF_E_INVALIDMEDIATYPE
;
439 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_NUM_CHANNELS
, &channel_count
)))
440 return MF_E_INVALIDMEDIATYPE
;
441 if (FAILED(IMFMediaType_GetItemType(type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &item_type
)) ||
442 item_type
!= MF_ATTRIBUTE_UINT32
)
443 return MF_E_INVALIDMEDIATYPE
;
444 if (FAILED(IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
445 return MF_E_INVALIDMEDIATYPE
;
446 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
449 decoder
->input_format
.u
.audio_wma
.depth
= sample_size
;
451 mf_media_type_to_wg_format(type
, &decoder
->output_format
);
452 decoder
->output_buf_size
= 1024 * block_alignment
* channel_count
;
454 if (FAILED(hr
= try_create_wg_transform(decoder
)))
460 decoder
->output_format
.major_type
= WG_MAJOR_TYPE_UNKNOWN
;
464 static HRESULT WINAPI
transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
466 FIXME("iface %p, id %lu, type %p stub!\n", iface
, id
, type
);
470 static HRESULT WINAPI
transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
472 FIXME("iface %p, id %lu, type %p stub!\n", iface
, id
, type
);
476 static HRESULT WINAPI
transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
478 FIXME("iface %p, id %lu, flags %p stub!\n", iface
, id
, flags
);
482 static HRESULT WINAPI
transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
484 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
488 static HRESULT WINAPI
transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
490 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface
, lower
, upper
);
494 static HRESULT WINAPI
transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
496 FIXME("iface %p, id %lu, event %p stub!\n", iface
, id
, event
);
500 static HRESULT WINAPI
transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
502 FIXME("iface %p, message %#x, param %p stub!\n", iface
, message
, (void *)param
);
506 static HRESULT WINAPI
transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
508 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
509 MFT_INPUT_STREAM_INFO info
;
513 TRACE("iface %p, id %lu, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
515 if (!decoder
->wg_transform
)
516 return MF_E_TRANSFORM_TYPE_NOT_SET
;
518 if (FAILED(hr
= IMFTransform_GetInputStreamInfo(iface
, 0, &info
))
519 || FAILED(hr
= IMFSample_GetTotalLength(sample
, &total_length
)))
522 /* WMA transform uses fixed size input samples and ignores samples with invalid sizes */
523 if (total_length
% info
.cbSize
)
526 return wg_transform_push_mf(decoder
->wg_transform
, sample
, decoder
->wg_sample_queue
);
529 static HRESULT WINAPI
transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
530 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
532 struct wma_decoder
*decoder
= impl_from_IMFTransform(iface
);
533 MFT_OUTPUT_STREAM_INFO info
;
536 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
541 if (!decoder
->wg_transform
)
542 return MF_E_TRANSFORM_TYPE_NOT_SET
;
544 *status
= samples
->dwStatus
= 0;
545 if (!samples
->pSample
)
547 samples
[0].dwStatus
= MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
;
548 return MF_E_TRANSFORM_NEED_MORE_INPUT
;
551 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(iface
, 0, &info
)))
554 if (SUCCEEDED(hr
= wg_transform_read_mf(decoder
->wg_transform
, samples
->pSample
,
555 info
.cbSize
, NULL
, &samples
->dwStatus
)))
556 wg_sample_queue_flush(decoder
->wg_sample_queue
, false);
561 static const IMFTransformVtbl transform_vtbl
=
563 transform_QueryInterface
,
566 transform_GetStreamLimits
,
567 transform_GetStreamCount
,
568 transform_GetStreamIDs
,
569 transform_GetInputStreamInfo
,
570 transform_GetOutputStreamInfo
,
571 transform_GetAttributes
,
572 transform_GetInputStreamAttributes
,
573 transform_GetOutputStreamAttributes
,
574 transform_DeleteInputStream
,
575 transform_AddInputStreams
,
576 transform_GetInputAvailableType
,
577 transform_GetOutputAvailableType
,
578 transform_SetInputType
,
579 transform_SetOutputType
,
580 transform_GetInputCurrentType
,
581 transform_GetOutputCurrentType
,
582 transform_GetInputStatus
,
583 transform_GetOutputStatus
,
584 transform_SetOutputBounds
,
585 transform_ProcessEvent
,
586 transform_ProcessMessage
,
587 transform_ProcessInput
,
588 transform_ProcessOutput
,
591 static inline struct wma_decoder
*impl_from_IMediaObject(IMediaObject
*iface
)
593 return CONTAINING_RECORD(iface
, struct wma_decoder
, IMediaObject_iface
);
596 static HRESULT WINAPI
media_object_QueryInterface(IMediaObject
*iface
, REFIID iid
, void **obj
)
598 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
599 return IUnknown_QueryInterface(decoder
->outer
, iid
, obj
);
602 static ULONG WINAPI
media_object_AddRef(IMediaObject
*iface
)
604 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
605 return IUnknown_AddRef(decoder
->outer
);
608 static ULONG WINAPI
media_object_Release(IMediaObject
*iface
)
610 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
611 return IUnknown_Release(decoder
->outer
);
614 static HRESULT WINAPI
media_object_GetStreamCount(IMediaObject
*iface
, DWORD
*input
, DWORD
*output
)
616 FIXME("iface %p, input %p, output %p semi-stub!\n", iface
, input
, output
);
617 *input
= *output
= 1;
621 static HRESULT WINAPI
media_object_GetInputStreamInfo(IMediaObject
*iface
, DWORD index
, DWORD
*flags
)
623 FIXME("iface %p, index %lu, flags %p stub!\n", iface
, index
, flags
);
627 static HRESULT WINAPI
media_object_GetOutputStreamInfo(IMediaObject
*iface
, DWORD index
, DWORD
*flags
)
629 FIXME("iface %p, index %lu, flags %p stub!\n", iface
, index
, flags
);
633 static HRESULT WINAPI
media_object_GetInputType(IMediaObject
*iface
, DWORD index
, DWORD type_index
,
634 DMO_MEDIA_TYPE
*type
)
636 TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface
, index
, type_index
, type
);
639 return DMO_E_INVALIDSTREAMINDEX
;
640 if (type_index
>= ARRAY_SIZE(wma_decoder_input_types
))
641 return DMO_E_NO_MORE_ITEMS
;
645 memset(type
, 0, sizeof(*type
));
646 type
->majortype
= MFMediaType_Audio
;
647 type
->subtype
= *wma_decoder_input_types
[type_index
];
648 type
->bFixedSizeSamples
= FALSE
;
649 type
->bTemporalCompression
= TRUE
;
650 type
->lSampleSize
= 0;
655 static HRESULT WINAPI
media_object_GetOutputType(IMediaObject
*iface
, DWORD index
, DWORD type_index
,
656 DMO_MEDIA_TYPE
*type
)
658 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
661 TRACE("iface %p, index %lu, type_index %lu, type %p\n", iface
, index
, type_index
, type
);
664 return DMO_E_INVALIDSTREAMINDEX
;
666 return DMO_E_NO_MORE_ITEMS
;
667 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
668 return DMO_E_TYPE_NOT_SET
;
672 memset(type
, 0, sizeof(*type
));
673 type
->majortype
= MFMediaType_Audio
;
674 type
->subtype
= MEDIASUBTYPE_PCM
;
675 type
->formattype
= FORMAT_WaveFormatEx
;
676 type
->bFixedSizeSamples
= FALSE
;
677 type
->bTemporalCompression
= TRUE
;
678 type
->lSampleSize
= 0;
680 type
->cbFormat
= sizeof(WAVEFORMATEX
);
681 type
->pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
682 memset(type
->pbFormat
, 0, type
->cbFormat
);
684 wfx
= (WAVEFORMATEX
*)type
->pbFormat
;
685 if (decoder
->input_format
.u
.audio_wma
.depth
== 32)
686 wfx
->wFormatTag
= WAVE_FORMAT_IEEE_FLOAT
;
688 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
689 wfx
->nChannels
= decoder
->input_format
.u
.audio_wma
.channels
;
690 wfx
->nSamplesPerSec
= decoder
->input_format
.u
.audio_wma
.rate
;
691 wfx
->wBitsPerSample
= decoder
->input_format
.u
.audio_wma
.depth
;
692 wfx
->nAvgBytesPerSec
= wfx
->nChannels
* wfx
->nSamplesPerSec
* wfx
->wBitsPerSample
/ 8;
693 wfx
->nBlockAlign
= wfx
->nChannels
* wfx
->wBitsPerSample
/ 8;
698 static HRESULT WINAPI
media_object_SetInputType(IMediaObject
*iface
, DWORD index
,
699 const DMO_MEDIA_TYPE
*type
, DWORD flags
)
701 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
702 struct wg_format wg_format
;
705 TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface
, index
, type
, flags
);
708 return DMO_E_INVALIDSTREAMINDEX
;
710 if (flags
& DMO_SET_TYPEF_CLEAR
)
712 if (flags
!= DMO_SET_TYPEF_CLEAR
)
714 memset(&decoder
->input_format
, 0, sizeof(decoder
->input_format
));
715 if (decoder
->wg_transform
)
717 wg_transform_destroy(decoder
->wg_transform
);
718 decoder
->wg_transform
= 0;
724 if (flags
& ~DMO_SET_TYPEF_TEST_ONLY
)
727 if (!IsEqualGUID(&type
->majortype
, &MEDIATYPE_Audio
))
728 return DMO_E_TYPE_NOT_ACCEPTED
;
730 for (i
= 0; i
< ARRAY_SIZE(wma_decoder_input_types
); ++i
)
731 if (IsEqualGUID(&type
->subtype
, wma_decoder_input_types
[i
]))
733 if (i
== ARRAY_SIZE(wma_decoder_input_types
))
734 return DMO_E_TYPE_NOT_ACCEPTED
;
736 if (!amt_to_wg_format((const AM_MEDIA_TYPE
*)type
, &wg_format
))
737 return DMO_E_TYPE_NOT_ACCEPTED
;
738 assert(wg_format
.major_type
== WG_MAJOR_TYPE_AUDIO_WMA
);
740 if (flags
& DMO_SET_TYPEF_TEST_ONLY
)
743 decoder
->input_format
= wg_format
;
744 if (decoder
->wg_transform
)
746 wg_transform_destroy(decoder
->wg_transform
);
747 decoder
->wg_transform
= 0;
753 static HRESULT WINAPI
media_object_SetOutputType(IMediaObject
*iface
, DWORD index
,
754 const DMO_MEDIA_TYPE
*type
, DWORD flags
)
756 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
757 struct wg_transform_attrs attrs
= {0};
758 struct wg_format wg_format
;
761 TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface
, index
, type
, flags
);
764 return DMO_E_INVALIDSTREAMINDEX
;
766 if (flags
& DMO_SET_TYPEF_CLEAR
)
768 if (flags
!= DMO_SET_TYPEF_CLEAR
)
770 memset(&decoder
->output_format
, 0, sizeof(decoder
->output_format
));
771 if (decoder
->wg_transform
)
773 wg_transform_destroy(decoder
->wg_transform
);
774 decoder
->wg_transform
= 0;
780 if (flags
& ~DMO_SET_TYPEF_TEST_ONLY
)
783 if (!IsEqualGUID(&type
->majortype
, &MEDIATYPE_Audio
))
784 return DMO_E_TYPE_NOT_ACCEPTED
;
786 for (i
= 0; i
< ARRAY_SIZE(wma_decoder_output_types
); ++i
)
787 if (IsEqualGUID(&type
->subtype
, wma_decoder_output_types
[i
]))
789 if (i
== ARRAY_SIZE(wma_decoder_output_types
))
790 return DMO_E_TYPE_NOT_ACCEPTED
;
793 if (!amt_to_wg_format((const AM_MEDIA_TYPE
*)type
, &wg_format
))
794 return DMO_E_TYPE_NOT_ACCEPTED
;
795 assert(wg_format
.major_type
== WG_MAJOR_TYPE_AUDIO
);
797 if (decoder
->input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
798 return DMO_E_TYPE_NOT_SET
;
800 if (flags
& DMO_SET_TYPEF_TEST_ONLY
)
803 decoder
->output_format
= wg_format
;
805 /* Set up wg_transform. */
806 if (decoder
->wg_transform
)
808 wg_transform_destroy(decoder
->wg_transform
);
809 decoder
->wg_transform
= 0;
811 if (!(decoder
->wg_transform
= wg_transform_create(&decoder
->input_format
, &decoder
->output_format
, &attrs
)))
817 static HRESULT WINAPI
media_object_GetInputCurrentType(IMediaObject
*iface
, DWORD index
, DMO_MEDIA_TYPE
*type
)
819 FIXME("iface %p, index %lu, type %p stub!\n", iface
, index
, type
);
823 static HRESULT WINAPI
media_object_GetOutputCurrentType(IMediaObject
*iface
, DWORD index
, DMO_MEDIA_TYPE
*type
)
825 FIXME("iface %p, index %lu, type %p stub!\n", iface
, index
, type
);
829 static HRESULT WINAPI
media_object_GetInputSizeInfo(IMediaObject
*iface
, DWORD index
, DWORD
*size
,
830 DWORD
*lookahead
, DWORD
*alignment
)
832 FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface
, index
, size
,
833 lookahead
, alignment
);
837 static HRESULT WINAPI
media_object_GetOutputSizeInfo(IMediaObject
*iface
, DWORD index
, DWORD
*size
, DWORD
*alignment
)
839 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
841 TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface
, index
, size
, alignment
);
843 if (!size
|| !alignment
)
846 return DMO_E_INVALIDSTREAMINDEX
;
847 if (decoder
->output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
848 return DMO_E_TYPE_NOT_SET
;
856 static HRESULT WINAPI
media_object_GetInputMaxLatency(IMediaObject
*iface
, DWORD index
, REFERENCE_TIME
*latency
)
858 FIXME("iface %p, index %lu, latency %p stub!\n", iface
, index
, latency
);
862 static HRESULT WINAPI
media_object_SetInputMaxLatency(IMediaObject
*iface
, DWORD index
, REFERENCE_TIME latency
)
864 FIXME("iface %p, index %lu, latency %s stub!\n", iface
, index
, wine_dbgstr_longlong(latency
));
868 static HRESULT WINAPI
media_object_Flush(IMediaObject
*iface
)
870 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
873 TRACE("iface %p.\n", iface
);
875 if (FAILED(hr
= wg_transform_flush(decoder
->wg_transform
)))
878 wg_sample_queue_flush(decoder
->wg_sample_queue
, TRUE
);
883 static HRESULT WINAPI
media_object_Discontinuity(IMediaObject
*iface
, DWORD index
)
885 TRACE("iface %p, index %lu.\n", iface
, index
);
888 return DMO_E_INVALIDSTREAMINDEX
;
893 static HRESULT WINAPI
media_object_AllocateStreamingResources(IMediaObject
*iface
)
895 FIXME("iface %p stub!\n", iface
);
899 static HRESULT WINAPI
media_object_FreeStreamingResources(IMediaObject
*iface
)
901 FIXME("iface %p stub!\n", iface
);
905 static HRESULT WINAPI
media_object_GetInputStatus(IMediaObject
*iface
, DWORD index
, DWORD
*flags
)
907 FIXME("iface %p, index %lu, flags %p stub!\n", iface
, index
, flags
);
911 static HRESULT WINAPI
media_object_ProcessInput(IMediaObject
*iface
, DWORD index
,
912 IMediaBuffer
*buffer
, DWORD flags
, REFERENCE_TIME timestamp
, REFERENCE_TIME timelength
)
914 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
916 TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface
,
917 index
, buffer
, flags
, wine_dbgstr_longlong(timestamp
), wine_dbgstr_longlong(timelength
));
919 if (!decoder
->wg_transform
)
920 return DMO_E_TYPE_NOT_SET
;
922 return wg_transform_push_dmo(decoder
->wg_transform
, buffer
, flags
, timestamp
, timelength
, decoder
->wg_sample_queue
);
925 static HRESULT WINAPI
media_object_ProcessOutput(IMediaObject
*iface
, DWORD flags
, DWORD count
,
926 DMO_OUTPUT_DATA_BUFFER
*buffers
, DWORD
*status
)
928 struct wma_decoder
*decoder
= impl_from_IMediaObject(iface
);
931 TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface
, flags
, count
, buffers
, status
);
933 if (!decoder
->wg_transform
)
934 return DMO_E_TYPE_NOT_SET
;
936 hr
= wg_transform_read_dmo(decoder
->wg_transform
, buffers
);
940 /* WMA Lossless emits anything from 0 to 12 packets of output for each packet of input */
941 buffers
[0].dwStatus
|= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE
;
942 wg_sample_queue_flush(decoder
->wg_sample_queue
, false);
948 static HRESULT WINAPI
media_object_Lock(IMediaObject
*iface
, LONG lock
)
950 FIXME("iface %p, lock %ld stub!\n", iface
, lock
);
954 static const IMediaObjectVtbl media_object_vtbl
=
956 media_object_QueryInterface
,
958 media_object_Release
,
959 media_object_GetStreamCount
,
960 media_object_GetInputStreamInfo
,
961 media_object_GetOutputStreamInfo
,
962 media_object_GetInputType
,
963 media_object_GetOutputType
,
964 media_object_SetInputType
,
965 media_object_SetOutputType
,
966 media_object_GetInputCurrentType
,
967 media_object_GetOutputCurrentType
,
968 media_object_GetInputSizeInfo
,
969 media_object_GetOutputSizeInfo
,
970 media_object_GetInputMaxLatency
,
971 media_object_SetInputMaxLatency
,
973 media_object_Discontinuity
,
974 media_object_AllocateStreamingResources
,
975 media_object_FreeStreamingResources
,
976 media_object_GetInputStatus
,
977 media_object_ProcessInput
,
978 media_object_ProcessOutput
,
982 static inline struct wma_decoder
*impl_from_IPropertyBag(IPropertyBag
*iface
)
984 return CONTAINING_RECORD(iface
, struct wma_decoder
, IPropertyBag_iface
);
987 static HRESULT WINAPI
property_bag_QueryInterface(IPropertyBag
*iface
, REFIID iid
, void **out
)
989 struct wma_decoder
*filter
= impl_from_IPropertyBag(iface
);
990 return IUnknown_QueryInterface(filter
->outer
, iid
, out
);
993 static ULONG WINAPI
property_bag_AddRef(IPropertyBag
*iface
)
995 struct wma_decoder
*filter
= impl_from_IPropertyBag(iface
);
996 return IUnknown_AddRef(filter
->outer
);
999 static ULONG WINAPI
property_bag_Release(IPropertyBag
*iface
)
1001 struct wma_decoder
*filter
= impl_from_IPropertyBag(iface
);
1002 return IUnknown_Release(filter
->outer
);
1005 static HRESULT WINAPI
property_bag_Read(IPropertyBag
*iface
, const WCHAR
*prop_name
, VARIANT
*value
,
1006 IErrorLog
*error_log
)
1008 FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface
, debugstr_w(prop_name
), value
, error_log
);
1012 static HRESULT WINAPI
property_bag_Write(IPropertyBag
*iface
, const WCHAR
*prop_name
, VARIANT
*value
)
1014 FIXME("iface %p, prop_name %s, value %p stub!\n", iface
, debugstr_w(prop_name
), value
);
1018 static const IPropertyBagVtbl property_bag_vtbl
=
1020 property_bag_QueryInterface
,
1021 property_bag_AddRef
,
1022 property_bag_Release
,
1027 HRESULT
wma_decoder_create(IUnknown
*outer
, IUnknown
**out
)
1029 static const struct wg_format output_format
=
1031 .major_type
= WG_MAJOR_TYPE_AUDIO
,
1034 .format
= WG_AUDIO_FORMAT_F32LE
,
1040 static const struct wg_format input_format
= {.major_type
= WG_MAJOR_TYPE_AUDIO_WMA
};
1041 struct wg_transform_attrs attrs
= {0};
1042 wg_transform_t transform
;
1043 struct wma_decoder
*decoder
;
1046 TRACE("outer %p, out %p.\n", outer
, out
);
1048 if (!(transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
1050 ERR_(winediag
)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n");
1053 wg_transform_destroy(transform
);
1055 if (!(decoder
= calloc(1, sizeof(*decoder
))))
1056 return E_OUTOFMEMORY
;
1058 if (FAILED(hr
= wg_sample_queue_create(&decoder
->wg_sample_queue
)))
1064 decoder
->IUnknown_inner
.lpVtbl
= &unknown_vtbl
;
1065 decoder
->IMFTransform_iface
.lpVtbl
= &transform_vtbl
;
1066 decoder
->IMediaObject_iface
.lpVtbl
= &media_object_vtbl
;
1067 decoder
->IPropertyBag_iface
.lpVtbl
= &property_bag_vtbl
;
1068 decoder
->refcount
= 1;
1069 decoder
->outer
= outer
? outer
: &decoder
->IUnknown_inner
;
1071 *out
= &decoder
->IUnknown_inner
;
1072 TRACE("Created decoder %p\n", *out
);