cmd: DIR command outputs free space for the path.
[wine.git] / dlls / winegstreamer / quartz_transform.c
blob1dce20d9cfff3f6c19ee47c549fc53a2b4f77a2e
1 /*
2 * DirectShow transform filters
4 * Copyright 2022 Anton Baskanov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "gst_private.h"
22 #include "gst_guids.h"
24 #include "mferror.h"
25 #include "mpegtype.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
28 WINE_DECLARE_DEBUG_CHANNEL(winediag);
30 struct transform
32 struct strmbase_filter filter;
33 IMpegAudioDecoder IMpegAudioDecoder_iface;
35 struct strmbase_sink sink;
36 struct strmbase_source source;
37 struct strmbase_passthrough passthrough;
39 IQualityControl sink_IQualityControl_iface;
40 IQualityControl source_IQualityControl_iface;
41 IQualityControl *qc_sink;
43 wg_transform_t transform;
44 struct wg_sample_queue *sample_queue;
46 const struct transform_ops *ops;
49 struct transform_ops
51 HRESULT (*sink_query_accept)(struct transform *filter, const AM_MEDIA_TYPE *mt);
52 HRESULT (*source_query_accept)(struct transform *filter, const AM_MEDIA_TYPE *mt);
53 HRESULT (*source_get_media_type)(struct transform *filter, unsigned int index, AM_MEDIA_TYPE *mt);
54 HRESULT (*source_decide_buffer_size)(struct transform *filter, IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props);
57 static inline struct transform *impl_from_strmbase_filter(struct strmbase_filter *iface)
59 return CONTAINING_RECORD(iface, struct transform, filter);
62 static struct strmbase_pin *transform_get_pin(struct strmbase_filter *iface, unsigned int index)
64 struct transform *filter = impl_from_strmbase_filter(iface);
65 if (index == 0)
66 return &filter->sink.pin;
67 if (index == 1)
68 return &filter->source.pin;
69 return NULL;
72 static void transform_destroy(struct strmbase_filter *iface)
74 struct transform *filter = impl_from_strmbase_filter(iface);
76 strmbase_passthrough_cleanup(&filter->passthrough);
77 strmbase_source_cleanup(&filter->source);
78 strmbase_sink_cleanup(&filter->sink);
79 strmbase_filter_cleanup(&filter->filter);
81 free(filter);
84 static HRESULT transform_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
86 struct transform *filter = impl_from_strmbase_filter(iface);
88 if (IsEqualGUID(iid, &IID_IMpegAudioDecoder) && filter->IMpegAudioDecoder_iface.lpVtbl)
89 *out = &filter->IMpegAudioDecoder_iface;
90 else
91 return E_NOINTERFACE;
93 IUnknown_AddRef((IUnknown *)*out);
94 return S_OK;
97 static HRESULT transform_init_stream(struct strmbase_filter *iface)
99 struct transform *filter = impl_from_strmbase_filter(iface);
100 struct wg_format input_format, output_format;
101 struct wg_transform_attrs attrs = {0};
102 HRESULT hr;
104 if (filter->source.pin.peer)
106 if (!amt_to_wg_format(&filter->sink.pin.mt, &input_format))
107 return E_FAIL;
109 if (!amt_to_wg_format(&filter->source.pin.mt, &output_format))
110 return E_FAIL;
112 if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue)))
113 return hr;
115 filter->transform = wg_transform_create(&input_format, &output_format, &attrs);
116 if (!filter->transform)
118 wg_sample_queue_destroy(filter->sample_queue);
119 return E_FAIL;
122 hr = IMemAllocator_Commit(filter->source.pAllocator);
123 if (FAILED(hr))
124 ERR("Failed to commit allocator, hr %#lx.\n", hr);
127 return S_OK;
130 static HRESULT transform_cleanup_stream(struct strmbase_filter *iface)
132 struct transform *filter = impl_from_strmbase_filter(iface);
134 if (filter->source.pin.peer)
136 IMemAllocator_Decommit(filter->source.pAllocator);
138 EnterCriticalSection(&filter->filter.stream_cs);
139 wg_transform_destroy(filter->transform);
140 wg_sample_queue_destroy(filter->sample_queue);
141 LeaveCriticalSection(&filter->filter.stream_cs);
144 return S_OK;
147 static const struct strmbase_filter_ops filter_ops =
149 .filter_get_pin = transform_get_pin,
150 .filter_destroy = transform_destroy,
151 .filter_query_interface = transform_query_interface,
152 .filter_init_stream = transform_init_stream,
153 .filter_cleanup_stream = transform_cleanup_stream,
156 static struct transform *impl_from_IMpegAudioDecoder(IMpegAudioDecoder *iface)
158 return CONTAINING_RECORD(iface, struct transform, IMpegAudioDecoder_iface);
161 static HRESULT WINAPI mpeg_audio_decoder_QueryInterface(IMpegAudioDecoder *iface,
162 REFIID iid, void **out)
164 struct transform *filter = impl_from_IMpegAudioDecoder(iface);
165 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
168 static ULONG WINAPI mpeg_audio_decoder_AddRef(IMpegAudioDecoder *iface)
170 struct transform *filter = impl_from_IMpegAudioDecoder(iface);
171 return IUnknown_AddRef(filter->filter.outer_unk);
174 static ULONG WINAPI mpeg_audio_decoder_Release(IMpegAudioDecoder *iface)
176 struct transform *filter = impl_from_IMpegAudioDecoder(iface);
177 return IUnknown_Release(filter->filter.outer_unk);
180 static HRESULT WINAPI mpeg_audio_decoder_get_FrequencyDivider(IMpegAudioDecoder *iface, ULONG *divider)
182 FIXME("iface %p, divider %p, stub!\n", iface, divider);
183 return E_NOTIMPL;
186 static HRESULT WINAPI mpeg_audio_decoder_put_FrequencyDivider(IMpegAudioDecoder *iface, ULONG divider)
188 FIXME("iface %p, divider %lu, stub!\n", iface, divider);
189 return E_NOTIMPL;
192 static HRESULT WINAPI mpeg_audio_decoder_get_DecoderAccuracy(IMpegAudioDecoder *iface, ULONG *accuracy)
194 FIXME("iface %p, accuracy %p, stub!\n", iface, accuracy);
195 return E_NOTIMPL;
198 static HRESULT WINAPI mpeg_audio_decoder_put_DecoderAccuracy(IMpegAudioDecoder *iface, ULONG accuracy)
200 FIXME("iface %p, accuracy %lu, stub!\n", iface, accuracy);
201 return E_NOTIMPL;
204 static HRESULT WINAPI mpeg_audio_decoder_get_Stereo(IMpegAudioDecoder *iface, ULONG *stereo)
206 FIXME("iface %p, stereo %p, stub!\n", iface, stereo);
207 return E_NOTIMPL;
210 static HRESULT WINAPI mpeg_audio_decoder_put_Stereo(IMpegAudioDecoder *iface, ULONG stereo)
212 FIXME("iface %p, stereo %lu, stub!\n", iface, stereo);
213 return E_NOTIMPL;
216 static HRESULT WINAPI mpeg_audio_decoder_get_DecoderWordSize(IMpegAudioDecoder *iface, ULONG *word_size)
218 FIXME("iface %p, word_size %p, stub!\n", iface, word_size);
219 return E_NOTIMPL;
222 static HRESULT WINAPI mpeg_audio_decoder_put_DecoderWordSize(IMpegAudioDecoder *iface, ULONG word_size)
224 FIXME("iface %p, word_size %lu, stub!\n", iface, word_size);
225 return E_NOTIMPL;
228 static HRESULT WINAPI mpeg_audio_decoder_get_IntegerDecode(IMpegAudioDecoder *iface, ULONG *integer_decode)
230 FIXME("iface %p, integer_decode %p, stub!\n", iface, integer_decode);
231 return E_NOTIMPL;
234 static HRESULT WINAPI mpeg_audio_decoder_put_IntegerDecode(IMpegAudioDecoder *iface, ULONG integer_decode)
236 FIXME("iface %p, integer_decode %lu, stub!\n", iface, integer_decode);
237 return E_NOTIMPL;
240 static HRESULT WINAPI mpeg_audio_decoder_get_DualMode(IMpegAudioDecoder *iface, ULONG *dual_mode)
242 FIXME("iface %p, dual_mode %p, stub!\n", iface, dual_mode);
243 return E_NOTIMPL;
246 static HRESULT WINAPI mpeg_audio_decoder_put_DualMode(IMpegAudioDecoder *iface, ULONG dual_mode)
248 FIXME("iface %p, dual_mode %lu, stub!\n", iface, dual_mode);
249 return E_NOTIMPL;
252 static HRESULT WINAPI mpeg_audio_decoder_get_AudioFormat(IMpegAudioDecoder *iface, MPEG1WAVEFORMAT *format)
254 FIXME("iface %p, format %p, stub!\n", iface, format);
255 return E_NOTIMPL;
258 static const IMpegAudioDecoderVtbl mpeg_audio_decoder_vtbl =
260 mpeg_audio_decoder_QueryInterface,
261 mpeg_audio_decoder_AddRef,
262 mpeg_audio_decoder_Release,
263 mpeg_audio_decoder_get_FrequencyDivider,
264 mpeg_audio_decoder_put_FrequencyDivider,
265 mpeg_audio_decoder_get_DecoderAccuracy,
266 mpeg_audio_decoder_put_DecoderAccuracy,
267 mpeg_audio_decoder_get_Stereo,
268 mpeg_audio_decoder_put_Stereo,
269 mpeg_audio_decoder_get_DecoderWordSize,
270 mpeg_audio_decoder_put_DecoderWordSize,
271 mpeg_audio_decoder_get_IntegerDecode,
272 mpeg_audio_decoder_put_IntegerDecode,
273 mpeg_audio_decoder_get_DualMode,
274 mpeg_audio_decoder_put_DualMode,
275 mpeg_audio_decoder_get_AudioFormat,
278 static HRESULT transform_sink_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
280 struct transform *filter = impl_from_strmbase_filter(pin->filter);
282 return filter->ops->sink_query_accept(filter, mt);
285 static HRESULT transform_sink_query_interface(struct strmbase_pin *pin, REFIID iid, void **out)
287 struct transform *filter = impl_from_strmbase_filter(pin->filter);
289 if (IsEqualGUID(iid, &IID_IMemInputPin))
290 *out = &filter->sink.IMemInputPin_iface;
291 else if (IsEqualGUID(iid, &IID_IQualityControl))
292 *out = &filter->sink_IQualityControl_iface;
293 else
294 return E_NOINTERFACE;
296 IUnknown_AddRef((IUnknown *)*out);
297 return S_OK;
300 static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSample *sample)
302 struct transform *filter = impl_from_strmbase_filter(pin->pin.filter);
303 struct wg_sample *wg_sample;
304 HRESULT hr;
306 /* We do not expect pin connection state to change while the filter is
307 * running. This guarantee is necessary, since otherwise we would have to
308 * take the filter lock, and we can't take the filter lock from a streaming
309 * thread. */
310 if (!filter->source.pMemInputPin)
312 WARN("Source is not connected, returning VFW_E_NOT_CONNECTED.\n");
313 return VFW_E_NOT_CONNECTED;
316 if (filter->filter.state == State_Stopped)
317 return VFW_E_WRONG_STATE;
319 if (filter->sink.flushing)
320 return S_FALSE;
322 hr = wg_sample_create_quartz(sample, &wg_sample);
323 if (FAILED(hr))
324 return hr;
326 hr = wg_transform_push_quartz(filter->transform, wg_sample, filter->sample_queue);
327 if (FAILED(hr))
328 return hr;
330 for (;;)
332 IMediaSample *output_sample;
334 hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &output_sample, NULL, NULL, 0);
335 if (FAILED(hr))
336 return hr;
338 hr = wg_sample_create_quartz(output_sample, &wg_sample);
339 if (FAILED(hr))
341 IMediaSample_Release(output_sample);
342 return hr;
345 hr = wg_transform_read_quartz(filter->transform, wg_sample);
346 wg_sample_release(wg_sample);
348 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
350 IMediaSample_Release(output_sample);
351 break;
353 if (FAILED(hr))
355 IMediaSample_Release(output_sample);
356 return hr;
359 wg_sample_queue_flush(filter->sample_queue, false);
361 hr = IMemInputPin_Receive(filter->source.pMemInputPin, output_sample);
362 if (FAILED(hr))
364 IMediaSample_Release(output_sample);
365 return hr;
368 IMediaSample_Release(output_sample);
371 return S_OK;
374 static const struct strmbase_sink_ops sink_ops =
376 .base.pin_query_accept = transform_sink_query_accept,
377 .base.pin_query_interface = transform_sink_query_interface,
378 .pfnReceive = transform_sink_receive,
381 static HRESULT transform_source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
383 struct transform *filter = impl_from_strmbase_filter(pin->filter);
385 return filter->ops->source_query_accept(filter, mt);
388 static HRESULT transform_source_get_media_type(struct strmbase_pin *pin, unsigned int index, AM_MEDIA_TYPE *mt)
390 struct transform *filter = impl_from_strmbase_filter(pin->filter);
392 return filter->ops->source_get_media_type(filter, index, mt);
395 static HRESULT transform_source_query_interface(struct strmbase_pin *pin, REFIID iid, void **out)
397 struct transform *filter = impl_from_strmbase_filter(pin->filter);
399 if (IsEqualGUID(iid, &IID_IMediaPosition))
400 *out = &filter->passthrough.IMediaPosition_iface;
401 else if (IsEqualGUID(iid, &IID_IMediaSeeking))
402 *out = &filter->passthrough.IMediaSeeking_iface;
403 else if (IsEqualGUID(iid, &IID_IQualityControl))
404 *out = &filter->source_IQualityControl_iface;
405 else
406 return E_NOINTERFACE;
408 IUnknown_AddRef((IUnknown *)*out);
409 return S_OK;
412 static HRESULT WINAPI transform_source_DecideBufferSize(struct strmbase_source *pin, IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props)
414 struct transform *filter = impl_from_strmbase_filter(pin->pin.filter);
416 return filter->ops->source_decide_buffer_size(filter, allocator, props);
419 static const struct strmbase_source_ops source_ops =
421 .base.pin_query_accept = transform_source_query_accept,
422 .base.pin_get_media_type = transform_source_get_media_type,
423 .base.pin_query_interface = transform_source_query_interface,
424 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
425 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
426 .pfnDecideBufferSize = transform_source_DecideBufferSize,
429 static struct transform *impl_from_sink_IQualityControl(IQualityControl *iface)
431 return CONTAINING_RECORD(iface, struct transform, sink_IQualityControl_iface);
434 static HRESULT WINAPI sink_quality_control_QueryInterface(IQualityControl *iface, REFIID iid, void **out)
436 struct transform *filter = impl_from_sink_IQualityControl(iface);
437 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
440 static ULONG WINAPI sink_quality_control_AddRef(IQualityControl *iface)
442 struct transform *filter = impl_from_sink_IQualityControl(iface);
443 return IPin_AddRef(&filter->source.pin.IPin_iface);
446 static ULONG WINAPI sink_quality_control_Release(IQualityControl *iface)
448 struct transform *filter = impl_from_sink_IQualityControl(iface);
449 return IPin_Release(&filter->source.pin.IPin_iface);
452 static HRESULT WINAPI sink_quality_control_Notify(IQualityControl *iface, IBaseFilter *sender, Quality q)
454 struct transform *filter = impl_from_sink_IQualityControl(iface);
456 TRACE("filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s.\n",
457 filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp));
459 return S_OK;
462 static HRESULT WINAPI sink_quality_control_SetSink(IQualityControl *iface, IQualityControl *sink)
464 struct transform *filter = impl_from_sink_IQualityControl(iface);
466 TRACE("filter %p, sink %p.\n", filter, sink);
468 filter->qc_sink = sink;
470 return S_OK;
473 static const IQualityControlVtbl sink_quality_control_vtbl =
475 sink_quality_control_QueryInterface,
476 sink_quality_control_AddRef,
477 sink_quality_control_Release,
478 sink_quality_control_Notify,
479 sink_quality_control_SetSink,
482 static struct transform *impl_from_source_IQualityControl(IQualityControl *iface)
484 return CONTAINING_RECORD(iface, struct transform, source_IQualityControl_iface);
487 static HRESULT WINAPI source_quality_control_QueryInterface(IQualityControl *iface, REFIID iid, void **out)
489 struct transform *filter = impl_from_source_IQualityControl(iface);
490 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
493 static ULONG WINAPI source_quality_control_AddRef(IQualityControl *iface)
495 struct transform *filter = impl_from_source_IQualityControl(iface);
496 return IPin_AddRef(&filter->source.pin.IPin_iface);
499 static ULONG WINAPI source_quality_control_Release(IQualityControl *iface)
501 struct transform *filter = impl_from_source_IQualityControl(iface);
502 return IPin_Release(&filter->source.pin.IPin_iface);
505 static HRESULT WINAPI source_quality_control_Notify(IQualityControl *iface, IBaseFilter *sender, Quality q)
507 struct transform *filter = impl_from_source_IQualityControl(iface);
508 IQualityControl *peer;
509 HRESULT hr = VFW_E_NOT_FOUND;
511 TRACE("filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s.\n",
512 filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp));
514 if (filter->qc_sink)
515 return IQualityControl_Notify(filter->qc_sink, &filter->filter.IBaseFilter_iface, q);
517 if (filter->sink.pin.peer
518 && SUCCEEDED(IPin_QueryInterface(filter->sink.pin.peer, &IID_IQualityControl, (void **)&peer)))
520 hr = IQualityControl_Notify(peer, &filter->filter.IBaseFilter_iface, q);
521 IQualityControl_Release(peer);
524 return hr;
527 static HRESULT WINAPI source_quality_control_SetSink(IQualityControl *iface, IQualityControl *sink)
529 struct transform *filter = impl_from_source_IQualityControl(iface);
531 TRACE("filter %p, sink %p.\n", filter, sink);
533 return S_OK;
536 static const IQualityControlVtbl source_quality_control_vtbl =
538 source_quality_control_QueryInterface,
539 source_quality_control_AddRef,
540 source_quality_control_Release,
541 source_quality_control_Notify,
542 source_quality_control_SetSink,
545 static HRESULT transform_create(IUnknown *outer, const CLSID *clsid, const struct transform_ops *ops, struct transform **out)
547 struct transform *object;
549 object = calloc(1, sizeof(*object));
550 if (!object)
551 return E_OUTOFMEMORY;
553 strmbase_filter_init(&object->filter, outer, clsid, &filter_ops);
554 strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL);
555 strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops);
557 strmbase_passthrough_init(&object->passthrough, (IUnknown *)&object->source.pin.IPin_iface);
558 ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE,
559 &object->sink.pin.IPin_iface);
561 object->sink_IQualityControl_iface.lpVtbl = &sink_quality_control_vtbl;
562 object->source_IQualityControl_iface.lpVtbl = &source_quality_control_vtbl;
564 object->ops = ops;
566 *out = object;
567 return S_OK;
570 static HRESULT mpeg_audio_codec_sink_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt)
572 const MPEG1WAVEFORMAT *format;
574 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio))
575 return S_FALSE;
577 if (!IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Packet)
578 && !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Payload)
579 && !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1AudioPayload)
580 && !IsEqualGUID(&mt->subtype, &GUID_NULL))
581 return S_FALSE;
583 if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
584 || mt->cbFormat < sizeof(MPEG1WAVEFORMAT))
585 return S_FALSE;
587 format = (const MPEG1WAVEFORMAT *)mt->pbFormat;
589 if (format->wfx.wFormatTag != WAVE_FORMAT_MPEG
590 || format->fwHeadLayer == ACM_MPEG_LAYER3)
591 return S_FALSE;
593 return S_OK;
596 static HRESULT mpeg_audio_codec_source_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt)
598 const MPEG1WAVEFORMAT *input_format;
599 const WAVEFORMATEX *output_format;
600 DWORD expected_avg_bytes_per_sec;
601 WORD expected_block_align;
603 if (!filter->sink.pin.peer)
604 return S_FALSE;
606 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)
607 || !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_PCM)
608 || !IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
609 || mt->cbFormat < sizeof(WAVEFORMATEX))
610 return S_FALSE;
612 input_format = (const MPEG1WAVEFORMAT *)filter->sink.pin.mt.pbFormat;
613 output_format = (const WAVEFORMATEX *)mt->pbFormat;
615 if (output_format->wFormatTag != WAVE_FORMAT_PCM
616 || input_format->wfx.nSamplesPerSec != output_format->nSamplesPerSec
617 || input_format->wfx.nChannels != output_format->nChannels
618 || (output_format->wBitsPerSample != 8 && output_format->wBitsPerSample != 16))
619 return S_FALSE;
621 expected_block_align = output_format->nChannels * output_format->wBitsPerSample / 8;
622 expected_avg_bytes_per_sec = expected_block_align * output_format->nSamplesPerSec;
624 if (output_format->nBlockAlign != expected_block_align
625 || output_format->nAvgBytesPerSec != expected_avg_bytes_per_sec)
626 return S_FALSE;
628 return S_OK;
631 static HRESULT mpeg_audio_codec_source_get_media_type(struct transform *filter, unsigned int index, AM_MEDIA_TYPE *mt)
633 const MPEG1WAVEFORMAT *input_format;
634 WAVEFORMATEX *output_format;
636 if (!filter->sink.pin.peer)
637 return VFW_S_NO_MORE_ITEMS;
639 if (index > 1)
640 return VFW_S_NO_MORE_ITEMS;
642 input_format = (const MPEG1WAVEFORMAT *)filter->sink.pin.mt.pbFormat;
644 output_format = CoTaskMemAlloc(sizeof(*output_format));
645 if (!output_format)
646 return E_OUTOFMEMORY;
648 memset(output_format, 0, sizeof(*output_format));
649 output_format->wFormatTag = WAVE_FORMAT_PCM;
650 output_format->nSamplesPerSec = input_format->wfx.nSamplesPerSec;
651 output_format->nChannels = input_format->wfx.nChannels;
652 output_format->wBitsPerSample = index ? 8 : 16;
653 output_format->nBlockAlign = output_format->nChannels * output_format->wBitsPerSample / 8;
654 output_format->nAvgBytesPerSec = output_format->nBlockAlign * output_format->nSamplesPerSec;
656 memset(mt, 0, sizeof(*mt));
657 mt->majortype = MEDIATYPE_Audio;
658 mt->subtype = MEDIASUBTYPE_PCM;
659 mt->bFixedSizeSamples = TRUE;
660 mt->lSampleSize = output_format->nBlockAlign;
661 mt->formattype = FORMAT_WaveFormatEx;
662 mt->cbFormat = sizeof(*output_format);
663 mt->pbFormat = (BYTE *)output_format;
665 return S_OK;
668 static HRESULT mpeg_audio_codec_source_decide_buffer_size(struct transform *filter, IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props)
670 MPEG1WAVEFORMAT *input_format = (MPEG1WAVEFORMAT *)filter->sink.pin.mt.pbFormat;
671 WAVEFORMATEX *output_format = (WAVEFORMATEX *)filter->source.pin.mt.pbFormat;
672 LONG frame_samples = (input_format->fwHeadLayer & ACM_MPEG_LAYER2) ? 1152 : 384;
673 LONG frame_size = frame_samples * output_format->nBlockAlign;
674 ALLOCATOR_PROPERTIES ret_props;
676 props->cBuffers = max(props->cBuffers, 8);
677 props->cbBuffer = max(props->cbBuffer, frame_size * 4);
678 props->cbAlign = max(props->cbAlign, 1);
680 return IMemAllocator_SetProperties(allocator, props, &ret_props);
683 static const struct transform_ops mpeg_audio_codec_transform_ops =
685 mpeg_audio_codec_sink_query_accept,
686 mpeg_audio_codec_source_query_accept,
687 mpeg_audio_codec_source_get_media_type,
688 mpeg_audio_codec_source_decide_buffer_size,
691 HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out)
693 static const struct wg_format output_format =
695 .major_type = WG_MAJOR_TYPE_AUDIO,
696 .u.audio =
698 .format = WG_AUDIO_FORMAT_S16LE,
699 .channel_mask = 1,
700 .channels = 1,
701 .rate = 44100,
704 static const struct wg_format input_format =
706 .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1,
707 .u.audio_mpeg1 =
709 .layer = 2,
710 .channels = 1,
711 .rate = 44100,
714 struct wg_transform_attrs attrs = {0};
715 wg_transform_t transform;
716 struct transform *object;
717 HRESULT hr;
719 transform = wg_transform_create(&input_format, &output_format, &attrs);
720 if (!transform)
722 ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n");
723 return E_FAIL;
725 wg_transform_destroy(transform);
727 hr = transform_create(outer, &CLSID_CMpegAudioCodec, &mpeg_audio_codec_transform_ops, &object);
728 if (FAILED(hr))
729 return hr;
731 wcscpy(object->sink.pin.name, L"XForm In");
732 wcscpy(object->source.pin.name, L"XForm Out");
734 object->IMpegAudioDecoder_iface.lpVtbl = &mpeg_audio_decoder_vtbl;
736 TRACE("Created MPEG audio decoder %p.\n", object);
737 *out = &object->filter.IUnknown_inner;
738 return hr;
741 static HRESULT mpeg_layer3_decoder_sink_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt)
743 const MPEGLAYER3WAVEFORMAT *format;
745 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)
746 || !IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
747 || mt->cbFormat < sizeof(MPEGLAYER3WAVEFORMAT))
748 return S_FALSE;
750 format = (const MPEGLAYER3WAVEFORMAT *)mt->pbFormat;
752 if (format->wfx.wFormatTag != WAVE_FORMAT_MPEGLAYER3)
753 return S_FALSE;
755 return S_OK;
758 static HRESULT mpeg_layer3_decoder_source_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt)
760 if (!filter->sink.pin.peer)
761 return S_FALSE;
763 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)
764 || !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_PCM))
765 return S_FALSE;
767 return S_OK;
770 static HRESULT mpeg_layer3_decoder_source_get_media_type(struct transform *filter, unsigned int index, AM_MEDIA_TYPE *mt)
772 const MPEGLAYER3WAVEFORMAT *input_format;
773 WAVEFORMATEX *output_format;
775 if (!filter->sink.pin.peer)
776 return VFW_S_NO_MORE_ITEMS;
778 if (index > 0)
779 return VFW_S_NO_MORE_ITEMS;
781 input_format = (const MPEGLAYER3WAVEFORMAT *)filter->sink.pin.mt.pbFormat;
783 output_format = CoTaskMemAlloc(sizeof(*output_format));
784 if (!output_format)
785 return E_OUTOFMEMORY;
787 memset(output_format, 0, sizeof(*output_format));
788 output_format->wFormatTag = WAVE_FORMAT_PCM;
789 output_format->nSamplesPerSec = input_format->wfx.nSamplesPerSec;
790 output_format->nChannels = input_format->wfx.nChannels;
791 output_format->wBitsPerSample = 16;
792 output_format->nBlockAlign = output_format->nChannels * output_format->wBitsPerSample / 8;
793 output_format->nAvgBytesPerSec = output_format->nBlockAlign * output_format->nSamplesPerSec;
795 memset(mt, 0, sizeof(*mt));
796 mt->majortype = MEDIATYPE_Audio;
797 mt->subtype = MEDIASUBTYPE_PCM;
798 mt->bFixedSizeSamples = TRUE;
799 mt->lSampleSize = 1152 * output_format->nBlockAlign;
800 mt->formattype = FORMAT_WaveFormatEx;
801 mt->cbFormat = sizeof(*output_format);
802 mt->pbFormat = (BYTE *)output_format;
804 return S_OK;
807 static HRESULT mpeg_layer3_decoder_source_decide_buffer_size(struct transform *filter, IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props)
809 ALLOCATOR_PROPERTIES ret_props;
811 props->cBuffers = max(props->cBuffers, 8);
812 props->cbBuffer = max(props->cbBuffer, filter->source.pin.mt.lSampleSize * 4);
813 props->cbAlign = max(props->cbAlign, 1);
815 return IMemAllocator_SetProperties(allocator, props, &ret_props);
818 static const struct transform_ops mpeg_layer3_decoder_transform_ops =
820 mpeg_layer3_decoder_sink_query_accept,
821 mpeg_layer3_decoder_source_query_accept,
822 mpeg_layer3_decoder_source_get_media_type,
823 mpeg_layer3_decoder_source_decide_buffer_size,
826 HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out)
828 static const struct wg_format output_format =
830 .major_type = WG_MAJOR_TYPE_AUDIO,
831 .u.audio =
833 .format = WG_AUDIO_FORMAT_S16LE,
834 .channel_mask = 1,
835 .channels = 1,
836 .rate = 44100,
839 static const struct wg_format input_format =
841 .major_type = WG_MAJOR_TYPE_AUDIO_MPEG1,
842 .u.audio_mpeg1 =
844 .layer = 3,
845 .channels = 1,
846 .rate = 44100,
849 struct wg_transform_attrs attrs = {0};
850 wg_transform_t transform;
851 struct transform *object;
852 HRESULT hr;
854 transform = wg_transform_create(&input_format, &output_format, &attrs);
855 if (!transform)
857 ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n");
858 return E_FAIL;
860 wg_transform_destroy(transform);
862 hr = transform_create(outer, &CLSID_mpeg_layer3_decoder, &mpeg_layer3_decoder_transform_ops, &object);
863 if (FAILED(hr))
864 return hr;
866 wcscpy(object->sink.pin.name, L"XForm In");
867 wcscpy(object->source.pin.name, L"XForm Out");
869 TRACE("Created MPEG layer-3 decoder %p.\n", object);
870 *out = &object->filter.IUnknown_inner;
871 return hr;