1 /* GStreamer Base Functions
3 * Copyright 2002 Lionel Ulmer
4 * Copyright 2010 Aric Stewart, CodeWeavers
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 #define WINE_NO_NAMELESS_EXTENSION
23 #define EXTERN_GUID DEFINE_GUID
25 #include "gst_private.h"
29 #include "gst_guids.h"
30 #include "wmcodecdsp.h"
32 static unixlib_handle_t unix_handle
;
34 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
36 DEFINE_GUID(GUID_NULL
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
38 bool array_reserve(void **elements
, size_t *capacity
, size_t count
, size_t size
)
40 unsigned int new_capacity
, max_capacity
;
43 if (count
<= *capacity
)
46 max_capacity
= ~(SIZE_T
)0 / size
;
47 if (count
> max_capacity
)
50 new_capacity
= max(4, *capacity
);
51 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
53 if (new_capacity
< count
)
54 new_capacity
= max_capacity
;
56 if (!(new_elements
= realloc(*elements
, new_capacity
* size
)))
59 *elements
= new_elements
;
60 *capacity
= new_capacity
;
65 struct wg_parser
*wg_parser_create(enum wg_parser_type type
, bool unlimited_buffering
)
67 struct wg_parser_create_params params
=
70 .unlimited_buffering
= unlimited_buffering
,
73 TRACE("type %#x, unlimited_buffering %d.\n", type
, unlimited_buffering
);
75 if (__wine_unix_call(unix_handle
, unix_wg_parser_create
, ¶ms
))
78 TRACE("Returning parser %p.\n", params
.parser
);
83 void wg_parser_destroy(struct wg_parser
*parser
)
85 TRACE("parser %p.\n", parser
);
87 __wine_unix_call(unix_handle
, unix_wg_parser_destroy
, parser
);
90 HRESULT
wg_parser_connect(struct wg_parser
*parser
, uint64_t file_size
)
92 struct wg_parser_connect_params params
=
95 .file_size
= file_size
,
98 TRACE("parser %p, file_size %I64u.\n", parser
, file_size
);
100 return __wine_unix_call(unix_handle
, unix_wg_parser_connect
, ¶ms
);
103 void wg_parser_disconnect(struct wg_parser
*parser
)
105 TRACE("parser %p.\n", parser
);
107 __wine_unix_call(unix_handle
, unix_wg_parser_disconnect
, parser
);
110 bool wg_parser_get_next_read_offset(struct wg_parser
*parser
, uint64_t *offset
, uint32_t *size
)
112 struct wg_parser_get_next_read_offset_params params
=
117 TRACE("parser %p, offset %p, size %p.\n", parser
, offset
, size
);
119 if (__wine_unix_call(unix_handle
, unix_wg_parser_get_next_read_offset
, ¶ms
))
121 *offset
= params
.offset
;
126 void wg_parser_push_data(struct wg_parser
*parser
, const void *data
, uint32_t size
)
128 struct wg_parser_push_data_params params
=
135 TRACE("parser %p, data %p, size %u.\n", parser
, data
, size
);
137 __wine_unix_call(unix_handle
, unix_wg_parser_push_data
, ¶ms
);
140 uint32_t wg_parser_get_stream_count(struct wg_parser
*parser
)
142 struct wg_parser_get_stream_count_params params
=
147 TRACE("parser %p.\n", parser
);
149 __wine_unix_call(unix_handle
, unix_wg_parser_get_stream_count
, ¶ms
);
153 struct wg_parser_stream
*wg_parser_get_stream(struct wg_parser
*parser
, uint32_t index
)
155 struct wg_parser_get_stream_params params
=
161 TRACE("parser %p, index %u.\n", parser
, index
);
163 __wine_unix_call(unix_handle
, unix_wg_parser_get_stream
, ¶ms
);
165 TRACE("Returning stream %p.\n", params
.stream
);
166 return params
.stream
;
169 void wg_parser_stream_get_preferred_format(struct wg_parser_stream
*stream
, struct wg_format
*format
)
171 struct wg_parser_stream_get_preferred_format_params params
=
177 TRACE("stream %p, format %p.\n", stream
, format
);
179 __wine_unix_call(unix_handle
, unix_wg_parser_stream_get_preferred_format
, ¶ms
);
182 void wg_parser_stream_enable(struct wg_parser_stream
*stream
, const struct wg_format
*format
)
184 struct wg_parser_stream_enable_params params
=
190 TRACE("stream %p, format %p.\n", stream
, format
);
192 __wine_unix_call(unix_handle
, unix_wg_parser_stream_enable
, ¶ms
);
195 void wg_parser_stream_disable(struct wg_parser_stream
*stream
)
197 TRACE("stream %p.\n", stream
);
199 __wine_unix_call(unix_handle
, unix_wg_parser_stream_disable
, stream
);
202 bool wg_parser_stream_get_buffer(struct wg_parser_stream
*stream
, struct wg_parser_buffer
*buffer
)
204 struct wg_parser_stream_get_buffer_params params
=
210 TRACE("stream %p, buffer %p.\n", stream
, buffer
);
212 return !__wine_unix_call(unix_handle
, unix_wg_parser_stream_get_buffer
, ¶ms
);
215 bool wg_parser_stream_copy_buffer(struct wg_parser_stream
*stream
,
216 void *data
, uint32_t offset
, uint32_t size
)
218 struct wg_parser_stream_copy_buffer_params params
=
226 TRACE("stream %p, data %p, offset %u, size %u.\n", stream
, data
, offset
, size
);
228 return !__wine_unix_call(unix_handle
, unix_wg_parser_stream_copy_buffer
, ¶ms
);
231 void wg_parser_stream_release_buffer(struct wg_parser_stream
*stream
)
233 TRACE("stream %p.\n", stream
);
235 __wine_unix_call(unix_handle
, unix_wg_parser_stream_release_buffer
, stream
);
238 void wg_parser_stream_notify_qos(struct wg_parser_stream
*stream
,
239 bool underflow
, double proportion
, int64_t diff
, uint64_t timestamp
)
241 struct wg_parser_stream_notify_qos_params params
=
244 .underflow
= underflow
,
245 .proportion
= proportion
,
247 .timestamp
= timestamp
,
250 TRACE("stream %p, underflow %d, proportion %.16e, diff %I64d, timestamp %I64u.\n",
251 stream
, underflow
, proportion
, diff
, timestamp
);
253 __wine_unix_call(unix_handle
, unix_wg_parser_stream_notify_qos
, ¶ms
);
256 uint64_t wg_parser_stream_get_duration(struct wg_parser_stream
*stream
)
258 struct wg_parser_stream_get_duration_params params
=
263 TRACE("stream %p.\n", stream
);
265 __wine_unix_call(unix_handle
, unix_wg_parser_stream_get_duration
, ¶ms
);
267 TRACE("Returning duration %I64u.\n", params
.duration
);
268 return params
.duration
;
271 void wg_parser_stream_seek(struct wg_parser_stream
*stream
, double rate
,
272 uint64_t start_pos
, uint64_t stop_pos
, DWORD start_flags
, DWORD stop_flags
)
274 struct wg_parser_stream_seek_params params
=
278 .start_pos
= start_pos
,
279 .stop_pos
= stop_pos
,
280 .start_flags
= start_flags
,
281 .stop_flags
= stop_flags
,
284 TRACE("stream %p, rate %.16e, start_pos %I64u, stop_pos %I64u, start_flags %#lx, stop_flags %#lx.\n",
285 stream
, rate
, start_pos
, stop_pos
, start_flags
, stop_flags
);
287 __wine_unix_call(unix_handle
, unix_wg_parser_stream_seek
, ¶ms
);
290 struct wg_transform
*wg_transform_create(const struct wg_format
*input_format
,
291 const struct wg_format
*output_format
)
293 struct wg_transform_create_params params
=
295 .input_format
= input_format
,
296 .output_format
= output_format
,
299 TRACE("input_format %p, output_format %p.\n", input_format
, output_format
);
301 if (__wine_unix_call(unix_handle
, unix_wg_transform_create
, ¶ms
))
304 TRACE("Returning transform %p.\n", params
.transform
);
305 return params
.transform
;
308 void wg_transform_destroy(struct wg_transform
*transform
)
310 TRACE("transform %p.\n", transform
);
312 __wine_unix_call(unix_handle
, unix_wg_transform_destroy
, transform
);
315 HRESULT
wg_transform_push_data(struct wg_transform
*transform
, struct wg_sample
*sample
)
317 struct wg_transform_push_data_params params
=
319 .transform
= transform
,
324 TRACE("transform %p, sample %p.\n", transform
, sample
);
326 if ((status
= __wine_unix_call(unix_handle
, unix_wg_transform_push_data
, ¶ms
)))
327 return HRESULT_FROM_NT(status
);
329 return params
.result
;
332 HRESULT
wg_transform_read_data(struct wg_transform
*transform
, struct wg_sample
*sample
)
334 struct wg_transform_read_data_params params
=
336 .transform
= transform
,
341 TRACE("transform %p, sample %p.\n", transform
, sample
);
343 if ((status
= __wine_unix_call(unix_handle
, unix_wg_transform_read_data
, ¶ms
)))
344 return HRESULT_FROM_NT(status
);
346 return params
.result
;
349 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, void *reserved
)
351 if (reason
== DLL_PROCESS_ATTACH
)
353 DisableThreadLibraryCalls(instance
);
354 NtQueryVirtualMemory(GetCurrentProcess(), instance
, MemoryWineUnixFuncs
,
355 &unix_handle
, sizeof(unix_handle
), NULL
);
362 IClassFactory IClassFactory_iface
;
363 HRESULT (*create_instance
)(IUnknown
*outer
, IUnknown
**out
);
366 static inline struct class_factory
*impl_from_IClassFactory(IClassFactory
*iface
)
368 return CONTAINING_RECORD(iface
, struct class_factory
, IClassFactory_iface
);
371 static HRESULT WINAPI
class_factory_QueryInterface(IClassFactory
*iface
, REFIID iid
, void **out
)
373 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
375 if (IsEqualGUID(iid
, &IID_IUnknown
) || IsEqualGUID(iid
, &IID_IClassFactory
))
378 IClassFactory_AddRef(iface
);
383 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
384 return E_NOINTERFACE
;
387 static ULONG WINAPI
class_factory_AddRef(IClassFactory
*iface
)
392 static ULONG WINAPI
class_factory_Release(IClassFactory
*iface
)
397 static HRESULT WINAPI
class_factory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID iid
, void **out
)
399 struct class_factory
*factory
= impl_from_IClassFactory(iface
);
403 TRACE("iface %p, outer %p, iid %s, out %p.\n", iface
, outer
, debugstr_guid(iid
), out
);
405 if (outer
&& !IsEqualGUID(iid
, &IID_IUnknown
))
406 return E_NOINTERFACE
;
409 if (SUCCEEDED(hr
= factory
->create_instance(outer
, &unk
)))
411 hr
= IUnknown_QueryInterface(unk
, iid
, out
);
412 IUnknown_Release(unk
);
417 static HRESULT WINAPI
class_factory_LockServer(IClassFactory
*iface
, BOOL lock
)
419 TRACE("iface %p, lock %d.\n", iface
, lock
);
423 static const IClassFactoryVtbl class_factory_vtbl
=
425 class_factory_QueryInterface
,
426 class_factory_AddRef
,
427 class_factory_Release
,
428 class_factory_CreateInstance
,
429 class_factory_LockServer
,
432 static struct class_factory avi_splitter_cf
= {{&class_factory_vtbl
}, avi_splitter_create
};
433 static struct class_factory decodebin_parser_cf
= {{&class_factory_vtbl
}, decodebin_parser_create
};
434 static struct class_factory mpeg_audio_codec_cf
= {{&class_factory_vtbl
}, mpeg_audio_codec_create
};
435 static struct class_factory mpeg_splitter_cf
= {{&class_factory_vtbl
}, mpeg_splitter_create
};
436 static struct class_factory wave_parser_cf
= {{&class_factory_vtbl
}, wave_parser_create
};
437 static struct class_factory wma_decoder_cf
= {{&class_factory_vtbl
}, wma_decoder_create
};
439 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID iid
, void **out
)
441 struct class_factory
*factory
;
444 TRACE("clsid %s, iid %s, out %p.\n", debugstr_guid(clsid
), debugstr_guid(iid
), out
);
446 if (!init_gstreamer())
447 return CLASS_E_CLASSNOTAVAILABLE
;
449 if (SUCCEEDED(hr
= mfplat_get_class_object(clsid
, iid
, out
)))
452 if (IsEqualGUID(clsid
, &CLSID_AviSplitter
))
453 factory
= &avi_splitter_cf
;
454 else if (IsEqualGUID(clsid
, &CLSID_decodebin_parser
))
455 factory
= &decodebin_parser_cf
;
456 else if (IsEqualGUID(clsid
, &CLSID_CMpegAudioCodec
))
457 factory
= &mpeg_audio_codec_cf
;
458 else if (IsEqualGUID(clsid
, &CLSID_MPEG1Splitter
))
459 factory
= &mpeg_splitter_cf
;
460 else if (IsEqualGUID(clsid
, &CLSID_WAVEParser
))
461 factory
= &wave_parser_cf
;
462 else if (IsEqualGUID(clsid
, &CLSID_WMADecMediaObject
))
463 factory
= &wma_decoder_cf
;
466 FIXME("%s not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid(clsid
));
467 return CLASS_E_CLASSNOTAVAILABLE
;
470 return IClassFactory_QueryInterface(&factory
->IClassFactory_iface
, iid
, out
);
473 static BOOL CALLBACK
init_gstreamer_proc(INIT_ONCE
*once
, void *param
, void **ctx
)
477 /* Unloading glib is a bad idea.. it installs atexit handlers,
478 * so never unload the dll after loading */
479 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_PIN
,
480 (LPCWSTR
)init_gstreamer_proc
, &handle
);
482 ERR("Failed to pin module.\n");
487 BOOL
init_gstreamer(void)
489 static INIT_ONCE once
= INIT_ONCE_STATIC_INIT
;
491 InitOnceExecuteOnce(&once
, init_gstreamer_proc
, NULL
, NULL
);
496 static const REGPINTYPES reg_audio_mt
= {&MEDIATYPE_Audio
, &GUID_NULL
};
497 static const REGPINTYPES reg_stream_mt
= {&MEDIATYPE_Stream
, &GUID_NULL
};
498 static const REGPINTYPES reg_video_mt
= {&MEDIATYPE_Video
, &GUID_NULL
};
500 static const REGPINTYPES reg_avi_splitter_sink_mt
= {&MEDIATYPE_Stream
, &MEDIASUBTYPE_Avi
};
502 static const REGFILTERPINS2 reg_avi_splitter_pins
[2] =
506 .lpMediaType
= ®_avi_splitter_sink_mt
,
509 .dwFlags
= REG_PINFLAG_B_OUTPUT
,
511 .lpMediaType
= ®_video_mt
,
515 static const REGFILTER2 reg_avi_splitter
=
518 .dwMerit
= MERIT_NORMAL
,
520 .u
.s2
.rgPins2
= reg_avi_splitter_pins
,
523 static const REGPINTYPES reg_mpeg_audio_codec_sink_mts
[3] =
525 {&MEDIATYPE_Audio
, &MEDIASUBTYPE_MPEG1Packet
},
526 {&MEDIATYPE_Audio
, &MEDIASUBTYPE_MPEG1Payload
},
527 {&MEDIATYPE_Audio
, &MEDIASUBTYPE_MPEG1AudioPayload
},
530 static const REGPINTYPES reg_mpeg_audio_codec_source_mts
[1] =
532 {&MEDIATYPE_Audio
, &MEDIASUBTYPE_PCM
},
535 static const REGFILTERPINS2 reg_mpeg_audio_codec_pins
[2] =
539 .lpMediaType
= reg_mpeg_audio_codec_sink_mts
,
542 .dwFlags
= REG_PINFLAG_B_OUTPUT
,
544 .lpMediaType
= reg_mpeg_audio_codec_source_mts
,
548 static const REGFILTER2 reg_mpeg_audio_codec
=
551 .dwMerit
= 0x03680001,
553 .u
.s2
.rgPins2
= reg_mpeg_audio_codec_pins
,
556 static const REGPINTYPES reg_mpeg_splitter_sink_mts
[4] =
558 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_MPEG1Audio
},
559 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_MPEG1Video
},
560 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_MPEG1System
},
561 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_MPEG1VideoCD
},
564 static const REGPINTYPES reg_mpeg_splitter_audio_mts
[2] =
566 {&MEDIATYPE_Audio
, &MEDIASUBTYPE_MPEG1Packet
},
567 {&MEDIATYPE_Audio
, &MEDIASUBTYPE_MPEG1AudioPayload
},
570 static const REGPINTYPES reg_mpeg_splitter_video_mts
[2] =
572 {&MEDIATYPE_Video
, &MEDIASUBTYPE_MPEG1Packet
},
573 {&MEDIATYPE_Video
, &MEDIASUBTYPE_MPEG1Payload
},
576 static const REGFILTERPINS2 reg_mpeg_splitter_pins
[3] =
580 .lpMediaType
= reg_mpeg_splitter_sink_mts
,
583 .dwFlags
= REG_PINFLAG_B_ZERO
| REG_PINFLAG_B_OUTPUT
,
585 .lpMediaType
= reg_mpeg_splitter_audio_mts
,
588 .dwFlags
= REG_PINFLAG_B_ZERO
| REG_PINFLAG_B_OUTPUT
,
590 .lpMediaType
= reg_mpeg_splitter_video_mts
,
594 static const REGFILTER2 reg_mpeg_splitter
=
597 .dwMerit
= MERIT_NORMAL
,
599 .u
.s2
.rgPins2
= reg_mpeg_splitter_pins
,
602 static const REGPINTYPES reg_wave_parser_sink_mts
[3] =
604 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_WAVE
},
605 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_AU
},
606 {&MEDIATYPE_Stream
, &MEDIASUBTYPE_AIFF
},
609 static const REGFILTERPINS2 reg_wave_parser_pins
[2] =
613 .lpMediaType
= reg_wave_parser_sink_mts
,
616 .dwFlags
= REG_PINFLAG_B_OUTPUT
,
618 .lpMediaType
= ®_audio_mt
,
622 static const REGFILTER2 reg_wave_parser
=
625 .dwMerit
= MERIT_UNLIKELY
,
627 .u
.s2
.rgPins2
= reg_wave_parser_pins
,
630 static const REGFILTERPINS2 reg_decodebin_parser_pins
[3] =
634 .lpMediaType
= ®_stream_mt
,
637 .dwFlags
= REG_PINFLAG_B_OUTPUT
,
639 .lpMediaType
= ®_audio_mt
,
642 .dwFlags
= REG_PINFLAG_B_OUTPUT
,
644 .lpMediaType
= ®_video_mt
,
648 static const REGFILTER2 reg_decodebin_parser
=
651 .dwMerit
= MERIT_PREFERRED
,
653 .u
.s2
.rgPins2
= reg_decodebin_parser_pins
,
656 HRESULT WINAPI
DllRegisterServer(void)
658 DMO_PARTIAL_MEDIATYPE wma_decoder_output
[2] =
660 {.type
= MEDIATYPE_Audio
, .subtype
= MEDIASUBTYPE_PCM
},
661 {.type
= MEDIATYPE_Audio
, .subtype
= MEDIASUBTYPE_IEEE_FLOAT
},
663 DMO_PARTIAL_MEDIATYPE wma_decoder_input
[4] =
665 {.type
= MEDIATYPE_Audio
, .subtype
= MEDIASUBTYPE_MSAUDIO1
},
666 {.type
= MEDIATYPE_Audio
, .subtype
= MEDIASUBTYPE_WMAUDIO2
},
667 {.type
= MEDIATYPE_Audio
, .subtype
= MEDIASUBTYPE_WMAUDIO3
},
668 {.type
= MEDIATYPE_Audio
, .subtype
= MEDIASUBTYPE_WMAUDIO_LOSSLESS
},
671 IFilterMapper2
*mapper
;
676 if (FAILED(hr
= __wine_register_resources()))
679 if (FAILED(hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
680 &IID_IFilterMapper2
, (void **)&mapper
)))
683 IFilterMapper2_RegisterFilter(mapper
, &CLSID_AviSplitter
, L
"AVI Splitter", NULL
, NULL
, NULL
, ®_avi_splitter
);
684 IFilterMapper2_RegisterFilter(mapper
, &CLSID_decodebin_parser
,
685 L
"GStreamer splitter filter", NULL
, NULL
, NULL
, ®_decodebin_parser
);
686 IFilterMapper2_RegisterFilter(mapper
, &CLSID_CMpegAudioCodec
,
687 L
"MPEG Audio Decoder", NULL
, NULL
, NULL
, ®_mpeg_audio_codec
);
688 IFilterMapper2_RegisterFilter(mapper
, &CLSID_MPEG1Splitter
,
689 L
"MPEG-I Stream Splitter", NULL
, NULL
, NULL
, ®_mpeg_splitter
);
690 IFilterMapper2_RegisterFilter(mapper
, &CLSID_WAVEParser
, L
"Wave Parser", NULL
, NULL
, NULL
, ®_wave_parser
);
692 IFilterMapper2_Release(mapper
);
694 if (FAILED(hr
= DMORegister(L
"WMA Decoder DMO", &CLSID_WMADecMediaObject
, &DMOCATEGORY_AUDIO_DECODER
,
695 0, ARRAY_SIZE(wma_decoder_input
), wma_decoder_input
, ARRAY_SIZE(wma_decoder_output
), wma_decoder_output
)))
698 return mfplat_DllRegisterServer();
701 HRESULT WINAPI
DllUnregisterServer(void)
703 IFilterMapper2
*mapper
;
708 if (FAILED(hr
= __wine_unregister_resources()))
711 if (FAILED(hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
712 &IID_IFilterMapper2
, (void **)&mapper
)))
715 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &CLSID_AviSplitter
);
716 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &CLSID_decodebin_parser
);
717 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &CLSID_CMpegAudioCodec
);
718 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &CLSID_MPEG1Splitter
);
719 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &CLSID_WAVEParser
);
721 IFilterMapper2_Release(mapper
);
723 if (FAILED(hr
= DMOUnregister(&CLSID_WMADecMediaObject
, &DMOCATEGORY_AUDIO_DECODER
)))