dmime/tests: Check more notification / dirty messages fields.
[wine.git] / dlls / mp3dmod / mp3dmod.c
blob842be5889dab238a19c70e2fa09eae6a7da1c580
1 /*
2 * MP3 decoder DMO
4 * Copyright 2018 Zebediah Figura
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 <stdarg.h>
22 #include <stdio.h>
23 #include <mpg123.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "mmreg.h"
28 #define COBJMACROS
29 #include "objbase.h"
30 #include "dmo.h"
31 #include "rpcproxy.h"
32 #include "wmcodecdsp.h"
33 #include "wine/debug.h"
35 #include "initguid.h"
36 DEFINE_GUID(WMMEDIATYPE_Audio, 0x73647561,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
37 DEFINE_GUID(WMMEDIASUBTYPE_MP3,0x00000055,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
38 DEFINE_GUID(WMMEDIASUBTYPE_PCM,0x00000001,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
39 DEFINE_GUID(WMFORMAT_WaveFormatEx, 0x05589f81,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a);
41 WINE_DEFAULT_DEBUG_CHANNEL(mp3dmod);
43 struct mp3_decoder
45 IUnknown IUnknown_inner;
46 IMediaObject IMediaObject_iface;
47 IUnknown *outer;
48 LONG ref;
49 mpg123_handle *mh;
51 DMO_MEDIA_TYPE intype, outtype;
52 BOOL intype_set, outtype_set;
54 IMediaBuffer *buffer;
55 REFERENCE_TIME timestamp;
58 static inline struct mp3_decoder *impl_from_IUnknown(IUnknown *iface)
60 return CONTAINING_RECORD(iface, struct mp3_decoder, IUnknown_inner);
63 static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID iid, void **obj)
65 struct mp3_decoder *This = impl_from_IUnknown(iface);
67 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), obj);
69 if (IsEqualGUID(iid, &IID_IUnknown))
70 *obj = &This->IUnknown_inner;
71 else if (IsEqualGUID(iid, &IID_IMediaObject))
72 *obj = &This->IMediaObject_iface;
73 else
75 FIXME("no interface for %s\n", debugstr_guid(iid));
76 *obj = NULL;
77 return E_NOINTERFACE;
80 IUnknown_AddRef((IUnknown *)*obj);
81 return S_OK;
84 static ULONG WINAPI Unknown_AddRef(IUnknown *iface)
86 struct mp3_decoder *This = impl_from_IUnknown(iface);
87 ULONG refcount = InterlockedIncrement(&This->ref);
89 TRACE("(%p) AddRef from %ld\n", This, refcount - 1);
91 return refcount;
94 static ULONG WINAPI Unknown_Release(IUnknown *iface)
96 struct mp3_decoder *This = impl_from_IUnknown(iface);
97 ULONG refcount = InterlockedDecrement(&This->ref);
99 TRACE("(%p) Release from %ld\n", This, refcount + 1);
101 if (!refcount)
103 if (This->buffer)
104 IMediaBuffer_Release(This->buffer);
105 if (This->intype_set)
106 MoFreeMediaType(&This->intype);
107 MoFreeMediaType(&This->outtype);
108 mpg123_delete(This->mh);
109 free(This);
111 return refcount;
114 static const IUnknownVtbl Unknown_vtbl = {
115 Unknown_QueryInterface,
116 Unknown_AddRef,
117 Unknown_Release,
120 static inline struct mp3_decoder *impl_from_IMediaObject(IMediaObject *iface)
122 return CONTAINING_RECORD(iface, struct mp3_decoder, IMediaObject_iface);
125 static HRESULT WINAPI MediaObject_QueryInterface(IMediaObject *iface, REFIID iid, void **obj)
127 struct mp3_decoder *This = impl_from_IMediaObject(iface);
128 return IUnknown_QueryInterface(This->outer, iid, obj);
131 static ULONG WINAPI MediaObject_AddRef(IMediaObject *iface)
133 struct mp3_decoder *This = impl_from_IMediaObject(iface);
134 return IUnknown_AddRef(This->outer);
137 static ULONG WINAPI MediaObject_Release(IMediaObject *iface)
139 struct mp3_decoder *This = impl_from_IMediaObject(iface);
140 return IUnknown_Release(This->outer);
143 static HRESULT WINAPI MediaObject_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output)
145 TRACE("iface %p, input %p, output %p.\n", iface, input, output);
147 *input = *output = 1;
149 return S_OK;
152 static HRESULT WINAPI MediaObject_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
154 TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags);
156 *flags = 0;
158 return S_OK;
161 static HRESULT WINAPI MediaObject_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
163 TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags);
165 *flags = 0;
167 return S_OK;
170 static HRESULT WINAPI MediaObject_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type)
172 TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type);
174 if (type_index)
175 return DMO_E_NO_MORE_ITEMS;
177 type->majortype = WMMEDIATYPE_Audio;
178 type->subtype = WMMEDIASUBTYPE_MP3;
179 type->formattype = GUID_NULL;
180 type->pUnk = NULL;
181 type->cbFormat = 0;
182 type->pbFormat = NULL;
184 return S_OK;
187 static HRESULT WINAPI MediaObject_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type)
189 struct mp3_decoder *dmo = impl_from_IMediaObject(iface);
190 const WAVEFORMATEX *input_format;
191 WAVEFORMATEX *format;
193 TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type);
195 if (!dmo->intype_set)
196 return DMO_E_TYPE_NOT_SET;
198 input_format = (WAVEFORMATEX *)dmo->intype.pbFormat;
200 if (type_index >= (2 * input_format->nChannels))
201 return DMO_E_NO_MORE_ITEMS;
203 type->majortype = WMMEDIATYPE_Audio;
204 type->subtype = WMMEDIASUBTYPE_PCM;
205 type->formattype = WMFORMAT_WaveFormatEx;
206 type->pUnk = NULL;
207 type->cbFormat = sizeof(WAVEFORMATEX);
208 if (!(type->pbFormat = CoTaskMemAlloc(sizeof(WAVEFORMATEX))))
209 return E_OUTOFMEMORY;
210 format = (WAVEFORMATEX *)type->pbFormat;
211 format->wFormatTag = WAVE_FORMAT_PCM;
212 format->nSamplesPerSec = input_format->nSamplesPerSec;
213 format->nChannels = (type_index / 2) ? 1 : input_format->nChannels;
214 format->wBitsPerSample = (type_index % 2) ? 8 : 16;
215 format->nBlockAlign = format->nChannels * format->wBitsPerSample / 8;
216 format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
217 format->cbSize = 0;
219 return S_OK;
222 static HRESULT WINAPI MediaObject_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags)
224 struct mp3_decoder *dmo = impl_from_IMediaObject(iface);
226 TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags);
228 if (flags & DMO_SET_TYPEF_CLEAR)
230 if (dmo->intype_set)
231 MoFreeMediaType(&dmo->intype);
232 dmo->intype_set = FALSE;
233 return S_OK;
236 if (!IsEqualGUID(&type->majortype, &WMMEDIATYPE_Audio)
237 || !IsEqualGUID(&type->subtype, &WMMEDIASUBTYPE_MP3)
238 || !IsEqualGUID(&type->formattype, &WMFORMAT_WaveFormatEx))
239 return DMO_E_TYPE_NOT_ACCEPTED;
241 if (!(flags & DMO_SET_TYPEF_TEST_ONLY))
243 if (dmo->intype_set)
244 MoFreeMediaType(&dmo->intype);
245 MoCopyMediaType(&dmo->intype, type);
246 dmo->intype_set = TRUE;
249 return S_OK;
252 static HRESULT WINAPI MediaObject_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags)
254 struct mp3_decoder *This = impl_from_IMediaObject(iface);
255 WAVEFORMATEX *format;
256 long enc;
257 int err;
259 TRACE("(%p)->(%ld, %p, %#lx)\n", iface, index, type, flags);
261 if (flags & DMO_SET_TYPEF_CLEAR)
263 MoFreeMediaType(&This->outtype);
264 This->outtype_set = FALSE;
265 return S_OK;
268 if (!IsEqualGUID(&type->formattype, &WMFORMAT_WaveFormatEx))
269 return DMO_E_TYPE_NOT_ACCEPTED;
271 format = (WAVEFORMATEX *)type->pbFormat;
273 if (format->wBitsPerSample == 8)
274 enc = MPG123_ENC_UNSIGNED_8;
275 else if (format->wBitsPerSample == 16)
276 enc = MPG123_ENC_SIGNED_16;
277 else
279 ERR("Cannot decode to bit depth %u.\n", format->wBitsPerSample);
280 return DMO_E_TYPE_NOT_ACCEPTED;
283 if (!(flags & DMO_SET_TYPEF_TEST_ONLY))
285 err = mpg123_format(This->mh, format->nSamplesPerSec, format->nChannels, enc);
286 if (err != MPG123_OK)
288 ERR("Failed to set format: %u channels, %lu samples/sec, %u bits/sample.\n",
289 format->nChannels, format->nSamplesPerSec, format->wBitsPerSample);
290 return DMO_E_TYPE_NOT_ACCEPTED;
292 MoCopyMediaType(&This->outtype, type);
293 This->outtype_set = TRUE;
296 return S_OK;
299 static HRESULT WINAPI MediaObject_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
301 FIXME("(%p)->(%ld, %p) stub!\n", iface, index, type);
303 return E_NOTIMPL;
306 static HRESULT WINAPI MediaObject_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
308 FIXME("(%p)->(%ld, %p) stub!\n", iface, index, type);
310 return E_NOTIMPL;
313 static HRESULT WINAPI MediaObject_GetInputSizeInfo(IMediaObject *iface,
314 DWORD index, DWORD *size, DWORD *lookahead, DWORD *alignment)
316 struct mp3_decoder *dmo = impl_from_IMediaObject(iface);
318 TRACE("iface %p, index %lu, size %p, lookahead %p, alignment %p.\n", iface, index, size, lookahead, alignment);
320 if (!dmo->intype_set || !dmo->outtype_set)
321 return DMO_E_TYPE_NOT_SET;
323 *size = 0;
324 *alignment = 1;
325 return S_OK;
328 static HRESULT WINAPI MediaObject_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
330 struct mp3_decoder *dmo = impl_from_IMediaObject(iface);
332 TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment);
334 if (!dmo->intype_set || !dmo->outtype_set)
335 return DMO_E_TYPE_NOT_SET;
337 *size = 2 * 1152 * ((WAVEFORMATEX *)dmo->outtype.pbFormat)->wBitsPerSample / 8;
338 *alignment = 1;
339 return S_OK;
342 static HRESULT WINAPI MediaObject_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency)
344 FIXME("(%p)->(%ld, %p) stub!\n", iface, index, latency);
346 return E_NOTIMPL;
349 static HRESULT WINAPI MediaObject_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency)
351 FIXME("(%p)->(%ld, %s) stub!\n", iface, index, wine_dbgstr_longlong(latency));
353 return E_NOTIMPL;
356 static HRESULT WINAPI MediaObject_Flush(IMediaObject *iface)
358 struct mp3_decoder *dmo = impl_from_IMediaObject(iface);
360 TRACE("iface %p.\n", iface);
362 if (dmo->buffer)
363 IMediaBuffer_Release(dmo->buffer);
364 dmo->buffer = NULL;
365 dmo->timestamp = 0;
367 /* mpg123 doesn't give us a way to flush, so just close and reopen the feed. */
368 mpg123_close(dmo->mh);
369 mpg123_open_feed(dmo->mh);
371 return S_OK;
374 static HRESULT WINAPI MediaObject_Discontinuity(IMediaObject *iface, DWORD index)
376 TRACE("iface %p.\n", iface);
378 return S_OK;
381 static HRESULT WINAPI MediaObject_AllocateStreamingResources(IMediaObject *iface)
383 FIXME("(%p)->() stub!\n", iface);
385 return E_NOTIMPL;
388 static HRESULT WINAPI MediaObject_FreeStreamingResources(IMediaObject *iface)
390 FIXME("(%p)->() stub!\n", iface);
392 return E_NOTIMPL;
395 static HRESULT WINAPI MediaObject_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags)
397 FIXME("(%p)->(%ld, %p) stub!\n", iface, index, flags);
399 return E_NOTIMPL;
402 static HRESULT WINAPI MediaObject_ProcessInput(IMediaObject *iface, DWORD index,
403 IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength)
405 struct mp3_decoder *This = impl_from_IMediaObject(iface);
406 HRESULT hr;
407 BYTE *data;
408 DWORD len;
409 int err;
411 TRACE("(%p)->(%ld, %p, %#lx, %s, %s)\n", iface, index, buffer, flags,
412 wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength));
414 if (This->buffer)
416 ERR("Already have a buffer.\n");
417 return DMO_E_NOTACCEPTING;
420 IMediaBuffer_AddRef(buffer);
421 This->buffer = buffer;
423 hr = IMediaBuffer_GetBufferAndLength(buffer, &data, &len);
424 if (FAILED(hr))
425 return hr;
427 err = mpg123_feed(This->mh, data, len);
428 if (err != MPG123_OK)
430 ERR("mpg123_feed() failed: %s\n", mpg123_strerror(This->mh));
431 return E_FAIL;
434 return S_OK;
437 static DWORD get_framesize(DMO_MEDIA_TYPE *type)
439 WAVEFORMATEX *format = (WAVEFORMATEX *)type->pbFormat;
440 return 1152 * format->nBlockAlign;
443 static REFERENCE_TIME get_frametime(DMO_MEDIA_TYPE *type)
445 WAVEFORMATEX *format = (WAVEFORMATEX *)type->pbFormat;
446 return (REFERENCE_TIME) 10000000 * 1152 / format->nSamplesPerSec;
449 static HRESULT WINAPI MediaObject_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
451 struct mp3_decoder *This = impl_from_IMediaObject(iface);
452 REFERENCE_TIME time = 0, frametime;
453 DWORD len, maxlen, framesize;
454 int got_data = 0;
455 size_t written;
456 HRESULT hr;
457 BYTE *data;
458 int err;
460 TRACE("(%p)->(%#lx, %ld, %p, %p)\n", iface, flags, count, buffers, status);
462 if (count > 1)
463 FIXME("Multiple buffers not handled.\n");
465 buffers[0].dwStatus = 0;
467 if (!buffers[0].pBuffer)
469 while ((err = mpg123_read(This->mh, NULL, 0, &written)) == MPG123_NEW_FORMAT);
470 if (err == MPG123_NEED_MORE)
471 return S_OK;
472 else if (err == MPG123_ERR)
473 ERR("mpg123_read() failed: %s\n", mpg123_strerror(This->mh));
474 else if (err != MPG123_OK)
475 ERR("mpg123_read() returned %d\n", err);
477 buffers[0].dwStatus = DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
478 return S_OK;
481 if (!This->buffer)
482 return S_FALSE;
484 buffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT;
486 hr = IMediaBuffer_GetBufferAndLength(buffers[0].pBuffer, &data, &len);
487 if (FAILED(hr)) return hr;
489 hr = IMediaBuffer_GetMaxLength(buffers[0].pBuffer, &maxlen);
490 if (FAILED(hr)) return hr;
492 framesize = get_framesize(&This->outtype);
493 frametime = get_frametime(&This->outtype);
495 while (1)
497 if (maxlen - len < framesize)
499 buffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
500 break;
503 while ((err = mpg123_read(This->mh, data + len, framesize, &written)) == MPG123_NEW_FORMAT);
504 if (err == MPG123_NEED_MORE)
506 IMediaBuffer_Release(This->buffer);
507 This->buffer = NULL;
508 break;
510 else if (err == MPG123_ERR)
511 ERR("mpg123_read() failed: %s\n", mpg123_strerror(This->mh));
512 else if (err != MPG123_OK)
513 ERR("mpg123_read() returned %d\n", err);
514 if (written < framesize)
515 ERR("short write: %Id/%lu\n", written, framesize);
517 got_data = 1;
519 len += framesize;
520 hr = IMediaBuffer_SetLength(buffers[0].pBuffer, len);
521 if (FAILED(hr)) return hr;
523 time += frametime;
526 if (got_data)
528 buffers[0].dwStatus |= (DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH);
529 buffers[0].rtTimelength = time;
530 buffers[0].rtTimestamp = This->timestamp;
531 This->timestamp += time;
532 return S_OK;
534 return S_FALSE;
537 static HRESULT WINAPI MediaObject_Lock(IMediaObject *iface, LONG lock)
539 FIXME("(%p)->(%ld) stub!\n", iface, lock);
541 return E_NOTIMPL;
544 static const IMediaObjectVtbl MediaObject_vtbl = {
545 MediaObject_QueryInterface,
546 MediaObject_AddRef,
547 MediaObject_Release,
548 MediaObject_GetStreamCount,
549 MediaObject_GetInputStreamInfo,
550 MediaObject_GetOutputStreamInfo,
551 MediaObject_GetInputType,
552 MediaObject_GetOutputType,
553 MediaObject_SetInputType,
554 MediaObject_SetOutputType,
555 MediaObject_GetInputCurrentType,
556 MediaObject_GetOutputCurrentType,
557 MediaObject_GetInputSizeInfo,
558 MediaObject_GetOutputSizeInfo,
559 MediaObject_GetInputMaxLatency,
560 MediaObject_SetInputMaxLatency,
561 MediaObject_Flush,
562 MediaObject_Discontinuity,
563 MediaObject_AllocateStreamingResources,
564 MediaObject_FreeStreamingResources,
565 MediaObject_GetInputStatus,
566 MediaObject_ProcessInput,
567 MediaObject_ProcessOutput,
568 MediaObject_Lock,
571 static HRESULT create_mp3_decoder(IUnknown *outer, REFIID iid, void **obj)
573 struct mp3_decoder *This;
574 HRESULT hr;
575 int err;
577 if (!(This = calloc(1, sizeof(*This))))
578 return E_OUTOFMEMORY;
580 This->IUnknown_inner.lpVtbl = &Unknown_vtbl;
581 This->IMediaObject_iface.lpVtbl = &MediaObject_vtbl;
582 This->ref = 1;
583 This->outer = outer ? outer : &This->IUnknown_inner;
585 mpg123_init();
586 This->mh = mpg123_new(NULL, &err);
587 mpg123_open_feed(This->mh);
588 mpg123_format_none(This->mh);
590 hr = IUnknown_QueryInterface(&This->IUnknown_inner, iid, obj);
591 IUnknown_Release(&This->IUnknown_inner);
592 return hr;
595 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID iid, void **obj)
597 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), obj);
599 if (IsEqualGUID(&IID_IUnknown, iid) ||
600 IsEqualGUID(&IID_IClassFactory, iid))
602 IClassFactory_AddRef(iface);
603 *obj = iface;
604 return S_OK;
607 *obj = NULL;
608 WARN("no interface for %s\n", debugstr_guid(iid));
609 return E_NOINTERFACE;
612 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
614 return 2;
617 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
619 return 1;
622 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **obj)
624 TRACE("(%p, %s, %p)\n", outer, debugstr_guid(iid), obj);
626 if (outer && !IsEqualGUID(iid, &IID_IUnknown))
628 *obj = NULL;
629 return E_NOINTERFACE;
632 return create_mp3_decoder(outer, iid, obj);
635 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL lock)
637 FIXME("(%d) stub\n", lock);
638 return S_OK;
641 static const IClassFactoryVtbl classfactory_vtbl = {
642 ClassFactory_QueryInterface,
643 ClassFactory_AddRef,
644 ClassFactory_Release,
645 ClassFactory_CreateInstance,
646 ClassFactory_LockServer
649 static IClassFactory mp3_decoder_cf = { &classfactory_vtbl };
651 /*************************************************************************
652 * DllGetClassObject (DSDMO.@)
654 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **obj)
656 TRACE("%s, %s, %p\n", debugstr_guid(clsid), debugstr_guid(iid), obj);
658 if (IsEqualGUID(clsid, &CLSID_CMP3DecMediaObject))
659 return IClassFactory_QueryInterface(&mp3_decoder_cf, iid, obj);
661 FIXME("class %s not available\n", debugstr_guid(clsid));
662 return CLASS_E_CLASSNOTAVAILABLE;
665 /***********************************************************************
666 * DllRegisterServer (DSDMO.@)
668 HRESULT WINAPI DllRegisterServer(void)
670 DMO_PARTIAL_MEDIATYPE in, out;
671 HRESULT hr;
673 in.type = WMMEDIATYPE_Audio;
674 in.subtype = WMMEDIASUBTYPE_MP3;
675 out.type = WMMEDIATYPE_Audio;
676 out.subtype = WMMEDIASUBTYPE_PCM;
677 hr = DMORegister(L"MP3 Decoder DMO", &CLSID_CMP3DecMediaObject, &DMOCATEGORY_AUDIO_DECODER,
678 0, 1, &in, 1, &out);
679 if (FAILED(hr)) return hr;
681 return __wine_register_resources();
684 /***********************************************************************
685 * DllUnregisterServer (DSDMO.@)
687 HRESULT WINAPI DllUnregisterServer(void)
689 HRESULT hr;
691 hr = DMOUnregister(&CLSID_CMP3DecMediaObject, &DMOCATEGORY_AUDIO_DECODER);
692 if (FAILED(hr)) return hr;
694 return __wine_unregister_resources();