From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- include/Makefile.in | 1 + include/mmreg.h | 12 ++++++++ include/mpegtype.idl | 69 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 include/mpegtype.idl
diff --git a/include/Makefile.in b/include/Makefile.in index f3e62c4bb5a..14c4caeb688 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -435,6 +435,7 @@ SOURCES = \ mmreg.h \ mmstream.idl \ mmsystem.h \ + mpegtype.idl \ mprapi.h \ mprerror.h \ msacm.h \ diff --git a/include/mmreg.h b/include/mmreg.h index bcee2a5ec61..1b19e1f068f 100644 --- a/include/mmreg.h +++ b/include/mmreg.h @@ -836,6 +836,18 @@ typedef struct { GUID SubFormat; } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
+typedef struct { + WAVEFORMATEX wfx; + WORD fwHeadLayer; + DWORD dwHeadBitrate; + WORD fwHeadMode; + WORD fwHeadModeExt; + WORD wHeadEmphasis; + WORD fwHeadFlags; + DWORD dwPTSLow; + DWORD dwPTSHigh; +} MPEG1WAVEFORMAT; + #pragma pack(pop) cpp_quote("#endif")
diff --git a/include/mpegtype.idl b/include/mpegtype.idl new file mode 100644 index 00000000000..5f26283640c --- /dev/null +++ b/include/mpegtype.idl @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 Anton Baskanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +import "unknwn.idl"; + +cpp_quote("#include <mmreg.h>") +#include <mmreg.h> + +[ + object, + /* uuid(b45dd570-3c77-11d1-abe1-00a0c905f375) conflicts with uuids.h */ + pointer_default(unique) +] +interface IMpegAudioDecoder : IUnknown +{ + HRESULT get_AudioFormat( + MPEG1WAVEFORMAT *format); + + HRESULT get_DecoderAccuracy( + unsigned long *accuracy); + + HRESULT get_DecoderWordSize( + unsigned long *word_size); + + HRESULT get_DualMode( + unsigned long *dual_mode); + + HRESULT get_FrequencyDivider( + unsigned long *divider); + + HRESULT get_IntegerDecode( + unsigned long *integer_decode); + + HRESULT get_Stereo( + unsigned long *stereo); + + HRESULT put_DecoderAccuracy( + unsigned long accuracy); + + HRESULT put_DecoderWordSize( + unsigned long word_size); + + HRESULT put_DualMode( + unsigned long dual_mode); + + HRESULT put_FrequencyDivider( + unsigned long divider); + + HRESULT put_IntegerDecode( + unsigned long integer_decode); + + HRESULT put_Stereo( + unsigned long stereo); +}
From: Anton Baskanov baskanov@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50462 Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpegaudio.c | 1 + dlls/winegstreamer/quartz_transform.c | 140 ++++++++++++++++++++++++++ 2 files changed, 141 insertions(+)
diff --git a/dlls/quartz/tests/mpegaudio.c b/dlls/quartz/tests/mpegaudio.c index 105469edaf1..99d078f9835 100644 --- a/dlls/quartz/tests/mpegaudio.c +++ b/dlls/quartz/tests/mpegaudio.c @@ -221,6 +221,7 @@ static void test_interfaces(void)
check_interface(filter, &IID_IBaseFilter, TRUE); check_interface(filter, &IID_IMediaFilter, TRUE); + check_interface(filter, &IID_IMpegAudioDecoder, TRUE); check_interface(filter, &IID_IPersist, TRUE); check_interface(filter, &IID_IUnknown, TRUE);
diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 5019cc6032b..85fbcee8bcd 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -21,6 +21,7 @@ #include "gst_private.h"
#include "mferror.h" +#include "mpegtype.h"
WINE_DEFAULT_DEBUG_CHANNEL(quartz); WINE_DECLARE_DEBUG_CHANNEL(winediag); @@ -28,6 +29,7 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag); struct transform { struct strmbase_filter filter; + IMpegAudioDecoder IMpegAudioDecoder_iface;
struct strmbase_sink sink; struct strmbase_source source; @@ -71,6 +73,19 @@ static void transform_destroy(struct strmbase_filter *iface) free(filter); }
+static HRESULT transform_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) +{ + struct transform *filter = impl_from_strmbase_filter(iface); + + if (IsEqualGUID(iid, &IID_IMpegAudioDecoder) && filter->IMpegAudioDecoder_iface.lpVtbl) + *out = &filter->IMpegAudioDecoder_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + static HRESULT transform_init_stream(struct strmbase_filter *iface) { struct transform *filter = impl_from_strmbase_filter(iface); @@ -115,10 +130,133 @@ static const struct strmbase_filter_ops filter_ops = { .filter_get_pin = transform_get_pin, .filter_destroy = transform_destroy, + .filter_query_interface = transform_query_interface, .filter_init_stream = transform_init_stream, .filter_cleanup_stream = transform_cleanup_stream, };
+static struct transform *impl_from_IMpegAudioDecoder(IMpegAudioDecoder *iface) +{ + return CONTAINING_RECORD(iface, struct transform, IMpegAudioDecoder_iface); +} + +static HRESULT WINAPI mpeg_audio_decoder_QueryInterface(IMpegAudioDecoder *iface, + REFIID iid, void **out) +{ + struct transform *filter = impl_from_IMpegAudioDecoder(iface); + return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out); +} + +static ULONG WINAPI mpeg_audio_decoder_AddRef(IMpegAudioDecoder *iface) +{ + struct transform *filter = impl_from_IMpegAudioDecoder(iface); + return IUnknown_AddRef(filter->filter.outer_unk); +} + +static ULONG WINAPI mpeg_audio_decoder_Release(IMpegAudioDecoder *iface) +{ + struct transform *filter = impl_from_IMpegAudioDecoder(iface); + return IUnknown_Release(filter->filter.outer_unk); +} + +static HRESULT WINAPI mpeg_audio_decoder_get_AudioFormat(IMpegAudioDecoder *iface, MPEG1WAVEFORMAT *format) +{ + FIXME("iface %p, format %p, stub!\n", iface, format); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_get_DecoderAccuracy(IMpegAudioDecoder *iface, ULONG *accuracy) +{ + FIXME("iface %p, accuracy %p, stub!\n", iface, accuracy); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_get_DecoderWordSize(IMpegAudioDecoder *iface, ULONG *word_size) +{ + FIXME("iface %p, word_size %p, stub!\n", iface, word_size); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_get_DualMode(IMpegAudioDecoder *iface, ULONG *dual_mode) +{ + FIXME("iface %p, dual_mode %p, stub!\n", iface, dual_mode); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_get_FrequencyDivider(IMpegAudioDecoder *iface, ULONG *divider) +{ + FIXME("iface %p, divider %p, stub!\n", iface, divider); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_get_IntegerDecode(IMpegAudioDecoder *iface, ULONG *integer_decode) +{ + FIXME("iface %p, integer_decode %p, stub!\n", iface, integer_decode); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_get_Stereo(IMpegAudioDecoder *iface, ULONG *stereo) +{ + FIXME("iface %p, stereo %p, stub!\n", iface, stereo); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_put_DecoderAccuracy(IMpegAudioDecoder *iface, ULONG accuracy) +{ + FIXME("iface %p, accuracy %lu, stub!\n", iface, accuracy); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_put_DecoderWordSize(IMpegAudioDecoder *iface, ULONG word_size) +{ + FIXME("iface %p, word_size %lu, stub!\n", iface, word_size); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_put_DualMode(IMpegAudioDecoder *iface, ULONG dual_mode) +{ + FIXME("iface %p, dual_mode %lu, stub!\n", iface, dual_mode); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_put_FrequencyDivider(IMpegAudioDecoder *iface, ULONG divider) +{ + FIXME("iface %p, divider %lu, stub!\n", iface, divider); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_put_IntegerDecode(IMpegAudioDecoder *iface, ULONG integer_decode) +{ + FIXME("iface %p, integer_decode %lu, stub!\n", iface, integer_decode); + return E_NOTIMPL; +} + +static HRESULT WINAPI mpeg_audio_decoder_put_Stereo(IMpegAudioDecoder *iface, ULONG stereo) +{ + FIXME("iface %p, stereo %lu, stub!\n", iface, stereo); + return E_NOTIMPL; +} + +static const IMpegAudioDecoderVtbl mpeg_audio_decoder_vtbl = +{ + mpeg_audio_decoder_QueryInterface, + mpeg_audio_decoder_AddRef, + mpeg_audio_decoder_Release, + mpeg_audio_decoder_get_AudioFormat, + mpeg_audio_decoder_get_DecoderAccuracy, + mpeg_audio_decoder_get_DecoderWordSize, + mpeg_audio_decoder_get_DualMode, + mpeg_audio_decoder_get_FrequencyDivider, + mpeg_audio_decoder_get_IntegerDecode, + mpeg_audio_decoder_get_Stereo, + mpeg_audio_decoder_put_DecoderAccuracy, + mpeg_audio_decoder_put_DecoderWordSize, + mpeg_audio_decoder_put_DualMode, + mpeg_audio_decoder_put_FrequencyDivider, + mpeg_audio_decoder_put_IntegerDecode, + mpeg_audio_decoder_put_Stereo, +}; + static HRESULT transform_sink_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt) { struct transform *filter = impl_from_strmbase_filter(pin->filter); @@ -440,6 +578,8 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) wcscpy(object->sink.pin.name, L"XForm In"); wcscpy(object->source.pin.name, L"XForm Out");
+ object->IMpegAudioDecoder_iface.lpVtbl = &mpeg_audio_decoder_vtbl; + TRACE("Created MPEG audio decoder %p.\n", object); *out = &object->filter.IUnknown_inner; return hr;
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/winegstreamer/main.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index a408704cf47..c3adbb82d61 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -520,6 +520,39 @@ static const REGFILTER2 reg_avi_splitter = .u.s2.rgPins2 = reg_avi_splitter_pins, };
+static const REGPINTYPES reg_mpeg_audio_codec_sink_mts[3] = +{ + {&MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Packet}, + {&MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Payload}, + {&MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload}, +}; + +static const REGPINTYPES reg_mpeg_audio_codec_source_mts[1] = +{ + {&MEDIATYPE_Audio, &MEDIASUBTYPE_PCM}, +}; + +static const REGFILTERPINS2 reg_mpeg_audio_codec_pins[2] = +{ + { + .nMediaTypes = 3, + .lpMediaType = reg_mpeg_audio_codec_sink_mts, + }, + { + .dwFlags = REG_PINFLAG_B_OUTPUT, + .nMediaTypes = 1, + .lpMediaType = reg_mpeg_audio_codec_source_mts, + }, +}; + +static const REGFILTER2 reg_mpeg_audio_codec = +{ + .dwVersion = 2, + .dwMerit = 0x03680001, + .u.s2.cPins2 = 2, + .u.s2.rgPins2 = reg_mpeg_audio_codec_pins, +}; + static const REGPINTYPES reg_mpeg_splitter_sink_mts[4] = { {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Audio}, @@ -650,6 +683,8 @@ HRESULT WINAPI DllRegisterServer(void) IFilterMapper2_RegisterFilter(mapper, &CLSID_AviSplitter, L"AVI Splitter", NULL, NULL, NULL, ®_avi_splitter); IFilterMapper2_RegisterFilter(mapper, &CLSID_decodebin_parser, L"GStreamer splitter filter", NULL, NULL, NULL, ®_decodebin_parser); + IFilterMapper2_RegisterFilter(mapper, &CLSID_CMpegAudioCodec, + L"MPEG Audio Decoder", NULL, NULL, NULL, ®_mpeg_audio_codec); IFilterMapper2_RegisterFilter(mapper, &CLSID_MPEG1Splitter, L"MPEG-I Stream Splitter", NULL, NULL, NULL, ®_mpeg_splitter); IFilterMapper2_RegisterFilter(mapper, &CLSID_WAVEParser, L"Wave Parser", NULL, NULL, NULL, ®_wave_parser); @@ -679,6 +714,7 @@ HRESULT WINAPI DllUnregisterServer(void)
IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_AviSplitter); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_decodebin_parser); + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_CMpegAudioCodec); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_MPEG1Splitter); IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_WAVEParser);
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpegaudio.c | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/dlls/quartz/tests/mpegaudio.c b/dlls/quartz/tests/mpegaudio.c index 99d078f9835..5fdf443f3c8 100644 --- a/dlls/quartz/tests/mpegaudio.c +++ b/dlls/quartz/tests/mpegaudio.c @@ -796,6 +796,8 @@ struct testfilter struct strmbase_sink sink; const AM_MEDIA_TYPE *mt; unsigned int got_sample; + REFERENCE_TIME expected_start_time; + REFERENCE_TIME expected_stop_time; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -872,6 +874,8 @@ static HRESULT testsink_connect(struct strmbase_sink *iface, IPin *peer, const A static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + REFERENCE_TIME start, stop; + HRESULT hr; LONG size;
++filter->got_sample; @@ -881,6 +885,16 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample size = IMediaSample_GetActualDataLength(sample); ok(size == 768, "Got valid size %lu.\n", size);
+ start = 0xdeadbeef; + stop = 0xdeadbeef; + hr = IMediaSample_GetTime(sample, &start, &stop); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (filter->got_sample == 1) + { + todo_wine ok(start == filter->expected_start_time, "Got start time %s.\n", wine_dbgstr_longlong(start)); + todo_wine ok(stop == filter->expected_stop_time, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + } + return S_OK; }
@@ -1060,6 +1074,7 @@ static void test_source_allocator(IFilterGraph2 *graph, IMediaControl *control,
static void test_sample_processing(IMediaControl *control, IMemInputPin *input, struct testfilter *sink) { + REFERENCE_TIME start, stop; IMemAllocator *allocator; IMediaSample *sample; HRESULT hr; @@ -1095,6 +1110,52 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input, hr = IMediaSample_SetActualDataLength(sample, 48); ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ hr = IMediaSample_SetTime(sample, NULL, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + sink->expected_start_time = 0; + sink->expected_stop_time = 120000; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(sink->got_sample >= 1, "Got %u calls to Receive().\n", sink->got_sample); + sink->got_sample = 0; + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + start = 22222; + hr = IMediaSample_SetTime(sample, &start, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + sink->expected_start_time = 22222; + sink->expected_stop_time = 142222; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(sink->got_sample >= 1, "Got %u calls to Receive().\n", sink->got_sample); + sink->got_sample = 0; + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + start = 22222; + stop = 33333; + hr = IMediaSample_SetTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + sink->expected_start_time = 22222; + sink->expected_stop_time = 142222; hr = IMemInputPin_Receive(input, sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IMemInputPin_Receive(input, sample);
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpegaudio.c | 6 +++--- dlls/winegstreamer/quartz_transform.c | 28 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/dlls/quartz/tests/mpegaudio.c b/dlls/quartz/tests/mpegaudio.c index 5fdf443f3c8..75b85ee8716 100644 --- a/dlls/quartz/tests/mpegaudio.c +++ b/dlls/quartz/tests/mpegaudio.c @@ -888,11 +888,11 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample start = 0xdeadbeef; stop = 0xdeadbeef; hr = IMediaSample_GetTime(sample, &start, &stop); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(hr == S_OK, "Got hr %#lx.\n", hr); if (filter->got_sample == 1) { - todo_wine ok(start == filter->expected_start_time, "Got start time %s.\n", wine_dbgstr_longlong(start)); - todo_wine ok(stop == filter->expected_stop_time, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + ok(start == filter->expected_start_time, "Got start time %s.\n", wine_dbgstr_longlong(start)); + ok(stop == filter->expected_stop_time, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); }
return S_OK; diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 85fbcee8bcd..b556b49c771 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -281,6 +281,8 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa { struct transform *filter = impl_from_strmbase_filter(pin->pin.filter); struct wg_sample input_wg_sample = {0}; + REFERENCE_TIME start_time; + REFERENCE_TIME end_time; HRESULT hr;
/* We do not expect pin connection state to change while the filter is @@ -306,6 +308,18 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa if (FAILED(hr)) return hr;
+ hr = IMediaSample_GetTime(sample, &start_time, &end_time); + if (SUCCEEDED(hr)) + { + input_wg_sample.pts = start_time; + input_wg_sample.flags |= WG_SAMPLE_FLAG_HAS_PTS; + } + if (hr == S_OK) + { + input_wg_sample.duration = end_time - start_time; + input_wg_sample.flags |= WG_SAMPLE_FLAG_HAS_DURATION; + } + hr = wg_transform_push_data(filter->transform, &input_wg_sample); if (FAILED(hr)) return hr; @@ -347,6 +361,20 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa return hr; }
+ if (output_wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) + { + start_time = output_wg_sample.pts; + if (output_wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) + { + end_time = start_time + output_wg_sample.duration; + IMediaSample_SetTime(output_sample, &start_time, &end_time); + } + else + { + IMediaSample_SetTime(output_sample, &start_time, NULL); + } + } + hr = IMemInputPin_Receive(filter->source.pMemInputPin, output_sample); if (FAILED(hr)) {
Chip Davis (@cdavis5e) commented about include/mpegtype.idl:
- HRESULT put_DecoderWordSize(
unsigned long word_size);
- HRESULT put_DualMode(
unsigned long dual_mode);
- HRESULT put_FrequencyDivider(
unsigned long divider);
- HRESULT put_IntegerDecode(
unsigned long integer_decode);
- HRESULT put_Stereo(
unsigned long stereo);
+}
At least in the Windows 7 SDK, these methods are in a completely different order. Unlike with free functions, order is significant here, because it determines how the v-table is physically laid out.
So something like this: ```suggestion:-40+0 interface IMpegAudioDecoder : IUnknown { [propget] HRESULT FrequencyDivider( [out, retval] unsigned long *divider);
[propput] HRESULT FrequencyDivider( unsigned long divider);
[propget] HRESULT DecoderAccuracy( [out, retval] unsigned long *accuracy);
[propput] HRESULT DecoderAccuracy( unsigned long accuracy);
[propget] HRESULT Stereo( [out, retval] unsigned long *stereo);
[propput] HRESULT Stereo( unsigned long stereo);
[propget] HRESULT DecoderWordSize( [out, retval] unsigned long *word_size);
[propput] HRESULT DecoderWordSize( unsigned long word_size);
[propget] HRESULT IntegerDecode( [out, retval] unsigned long *integer_decode);
[propput] HRESULT IntegerDecode( unsigned long integer_decode);
[propget] HRESULT DualMode( [out, retval] unsigned long *dual_mode);
[propput] HRESULT DualMode( unsigned long dual_mode);
[propget] HRESULT AudioFormat( [out, retval] MPEG1WAVEFORMAT *format); } ```