1 #ifdef WINRT
2 #define ICustomStreamSink StreamSink
3 #ifndef __cplusplus_winrt
4 
5 #define __is_winrt_array(type) (type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt8Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int16Array ||\
6     type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt16Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int32Array ||\
7     type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt32Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int64Array ||\
8     type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt64Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_SingleArray ||\
9     type == ABI::Windows::Foundation::PropertyType::PropertyType_DoubleArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_Char16Array ||\
10     type == ABI::Windows::Foundation::PropertyType::PropertyType_BooleanArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_StringArray ||\
11     type == ABI::Windows::Foundation::PropertyType::PropertyType_InspectableArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_DateTimeArray ||\
12     type == ABI::Windows::Foundation::PropertyType::PropertyType_TimeSpanArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_GuidArray ||\
13     type == ABI::Windows::Foundation::PropertyType::PropertyType_PointArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_SizeArray ||\
14     type == ABI::Windows::Foundation::PropertyType::PropertyType_RectArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_OtherTypeArray)
15 
16 template<typename _Type, bool bUnknown = std::is_base_of<IUnknown, _Type>::value>
17 struct winrt_type
18 {
19 };
20 template<typename _Type>
21 struct winrt_type<_Type, true>
22 {
createwinrt_type23     static IUnknown* create(_Type* _ObjInCtx) {
24         return reinterpret_cast<IUnknown*>(_ObjInCtx);
25     }
getuuidwinrt_type26     static IID getuuid() { return __uuidof(_Type); }
27     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherType;
28 };
29 template <typename _Type>
30 struct winrt_type<_Type, false>
31 {
createwinrt_type32     static IUnknown* create(_Type* _ObjInCtx) {
33         Microsoft::WRL::ComPtr<IInspectable> _PObj;
34         Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
35         HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
36         if (FAILED(hr)) return nullptr;
37         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
38         if (SUCCEEDED(hr))
39             hr = objFactory.As(&spPropVal);
40         if (SUCCEEDED(hr)) {
41             hr = winrt_type<_Type>::create(spPropVal.Get(), _ObjInCtx, _PObj.GetAddressOf());
42             if (SUCCEEDED(hr))
43                 return reinterpret_cast<IUnknown*>(_PObj.Detach());
44         }
45         return nullptr;
46     }
getuuidwinrt_type47     static IID getuuid() { return __uuidof(ABI::Windows::Foundation::IPropertyValue); }
48     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherType;
49 };
50 
51 template<>
52 struct winrt_type<void>
53 {
createwinrt_type54     static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, void* _ObjInCtx, IInspectable** ppInsp) {
55         (void)_ObjInCtx;
56         return spPropVal->CreateEmpty(ppInsp);
57     }
58     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
59 };
60 #define MAKE_TYPE(Type, Name) template<>\
61 struct winrt_type<Type>\
62 {\
63     static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, Type* _ObjInCtx, IInspectable** ppInsp) {\
64     return spPropVal->Create##Name(*_ObjInCtx, ppInsp);\
65 }\
66     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_##Name;\
67 };
68 
69 template<typename _Type>
70 struct winrt_array_type
71 {
createwinrt_array_type72     static IUnknown* create(_Type* _ObjInCtx, size_t N) {
73         Microsoft::WRL::ComPtr<IInspectable> _PObj;
74         Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
75         HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
76         if (FAILED(hr)) return nullptr;
77         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
78         if (SUCCEEDED(hr))
79             hr = objFactory.As(&spPropVal);
80         if (SUCCEEDED(hr)) {
81             hr = winrt_array_type<_Type>::create(spPropVal.Get(), N, _ObjInCtx, _PObj.GetAddressOf());
82             if (SUCCEEDED(hr))
83                 return reinterpret_cast<IUnknown*>(_PObj.Detach());
84         }
85         return nullptr;
86     }
87     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherTypeArray;
88 };
89 template<int>
90 struct winrt_prop_type {};
91 
92 template <>
93 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_Empty> {
94     typedef void _Type;
95 };
96 
97 template <>
98 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_OtherType> {
99     typedef void _Type;
100 };
101 
102 template <>
103 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_OtherTypeArray> {
104     typedef void _Type;
105 };
106 
107 #define MAKE_PROP(Prop, Type) template <>\
108 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_##Prop> {\
109     typedef Type _Type;\
110 };
111 
112 #define MAKE_ARRAY_TYPE(Type, Name) MAKE_PROP(Name, Type)\
113     MAKE_PROP(Name##Array, Type*)\
114     MAKE_TYPE(Type, Name)\
115     template<>\
116 struct winrt_array_type<Type*>\
117 {\
118     static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, Type** _ObjInCtx, IInspectable** ppInsp) {\
119     return spPropVal->Create##Name##Array(__valueSize, *_ObjInCtx, ppInsp);\
120 }\
121     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_##Name##Array;\
122     static std::vector<Type> PropertyValueToVector(ABI::Windows::Foundation::IPropertyValue* propValue)\
123 {\
124     UINT32 uLen = 0;\
125     Type* pArray = nullptr;\
126     propValue->Get##Name##Array(&uLen, &pArray);\
127     return std::vector<Type>(pArray, pArray + uLen);\
128 }\
129 };
130 MAKE_ARRAY_TYPE(BYTE, UInt8)
131 MAKE_ARRAY_TYPE(INT16, Int16)
132 MAKE_ARRAY_TYPE(UINT16, UInt16)
133 MAKE_ARRAY_TYPE(INT32, Int32)
134 MAKE_ARRAY_TYPE(UINT32, UInt32)
135 MAKE_ARRAY_TYPE(INT64, Int64)
136 MAKE_ARRAY_TYPE(UINT64, UInt64)
137 MAKE_ARRAY_TYPE(FLOAT, Single)
138 MAKE_ARRAY_TYPE(DOUBLE, Double)
139 MAKE_ARRAY_TYPE(WCHAR, Char16)
140 //MAKE_ARRAY_TYPE(boolean, Boolean) //conflict with identical type in C++ of BYTE/UInt8
141 MAKE_ARRAY_TYPE(HSTRING, String)
142 MAKE_ARRAY_TYPE(IInspectable*, Inspectable)
143 MAKE_ARRAY_TYPE(GUID, Guid)
144 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::DateTime, DateTime)
145 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::TimeSpan, TimeSpan)
146 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Point, Point)
147 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Size, Size)
148 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Rect, Rect)
149 
150 template < typename T >
151 struct DerefHelper
152 {
153     typedef T DerefType;
154 };
155 
156 template < typename T >
157 struct DerefHelper<T*>
158 {
159     typedef T DerefType;
160 };
161 
162 #define __is_valid_winrt_type(_Type) (std::is_void<_Type>::value || \
163     std::is_same<_Type, BYTE>::value || \
164     std::is_same<_Type, INT16>::value || \
165     std::is_same<_Type, UINT16>::value || \
166     std::is_same<_Type, INT32>::value || \
167     std::is_same<_Type, UINT32>::value || \
168     std::is_same<_Type, INT64>::value || \
169     std::is_same<_Type, UINT64>::value || \
170     std::is_same<_Type, FLOAT>::value || \
171     std::is_same<_Type, DOUBLE>::value || \
172     std::is_same<_Type, WCHAR>::value || \
173     std::is_same<_Type, boolean>::value || \
174     std::is_same<_Type, HSTRING>::value || \
175     std::is_same<_Type, IInspectable *>::value || \
176     std::is_base_of<Microsoft::WRL::Details::RuntimeClassBase, _Type>::value || \
177     std::is_base_of<IInspectable, typename DerefHelper<_Type>::DerefType>::value || \
178     std::is_same<_Type, GUID>::value || \
179     std::is_same<_Type, ABI::Windows::Foundation::DateTime>::value || \
180     std::is_same<_Type, ABI::Windows::Foundation::TimeSpan>::value || \
181     std::is_same<_Type, ABI::Windows::Foundation::Point>::value || \
182     std::is_same<_Type, ABI::Windows::Foundation::Size>::value || \
183     std::is_same<_Type, ABI::Windows::Foundation::Rect>::value || \
184     std::is_same<_Type, BYTE*>::value || \
185     std::is_same<_Type, INT16*>::value || \
186     std::is_same<_Type, UINT16*>::value || \
187     std::is_same<_Type, INT32*>::value || \
188     std::is_same<_Type, UINT32*>::value || \
189     std::is_same<_Type, INT64*>::value || \
190     std::is_same<_Type, UINT64*>::value || \
191     std::is_same<_Type, FLOAT*>::value || \
192     std::is_same<_Type, DOUBLE*>::value || \
193     std::is_same<_Type, WCHAR*>::value || \
194     std::is_same<_Type, boolean*>::value || \
195     std::is_same<_Type, HSTRING*>::value || \
196     std::is_same<_Type, IInspectable **>::value || \
197     std::is_same<_Type, GUID*>::value || \
198     std::is_same<_Type, ABI::Windows::Foundation::DateTime*>::value || \
199     std::is_same<_Type, ABI::Windows::Foundation::TimeSpan*>::value || \
200     std::is_same<_Type, ABI::Windows::Foundation::Point*>::value || \
201     std::is_same<_Type, ABI::Windows::Foundation::Size*>::value || \
202     std::is_same<_Type, ABI::Windows::Foundation::Rect*>::value)
203 #endif
204 #else
205 EXTERN_C const IID IID_ICustomStreamSink;
206 
207 class DECLSPEC_UUID("4F8A1939-2FD3-46DB-AE70-DB7E0DD79B73") DECLSPEC_NOVTABLE ICustomStreamSink : public IUnknown
208 {
209 public:
210     virtual HRESULT Initialize() = 0;
211     virtual HRESULT Shutdown() = 0;
212     virtual HRESULT Start(MFTIME start) = 0;
213     virtual HRESULT Pause() = 0;
214     virtual HRESULT Restart() = 0;
215     virtual HRESULT Stop() = 0;
216 };
217 #endif
218 
219 #define MF_PROP_SAMPLEGRABBERCALLBACK L"samplegrabbercallback"
220 #define MF_PROP_VIDTYPE L"vidtype"
221 #define MF_PROP_VIDENCPROPS L"videncprops"
222 
223 #include <initguid.h>
224 
225 // MF_MEDIASINK_SAMPLEGRABBERCALLBACK: {26957AA7-AFF4-464c-BB8B-07BA65CE11DF}
226 // Type: IUnknown*
227 DEFINE_GUID(MF_MEDIASINK_SAMPLEGRABBERCALLBACK,
228             0x26957aa7, 0xaff4, 0x464c, 0xbb, 0x8b, 0x7, 0xba, 0x65, 0xce, 0x11, 0xdf);
229 
230 // {4BD133CC-EB9B-496E-8865-0813BFBC6FAA}
231 DEFINE_GUID(MF_STREAMSINK_ID, 0x4bd133cc, 0xeb9b, 0x496e, 0x88, 0x65, 0x8, 0x13, 0xbf, 0xbc, 0x6f, 0xaa);
232 
233 // {C9E22A8C-6A50-4D78-9183-0834A02A3780}
234 DEFINE_GUID(MF_STREAMSINK_MEDIASINKINTERFACE,
235     0xc9e22a8c, 0x6a50, 0x4d78, 0x91, 0x83, 0x8, 0x34, 0xa0, 0x2a, 0x37, 0x80);
236 
237 // {DABD13AB-26B7-47C2-97C1-4B04C187B838}
238 DEFINE_GUID(MF_MEDIASINK_PREFERREDTYPE,
239     0xdabd13ab, 0x26b7, 0x47c2, 0x97, 0xc1, 0x4b, 0x4, 0xc1, 0x87, 0xb8, 0x38);
240 
241 #include <utility>
242 #ifdef _UNICODE
243 #define MAKE_MAP(e) std::map<e, std::wstring>
244 #define MAKE_ENUM(e) std::pair<e, std::wstring>
245 #define MAKE_ENUM_PAIR(e, str) std::pair<e, std::wstring>(str, L#str)
246 #else
247 #define MAKE_MAP(e) std::map<e, std::string>
248 #define MAKE_ENUM(e) std::pair<e, std::string>
249 #define MAKE_ENUM_PAIR(e, str) std::pair<e, std::string>(str, #str)
250 #endif
251 
252 MAKE_ENUM(MediaEventType) MediaEventTypePairs[] = {
253     MAKE_ENUM_PAIR(MediaEventType, MEUnknown),
254     MAKE_ENUM_PAIR(MediaEventType, MEError),
255     MAKE_ENUM_PAIR(MediaEventType, MEExtendedType),
256     MAKE_ENUM_PAIR(MediaEventType, MENonFatalError),
257     MAKE_ENUM_PAIR(MediaEventType, MEGenericV1Anchor),
258     MAKE_ENUM_PAIR(MediaEventType, MESessionUnknown),
259     MAKE_ENUM_PAIR(MediaEventType, MESessionTopologySet),
260     MAKE_ENUM_PAIR(MediaEventType, MESessionTopologiesCleared),
261     MAKE_ENUM_PAIR(MediaEventType, MESessionStarted),
262     MAKE_ENUM_PAIR(MediaEventType, MESessionPaused),
263     MAKE_ENUM_PAIR(MediaEventType, MESessionStopped),
264     MAKE_ENUM_PAIR(MediaEventType, MESessionClosed),
265     MAKE_ENUM_PAIR(MediaEventType, MESessionEnded),
266     MAKE_ENUM_PAIR(MediaEventType, MESessionRateChanged),
267     MAKE_ENUM_PAIR(MediaEventType, MESessionScrubSampleComplete),
268     MAKE_ENUM_PAIR(MediaEventType, MESessionCapabilitiesChanged),
269     MAKE_ENUM_PAIR(MediaEventType, MESessionTopologyStatus),
270     MAKE_ENUM_PAIR(MediaEventType, MESessionNotifyPresentationTime),
271     MAKE_ENUM_PAIR(MediaEventType, MENewPresentation),
272     MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionStart),
273     MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionCompleted),
274     MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationStart),
275     MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationCompleted),
276     MAKE_ENUM_PAIR(MediaEventType, MEEnablerProgress),
277     MAKE_ENUM_PAIR(MediaEventType, MEEnablerCompleted),
278     MAKE_ENUM_PAIR(MediaEventType, MEPolicyError),
279     MAKE_ENUM_PAIR(MediaEventType, MEPolicyReport),
280     MAKE_ENUM_PAIR(MediaEventType, MEBufferingStarted),
281     MAKE_ENUM_PAIR(MediaEventType, MEBufferingStopped),
282     MAKE_ENUM_PAIR(MediaEventType, MEConnectStart),
283     MAKE_ENUM_PAIR(MediaEventType, MEConnectEnd),
284     MAKE_ENUM_PAIR(MediaEventType, MEReconnectStart),
285     MAKE_ENUM_PAIR(MediaEventType, MEReconnectEnd),
286     MAKE_ENUM_PAIR(MediaEventType, MERendererEvent),
287     MAKE_ENUM_PAIR(MediaEventType, MESessionStreamSinkFormatChanged),
288     MAKE_ENUM_PAIR(MediaEventType, MESessionV1Anchor),
289     MAKE_ENUM_PAIR(MediaEventType, MESourceUnknown),
290     MAKE_ENUM_PAIR(MediaEventType, MESourceStarted),
291     MAKE_ENUM_PAIR(MediaEventType, MEStreamStarted),
292     MAKE_ENUM_PAIR(MediaEventType, MESourceSeeked),
293     MAKE_ENUM_PAIR(MediaEventType, MEStreamSeeked),
294     MAKE_ENUM_PAIR(MediaEventType, MENewStream),
295     MAKE_ENUM_PAIR(MediaEventType, MEUpdatedStream),
296     MAKE_ENUM_PAIR(MediaEventType, MESourceStopped),
297     MAKE_ENUM_PAIR(MediaEventType, MEStreamStopped),
298     MAKE_ENUM_PAIR(MediaEventType, MESourcePaused),
299     MAKE_ENUM_PAIR(MediaEventType, MEStreamPaused),
300     MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentation),
301     MAKE_ENUM_PAIR(MediaEventType, MEEndOfStream),
302     MAKE_ENUM_PAIR(MediaEventType, MEMediaSample),
303     MAKE_ENUM_PAIR(MediaEventType, MEStreamTick),
304     MAKE_ENUM_PAIR(MediaEventType, MEStreamThinMode),
305     MAKE_ENUM_PAIR(MediaEventType, MEStreamFormatChanged),
306     MAKE_ENUM_PAIR(MediaEventType, MESourceRateChanged),
307     MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentationSegment),
308     MAKE_ENUM_PAIR(MediaEventType, MESourceCharacteristicsChanged),
309     MAKE_ENUM_PAIR(MediaEventType, MESourceRateChangeRequested),
310     MAKE_ENUM_PAIR(MediaEventType, MESourceMetadataChanged),
311     MAKE_ENUM_PAIR(MediaEventType, MESequencerSourceTopologyUpdated),
312     MAKE_ENUM_PAIR(MediaEventType, MESourceV1Anchor),
313     MAKE_ENUM_PAIR(MediaEventType, MESinkUnknown),
314     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStarted),
315     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStopped),
316     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPaused),
317     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRateChanged),
318     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRequestSample),
319     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkMarker),
320     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPrerolled),
321     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkScrubSampleComplete),
322     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkFormatChanged),
323     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkDeviceChanged),
324     MAKE_ENUM_PAIR(MediaEventType, MEQualityNotify),
325     MAKE_ENUM_PAIR(MediaEventType, MESinkInvalidated),
326     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionNameChanged),
327     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionVolumeChanged),
328     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDeviceRemoved),
329     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionServerShutdown),
330     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionGroupingParamChanged),
331     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionIconChanged),
332     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionFormatChanged),
333     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDisconnected),
334     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionExclusiveModeOverride),
335     MAKE_ENUM_PAIR(MediaEventType, MESinkV1Anchor),
336 #if (WINVER >= 0x0602) // Available since Win 8
337     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionVolumeChanged),
338     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDeviceRemoved),
339     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionFormatChanged),
340     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDisconnected),
341     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionExclusiveModeOverride),
342     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionServerShutdown),
343     MAKE_ENUM_PAIR(MediaEventType, MESinkV2Anchor),
344 #endif
345     MAKE_ENUM_PAIR(MediaEventType, METrustUnknown),
346     MAKE_ENUM_PAIR(MediaEventType, MEPolicyChanged),
347     MAKE_ENUM_PAIR(MediaEventType, MEContentProtectionMessage),
348     MAKE_ENUM_PAIR(MediaEventType, MEPolicySet),
349     MAKE_ENUM_PAIR(MediaEventType, METrustV1Anchor),
350     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupCompleted),
351     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupProgress),
352     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreCompleted),
353     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreProgress),
354     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseAcquisitionCompleted),
355     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationCompleted),
356     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationProgress),
357     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMProximityCompleted),
358     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseStoreCleaned),
359     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMRevocationDownloadCompleted),
360     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMV1Anchor),
361     MAKE_ENUM_PAIR(MediaEventType, METransformUnknown),
362     MAKE_ENUM_PAIR(MediaEventType, METransformNeedInput),
363     MAKE_ENUM_PAIR(MediaEventType, METransformHaveOutput),
364     MAKE_ENUM_PAIR(MediaEventType, METransformDrainComplete),
365     MAKE_ENUM_PAIR(MediaEventType, METransformMarker),
366 #if (WINVER >= 0x0602) // Available since Win 8
367     MAKE_ENUM_PAIR(MediaEventType, MEByteStreamCharacteristicsChanged),
368     MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDeviceRemoved),
369     MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDevicePreempted),
370 #endif
371     MAKE_ENUM_PAIR(MediaEventType, MEReservedMax)
372 };
373 MAKE_MAP(MediaEventType) MediaEventTypeMap(MediaEventTypePairs, MediaEventTypePairs + sizeof(MediaEventTypePairs) / sizeof(MediaEventTypePairs[0]));
374 
375 MAKE_ENUM(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypePairs[] = {
376     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_DEFAULT),
377     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_ENDOFSEGMENT),
378     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_TICK),
379     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_EVENT)
380 };
381 MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypePairs, StreamSinkMarkerTypePairs + sizeof(StreamSinkMarkerTypePairs) / sizeof(StreamSinkMarkerTypePairs[0]));
382 
383 #ifdef WINRT
384 
385 #ifdef __cplusplus_winrt
386 #define _ContextCallback Concurrency::details::_ContextCallback
387 #define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = S_OK;\
388     var._CallInContext([__VA_ARGS__]() {
389 #define END_CALL_IN_CONTEXT(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\
390 });
391 #define END_CALL_IN_CONTEXT_BASE });
392 #else
393 #define _ContextCallback Concurrency_winrt::details::_ContextCallback
394 #define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = var._CallInContext([__VA_ARGS__]() -> HRESULT {
395 #define END_CALL_IN_CONTEXT(hr) return hr;\
396 });
397 #define END_CALL_IN_CONTEXT_BASE return S_OK;\
398 });
399 #endif
400 #define GET_CURRENT_CONTEXT _ContextCallback::_CaptureCurrent()
401 #define SAVE_CURRENT_CONTEXT(var) _ContextCallback var = GET_CURRENT_CONTEXT
402 
403 #define COMMA ,
404 
405 #ifdef __cplusplus_winrt
406 #define _Object Platform::Object^
407 #define _ObjectObj Platform::Object^
408 #define _String Platform::String^
409 #define _StringObj Platform::String^
410 #define _StringReference ref new Platform::String
411 #define _StringReferenceObj Platform::String^
412 #define _DeviceInformationCollection Windows::Devices::Enumeration::DeviceInformationCollection
413 #define _MediaCapture Windows::Media::Capture::MediaCapture
414 #define _MediaCaptureVideoPreview Windows::Media::Capture::MediaCapture
415 #define _MediaCaptureInitializationSettings Windows::Media::Capture::MediaCaptureInitializationSettings
416 #define _VideoDeviceController Windows::Media::Devices::VideoDeviceController
417 #define _MediaDeviceController Windows::Media::Devices::VideoDeviceController
418 #define _MediaEncodingProperties Windows::Media::MediaProperties::IMediaEncodingProperties
419 #define _VideoEncodingProperties Windows::Media::MediaProperties::VideoEncodingProperties
420 #define _MediaStreamType Windows::Media::Capture::MediaStreamType
421 #define _AsyncInfo Windows::Foundation::IAsyncInfo
422 #define _AsyncAction Windows::Foundation::IAsyncAction
423 #define _AsyncOperation Windows::Foundation::IAsyncOperation
424 #define _DeviceClass Windows::Devices::Enumeration::DeviceClass
425 #define _IDeviceInformation Windows::Devices::Enumeration::DeviceInformation
426 #define _DeviceInformation Windows::Devices::Enumeration::DeviceInformation
427 #define _DeviceInformationStatics Windows::Devices::Enumeration::DeviceInformation
428 #define _MediaEncodingProfile Windows::Media::MediaProperties::MediaEncodingProfile
429 #define _StreamingCaptureMode Windows::Media::Capture::StreamingCaptureMode
430 #define _PropertySet Windows::Foundation::Collections::PropertySet
431 #define _Map Windows::Foundation::Collections::PropertySet
432 #define _PropertyValueStatics Windows::Foundation::PropertyValue
433 #define _VectorView Windows::Foundation::Collections::IVectorView
434 #define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkAsync
435 #define _InitializeWithSettingsAsync InitializeAsync
436 #define _FindAllAsyncDeviceClass FindAllAsync
437 #define _MediaExtension Windows::Media::IMediaExtension
438 #define BEGIN_CREATE_ASYNC(type, ...) (Concurrency::create_async([__VA_ARGS__]() {
439 #define END_CREATE_ASYNC(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\
440 }))
441 #define DEFINE_TASK Concurrency::task
442 #define CREATE_TASK Concurrency::create_task
443 #define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency::task<rettype>()) ? Concurrency::create_task(func) : _task.then([func](rettype) -> rettype { return func(); });
444 #define DEFINE_RET_VAL(x)
445 #define DEFINE_RET_TYPE(x)
446 #define DEFINE_RET_FORMAL(x) x
447 #define RET_VAL(x) return x;
448 #define RET_VAL_BASE
449 #define MAKE_STRING(str) str
450 #define GET_STL_STRING(str) std::wstring(str->Data())
451 #define GET_STL_STRING_RAW(str) std::wstring(str->Data())
452 #define MAKE_WRL_OBJ(x) x^
453 #define MAKE_WRL_REF(x) x^
454 #define MAKE_OBJ_REF(x) x^
455 #define MAKE_WRL_AGILE_REF(x) Platform::Agile<x^>
456 #define MAKE_PROPERTY_BACKING(Type, PropName) property Type PropName;
457 #define MAKE_PROPERTY(Type, PropName, PropValue)
458 #define MAKE_PROPERTY_STRING(Type, PropName, PropValue)
459 #define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) property Type PropName\
460 {\
461     Type get() { return PropValue; }\
462 }
463 #define THROW_INVALID_ARG throw ref new Platform::InvalidArgumentException();
464 #define RELEASE_AGILE_WRL(x) x = nullptr;
465 #define RELEASE_WRL(x) x = nullptr;
466 #define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) objtype^ obj = orig;\
467 hr = S_OK;
468 #define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) objtype^ obj = safe_cast<objtype^>(orig);\
469 hr = S_OK;
470 #define WRL_ENUM_GET(obj, prefix, prop) obj::##prop
471 #define WRL_PROP_GET(obj, prop, arg, hr) arg = obj->##prop;\
472 hr = S_OK;
473 #define WRL_PROP_PUT(obj, prop, arg, hr) obj->##prop = arg;\
474 hr = S_OK;
475 #define WRL_METHOD_BASE(obj, method, ret, hr) ret = obj->##method();\
476 hr = S_OK;
477 #define WRL_METHOD(obj, method, ret, hr, ...) ret = obj->##method(__VA_ARGS__);\
478 hr = S_OK;
479 #define WRL_METHOD_NORET_BASE(obj, method, hr) obj->##method();\
480     hr = S_OK;
481 #define WRL_METHOD_NORET(obj, method, hr, ...) obj->##method(__VA_ARGS__);\
482     hr = S_OK;
483 #define REF_WRL_OBJ(obj) &obj
484 #define DEREF_WRL_OBJ(obj) obj
485 #define DEREF_AGILE_WRL_OBJ(obj) obj.Get()
486 #define DEREF_AS_NATIVE_WRL_OBJ(type, obj) reinterpret_cast<type*>(obj)
487 #define PREPARE_TRANSFER_WRL_OBJ(obj) obj
488 #define ACTIVATE_LOCAL_OBJ_BASE(objtype) ref new objtype()
489 #define ACTIVATE_LOCAL_OBJ(objtype, ...) ref new objtype(__VA_ARGS__)
490 #define ACTIVATE_EVENT_HANDLER(objtype, ...) ref new objtype(__VA_ARGS__)
491 #define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj = ref new objtype();\
492 hr = S_OK;
493 #define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\
494 hr = S_OK;
495 #else
496 #define _Object IInspectable*
497 #define _ObjectObj Microsoft::WRL::ComPtr<IInspectable>
498 #define _String HSTRING
499 #define _StringObj Microsoft::WRL::Wrappers::HString
500 #define _StringReference Microsoft::WRL::Wrappers::HStringReference
501 #define _StringReferenceObj Microsoft::WRL::Wrappers::HStringReference
502 #define _DeviceInformationCollection ABI::Windows::Devices::Enumeration::DeviceInformationCollection
503 #define _MediaCapture ABI::Windows::Media::Capture::IMediaCapture
504 #define _MediaCaptureVideoPreview ABI::Windows::Media::Capture::IMediaCaptureVideoPreview
505 #define _MediaCaptureInitializationSettings ABI::Windows::Media::Capture::IMediaCaptureInitializationSettings
506 #define _VideoDeviceController ABI::Windows::Media::Devices::IVideoDeviceController
507 #define _MediaDeviceController ABI::Windows::Media::Devices::IMediaDeviceController
508 #define _MediaEncodingProperties ABI::Windows::Media::MediaProperties::IMediaEncodingProperties
509 #define _VideoEncodingProperties ABI::Windows::Media::MediaProperties::IVideoEncodingProperties
510 #define _MediaStreamType ABI::Windows::Media::Capture::MediaStreamType
511 #define _AsyncInfo ABI::Windows::Foundation::IAsyncInfo
512 #define _AsyncAction ABI::Windows::Foundation::IAsyncAction
513 #define _AsyncOperation ABI::Windows::Foundation::IAsyncOperation
514 #define _DeviceClass ABI::Windows::Devices::Enumeration::DeviceClass
515 #define _IDeviceInformation ABI::Windows::Devices::Enumeration::IDeviceInformation
516 #define _DeviceInformation ABI::Windows::Devices::Enumeration::DeviceInformation
517 #define _DeviceInformationStatics ABI::Windows::Devices::Enumeration::IDeviceInformationStatics
518 #define _MediaEncodingProfile ABI::Windows::Media::MediaProperties::IMediaEncodingProfile
519 #define _StreamingCaptureMode ABI::Windows::Media::Capture::StreamingCaptureMode
520 #define _PropertySet ABI::Windows::Foundation::Collections::IPropertySet
521 #define _Map ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>
522 #define _PropertyValueStatics ABI::Windows::Foundation::IPropertyValueStatics
523 #define _VectorView ABI::Windows::Foundation::Collections::IVectorView
524 #define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkIdAsync
525 #define _InitializeWithSettingsAsync InitializeWithSettingsAsync
526 #define _FindAllAsyncDeviceClass FindAllAsyncDeviceClass
527 #define _MediaExtension ABI::Windows::Media::IMediaExtension
528 #define BEGIN_CREATE_ASYNC(type, ...) Concurrency_winrt::create_async<type>([__VA_ARGS__]() -> HRESULT {
529 #define END_CREATE_ASYNC(hr) return hr;\
530 })
531 #define DEFINE_TASK Concurrency_winrt::task
532 #define CREATE_TASK Concurrency_winrt::create_task
533 #define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency_winrt::task<rettype>()) ? Concurrency_winrt::create_task<rettype>(func) : _task.then([func](rettype, rettype* retVal) -> HRESULT { return func(retVal); });
534 #define DEFINE_RET_VAL(x) x* retVal
535 #define DEFINE_RET_TYPE(x) <x>
536 #define DEFINE_RET_FORMAL(x) HRESULT
537 #define RET_VAL(x) *retVal = x;\
538 return S_OK;
539 #define RET_VAL_BASE return S_OK;
540 #define MAKE_STRING(str) Microsoft::WRL::Wrappers::HStringReference(L##str)
541 #define GET_STL_STRING(str) std::wstring(str.GetRawBuffer(NULL))
542 #define GET_STL_STRING_RAW(str) WindowsGetStringRawBuffer(str, NULL)
543 #define MAKE_WRL_OBJ(x) Microsoft::WRL::ComPtr<x>
544 #define MAKE_WRL_REF(x) x*
545 #define MAKE_OBJ_REF(x) x
546 #define MAKE_WRL_AGILE_REF(x) x*
547 #define MAKE_PROPERTY_BACKING(Type, PropName) Type PropName;
548 #define MAKE_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }\
549     STDMETHODIMP put_##PropName(Type Val) { PropValue = Val; return S_OK; }
550 #define MAKE_PROPERTY_STRING(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { return ::WindowsDuplicateString(PropValue.Get(), pVal); } else { return E_INVALIDARG; } }\
551     STDMETHODIMP put_##PropName(Type Val) { return PropValue.Set(Val); }
552 #define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }
553 #define THROW_INVALID_ARG RoOriginateError(E_INVALIDARG, nullptr);
554 #define RELEASE_AGILE_WRL(x) if (x) { (x)->Release(); x = nullptr; }
555 #define RELEASE_WRL(x) if (x) { (x)->Release(); x = nullptr; }
556 #define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) Microsoft::WRL::ComPtr<objtype> obj;\
557 hr = orig->QueryInterface(__uuidof(objtype), &obj);
558 #define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) Microsoft::WRL::ComPtr<objtype> obj;\
559 hr = orig.As(&obj);
560 #define WRL_ENUM_GET(obj, prefix, prop) obj::prefix##_##prop
561 #define WRL_PROP_GET(obj, prop, arg, hr) hr = obj->get_##prop(&arg);
562 #define WRL_PROP_PUT(obj, prop, arg, hr) hr = obj->put_##prop(arg);
563 #define WRL_METHOD_BASE(obj, method, ret, hr) hr = obj->##method(&ret);
564 #define WRL_METHOD(obj, method, ret, hr, ...) hr = obj->##method(__VA_ARGS__, &ret);
565 #define WRL_METHOD_NORET_BASE(obj, method, hr) hr = obj->##method();
566 #define REF_WRL_OBJ(obj) obj.GetAddressOf()
567 #define DEREF_WRL_OBJ(obj) obj.Get()
568 #define DEREF_AGILE_WRL_OBJ(obj) obj
569 #define DEREF_AS_NATIVE_WRL_OBJ(type, obj) obj.Get()
570 #define PREPARE_TRANSFER_WRL_OBJ(obj) obj.Detach()
571 #define ACTIVATE_LOCAL_OBJ_BASE(objtype) Microsoft::WRL::Make<objtype>()
572 #define ACTIVATE_LOCAL_OBJ(objtype, ...) Microsoft::WRL::Make<objtype>(__VA_ARGS__)
573 #define ACTIVATE_EVENT_HANDLER(objtype, ...) Microsoft::WRL::Callback<objtype>(__VA_ARGS__).Get()
574 #define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj;\
575 {\
576     Microsoft::WRL::ComPtr<IActivationFactory> objFactory;\
577     hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\
578     if (SUCCEEDED(hr)) {\
579         Microsoft::WRL::ComPtr<IInspectable> pInsp;\
580         hr = objFactory->ActivateInstance(pInsp.GetAddressOf());\
581         if (SUCCEEDED(hr)) hr = pInsp.As(&obj);\
582     }\
583 }
584 #define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\
585 {\
586     Microsoft::WRL::ComPtr<IActivationFactory> objFactory;\
587     hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\
588     if (SUCCEEDED(hr)) {\
589         if (SUCCEEDED(hr)) hr = objFactory.As(&obj);\
590     }\
591 }
592 #endif
593 
594 #define _ComPtr Microsoft::WRL::ComPtr
595 #else
596 
597 #define _COM_SMARTPTR_DECLARE(T,var) T ## Ptr var
598 
599 template <class T>
600 class ComPtr
601 {
602 public:
ComPtr()603     ComPtr() throw()
604     {
605     }
ComPtr(T * lp)606     ComPtr(T* lp) throw()
607     {
608         p = lp;
609     }
ComPtr(_In_ const ComPtr<T> & lp)610     ComPtr(_In_ const ComPtr<T>& lp) throw()
611     {
612         p = lp.p;
613     }
~ComPtr()614     virtual ~ComPtr()
615     {
616     }
617 
operator &()618     T** operator&() throw()
619     {
620         assert(p == NULL);
621         return p.operator&();
622     }
operator ->() const623     T* operator->() const throw()
624     {
625         assert(p != NULL);
626         return p.operator->();
627     }
operator !() const628     bool operator!() const throw()
629     {
630         return p.operator==(NULL);
631     }
operator ==(_In_opt_ T * pT) const632     bool operator==(_In_opt_ T* pT) const throw()
633     {
634         return p.operator==(pT);
635     }
operator !=(_In_opt_ T * pT) const636     bool operator!=(_In_opt_ T* pT) const throw()
637     {
638         return p.operator!=(pT);
639     }
operator bool()640     operator bool()
641     {
642         return p.operator!=(NULL);
643     }
644 
GetAddressOf() const645     T* const* GetAddressOf() const throw()
646     {
647         return &p;
648     }
649 
GetAddressOf()650     T** GetAddressOf() throw()
651     {
652         return &p;
653     }
654 
ReleaseAndGetAddressOf()655     T** ReleaseAndGetAddressOf() throw()
656     {
657         p.Release();
658         return &p;
659     }
660 
Get() const661     T* Get() const throw()
662     {
663         return p;
664     }
665 
666     // Attach to an existing interface (does not AddRef)
Attach(_In_opt_ T * p2)667     void Attach(_In_opt_ T* p2) throw()
668     {
669         p.Attach(p2);
670     }
671     // Detach the interface (does not Release)
Detach()672     T* Detach() throw()
673     {
674         return p.Detach();
675     }
CopyTo(_Deref_out_opt_ T ** ppT)676     _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw()
677     {
678         assert(ppT != NULL);
679         if (ppT == NULL)
680             return E_POINTER;
681         *ppT = p;
682         if (p != NULL)
683             p->AddRef();
684         return S_OK;
685     }
686 
Reset()687     void Reset()
688     {
689         p.Release();
690     }
691 
692     // query for U interface
693     template<typename U>
As(_Inout_ U ** lp) const694     HRESULT As(_Inout_ U** lp) const throw()
695     {
696         return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp));
697     }
698     // query for U interface
699     template<typename U>
As(_Out_ ComPtr<U> * lp) const700     HRESULT As(_Out_ ComPtr<U>* lp) const throw()
701     {
702         return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp->ReleaseAndGetAddressOf()));
703     }
704 private:
705     _COM_SMARTPTR_TYPEDEF(T, __uuidof(T));
706     _COM_SMARTPTR_DECLARE(T, p);
707 };
708 
709 #define _ComPtr ComPtr
710 #endif
711 
712 template <class TBase=IMFAttributes>
713 class CBaseAttributes : public TBase
714 {
715 protected:
716     // This version of the constructor does not initialize the
717     // attribute store. The derived class must call Initialize() in
718     // its own constructor.
CBaseAttributes()719     CBaseAttributes()
720     {
721     }
722 
723     // This version of the constructor initializes the attribute
724     // store, but the derived class must pass an HRESULT parameter
725     // to the constructor.
726 
CBaseAttributes(HRESULT & hr,UINT32 cInitialSize=0)727     CBaseAttributes(HRESULT& hr, UINT32 cInitialSize = 0)
728     {
729         hr = Initialize(cInitialSize);
730     }
731 
732     // The next version of the constructor uses a caller-provided
733     // implementation of IMFAttributes.
734 
735     // (Sometimes you want to delegate IMFAttributes calls to some
736     // other object that implements IMFAttributes, rather than using
737     // MFCreateAttributes.)
738 
CBaseAttributes(HRESULT & hr,IUnknown * pUnk)739     CBaseAttributes(HRESULT& hr, IUnknown *pUnk)
740     {
741         hr = Initialize(pUnk);
742     }
743 
~CBaseAttributes()744     virtual ~CBaseAttributes()
745     {
746     }
747 
748     // Initializes the object by creating the standard Media Foundation attribute store.
Initialize(UINT32 cInitialSize=0)749     HRESULT Initialize(UINT32 cInitialSize = 0)
750     {
751         if (_spAttributes.Get() == nullptr)
752         {
753             return MFCreateAttributes(&_spAttributes, cInitialSize);
754         }
755         else
756         {
757             return S_OK;
758         }
759     }
760 
761     // Initializes this object from a caller-provided attribute store.
762     // pUnk: Pointer to an object that exposes IMFAttributes.
Initialize(IUnknown * pUnk)763     HRESULT Initialize(IUnknown *pUnk)
764     {
765         if (_spAttributes)
766         {
767             _spAttributes.Reset();
768             _spAttributes = nullptr;
769         }
770 
771 
772         return pUnk->QueryInterface(IID_PPV_ARGS(&_spAttributes));
773     }
774 
775 public:
776 
777     // IMFAttributes methods
778 
GetItem(REFGUID guidKey,PROPVARIANT * pValue)779     STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue)
780     {
781         assert(_spAttributes);
782         return _spAttributes->GetItem(guidKey, pValue);
783     }
784 
GetItemType(REFGUID guidKey,MF_ATTRIBUTE_TYPE * pType)785     STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType)
786     {
787         assert(_spAttributes);
788         return _spAttributes->GetItemType(guidKey, pType);
789     }
790 
CompareItem(REFGUID guidKey,REFPROPVARIANT Value,BOOL * pbResult)791     STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult)
792     {
793         assert(_spAttributes);
794         return _spAttributes->CompareItem(guidKey, Value, pbResult);
795     }
796 
Compare(IMFAttributes * pTheirs,MF_ATTRIBUTES_MATCH_TYPE MatchType,BOOL * pbResult)797     STDMETHODIMP Compare(
798         IMFAttributes* pTheirs,
799         MF_ATTRIBUTES_MATCH_TYPE MatchType,
800         BOOL* pbResult
801         )
802     {
803         assert(_spAttributes);
804         return _spAttributes->Compare(pTheirs, MatchType, pbResult);
805     }
806 
GetUINT32(REFGUID guidKey,UINT32 * punValue)807     STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue)
808     {
809         assert(_spAttributes);
810         return _spAttributes->GetUINT32(guidKey, punValue);
811     }
812 
GetUINT64(REFGUID guidKey,UINT64 * punValue)813     STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue)
814     {
815         assert(_spAttributes);
816         return _spAttributes->GetUINT64(guidKey, punValue);
817     }
818 
GetDouble(REFGUID guidKey,double * pfValue)819     STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue)
820     {
821         assert(_spAttributes);
822         return _spAttributes->GetDouble(guidKey, pfValue);
823     }
824 
GetGUID(REFGUID guidKey,GUID * pguidValue)825     STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue)
826     {
827         assert(_spAttributes);
828         return _spAttributes->GetGUID(guidKey, pguidValue);
829     }
830 
GetStringLength(REFGUID guidKey,UINT32 * pcchLength)831     STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength)
832     {
833         assert(_spAttributes);
834         return _spAttributes->GetStringLength(guidKey, pcchLength);
835     }
836 
GetString(REFGUID guidKey,LPWSTR pwszValue,UINT32 cchBufSize,UINT32 * pcchLength)837     STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength)
838     {
839         assert(_spAttributes);
840         return _spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
841     }
842 
GetAllocatedString(REFGUID guidKey,LPWSTR * ppwszValue,UINT32 * pcchLength)843     STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength)
844     {
845         assert(_spAttributes);
846         return _spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
847     }
848 
GetBlobSize(REFGUID guidKey,UINT32 * pcbBlobSize)849     STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize)
850     {
851         assert(_spAttributes);
852         return _spAttributes->GetBlobSize(guidKey, pcbBlobSize);
853     }
854 
GetBlob(REFGUID guidKey,UINT8 * pBuf,UINT32 cbBufSize,UINT32 * pcbBlobSize)855     STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize)
856     {
857         assert(_spAttributes);
858         return _spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
859     }
860 
GetAllocatedBlob(REFGUID guidKey,UINT8 ** ppBuf,UINT32 * pcbSize)861     STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize)
862     {
863         assert(_spAttributes);
864         return _spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
865     }
866 
GetUnknown(REFGUID guidKey,REFIID riid,LPVOID * ppv)867     STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv)
868     {
869         assert(_spAttributes);
870         return _spAttributes->GetUnknown(guidKey, riid, ppv);
871     }
872 
SetItem(REFGUID guidKey,REFPROPVARIANT Value)873     STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value)
874     {
875         assert(_spAttributes);
876         return _spAttributes->SetItem(guidKey, Value);
877     }
878 
DeleteItem(REFGUID guidKey)879     STDMETHODIMP DeleteItem(REFGUID guidKey)
880     {
881         assert(_spAttributes);
882         return _spAttributes->DeleteItem(guidKey);
883     }
884 
DeleteAllItems()885     STDMETHODIMP DeleteAllItems()
886     {
887         assert(_spAttributes);
888         return _spAttributes->DeleteAllItems();
889     }
890 
SetUINT32(REFGUID guidKey,UINT32 unValue)891     STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue)
892     {
893         assert(_spAttributes);
894         return _spAttributes->SetUINT32(guidKey, unValue);
895     }
896 
SetUINT64(REFGUID guidKey,UINT64 unValue)897     STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue)
898     {
899         assert(_spAttributes);
900         return _spAttributes->SetUINT64(guidKey, unValue);
901     }
902 
SetDouble(REFGUID guidKey,double fValue)903     STDMETHODIMP SetDouble(REFGUID guidKey, double fValue)
904     {
905         assert(_spAttributes);
906         return _spAttributes->SetDouble(guidKey, fValue);
907     }
908 
SetGUID(REFGUID guidKey,REFGUID guidValue)909     STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue)
910     {
911         assert(_spAttributes);
912         return _spAttributes->SetGUID(guidKey, guidValue);
913     }
914 
SetString(REFGUID guidKey,LPCWSTR wszValue)915     STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue)
916     {
917         assert(_spAttributes);
918         return _spAttributes->SetString(guidKey, wszValue);
919     }
920 
SetBlob(REFGUID guidKey,const UINT8 * pBuf,UINT32 cbBufSize)921     STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize)
922     {
923         assert(_spAttributes);
924         return _spAttributes->SetBlob(guidKey, pBuf, cbBufSize);
925     }
926 
SetUnknown(REFGUID guidKey,IUnknown * pUnknown)927     STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown)
928     {
929         assert(_spAttributes);
930         return _spAttributes->SetUnknown(guidKey, pUnknown);
931     }
932 
LockStore()933     STDMETHODIMP LockStore()
934     {
935         assert(_spAttributes);
936         return _spAttributes->LockStore();
937     }
938 
UnlockStore()939     STDMETHODIMP UnlockStore()
940     {
941         assert(_spAttributes);
942         return _spAttributes->UnlockStore();
943     }
944 
GetCount(UINT32 * pcItems)945     STDMETHODIMP GetCount(UINT32* pcItems)
946     {
947         assert(_spAttributes);
948         return _spAttributes->GetCount(pcItems);
949     }
950 
GetItemByIndex(UINT32 unIndex,GUID * pguidKey,PROPVARIANT * pValue)951     STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue)
952     {
953         assert(_spAttributes);
954         return _spAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
955     }
956 
CopyAllItems(IMFAttributes * pDest)957     STDMETHODIMP CopyAllItems(IMFAttributes* pDest)
958     {
959         assert(_spAttributes);
960         return _spAttributes->CopyAllItems(pDest);
961     }
962 
963     // Helper functions
964 
SerializeToStream(DWORD dwOptions,IStream * pStm)965     HRESULT SerializeToStream(DWORD dwOptions, IStream* pStm)
966         // dwOptions: Flags from MF_ATTRIBUTE_SERIALIZE_OPTIONS
967     {
968         assert(_spAttributes);
969         return MFSerializeAttributesToStream(_spAttributes.Get(), dwOptions, pStm);
970     }
971 
DeserializeFromStream(DWORD dwOptions,IStream * pStm)972     HRESULT DeserializeFromStream(DWORD dwOptions, IStream* pStm)
973     {
974         assert(_spAttributes);
975         return MFDeserializeAttributesFromStream(_spAttributes.Get(), dwOptions, pStm);
976     }
977 
978     // SerializeToBlob: Stores the attributes in a byte array.
979     //
980     // ppBuf: Receives a pointer to the byte array.
981     // pcbSize: Receives the size of the byte array.
982     //
983     // The caller must free the array using CoTaskMemFree.
SerializeToBlob(UINT8 ** ppBuffer,UINT * pcbSize)984     HRESULT SerializeToBlob(UINT8 **ppBuffer, UINT *pcbSize)
985     {
986         assert(_spAttributes);
987 
988         if (ppBuffer == NULL)
989         {
990             return E_POINTER;
991         }
992         if (pcbSize == NULL)
993         {
994             return E_POINTER;
995         }
996 
997         HRESULT hr = S_OK;
998         UINT32 cbSize = 0;
999         BYTE *pBuffer = NULL;
1000 
1001         CHECK_HR(hr = MFGetAttributesAsBlobSize(_spAttributes.Get(), &cbSize));
1002 
1003         pBuffer = (BYTE*)CoTaskMemAlloc(cbSize);
1004         if (pBuffer == NULL)
1005         {
1006             CHECK_HR(hr = E_OUTOFMEMORY);
1007         }
1008 
1009         CHECK_HR(hr = MFGetAttributesAsBlob(_spAttributes.Get(), pBuffer, cbSize));
1010 
1011         *ppBuffer = pBuffer;
1012         *pcbSize = cbSize;
1013 
1014 done:
1015         if (FAILED(hr))
1016         {
1017             *ppBuffer = NULL;
1018             *pcbSize = 0;
1019             CoTaskMemFree(pBuffer);
1020         }
1021         return hr;
1022     }
1023 
DeserializeFromBlob(const UINT8 * pBuffer,UINT cbSize)1024     HRESULT DeserializeFromBlob(const UINT8* pBuffer, UINT cbSize)
1025     {
1026         assert(_spAttributes);
1027         return MFInitAttributesFromBlob(_spAttributes.Get(), pBuffer, cbSize);
1028     }
1029 
GetRatio(REFGUID guidKey,UINT32 * pnNumerator,UINT32 * punDenominator)1030     HRESULT GetRatio(REFGUID guidKey, UINT32* pnNumerator, UINT32* punDenominator)
1031     {
1032         assert(_spAttributes);
1033         return MFGetAttributeRatio(_spAttributes.Get(), guidKey, pnNumerator, punDenominator);
1034     }
1035 
SetRatio(REFGUID guidKey,UINT32 unNumerator,UINT32 unDenominator)1036     HRESULT SetRatio(REFGUID guidKey, UINT32 unNumerator, UINT32 unDenominator)
1037     {
1038         assert(_spAttributes);
1039         return MFSetAttributeRatio(_spAttributes.Get(), guidKey, unNumerator, unDenominator);
1040     }
1041 
1042     // Gets an attribute whose value represents the size of something (eg a video frame).
GetSize(REFGUID guidKey,UINT32 * punWidth,UINT32 * punHeight)1043     HRESULT GetSize(REFGUID guidKey, UINT32* punWidth, UINT32* punHeight)
1044     {
1045         assert(_spAttributes);
1046         return MFGetAttributeSize(_spAttributes.Get(), guidKey, punWidth, punHeight);
1047     }
1048 
1049     // Sets an attribute whose value represents the size of something (eg a video frame).
SetSize(REFGUID guidKey,UINT32 unWidth,UINT32 unHeight)1050     HRESULT SetSize(REFGUID guidKey, UINT32 unWidth, UINT32 unHeight)
1051     {
1052         assert(_spAttributes);
1053         return MFSetAttributeSize (_spAttributes.Get(), guidKey, unWidth, unHeight);
1054     }
1055 
1056 protected:
1057     _ComPtr<IMFAttributes> _spAttributes;
1058 };
1059 
1060 class StreamSink :
1061 #ifdef WINRT
1062     public Microsoft::WRL::RuntimeClass<
1063     Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>,
1064     IMFStreamSink,
1065     IMFMediaEventGenerator,
1066     IMFMediaTypeHandler,
1067     CBaseAttributes<> >
1068 #else
1069     public IMFStreamSink,
1070     public IMFMediaTypeHandler,
1071     public CBaseAttributes<>,
1072     public ICustomStreamSink
1073 #endif
1074 {
1075 public:
1076     // IUnknown methods
1077 #if defined(_MSC_VER) && _MSC_VER >= 1700  // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012
STDMETHOD(QueryInterface)1078     STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv)
1079 #else
1080     STDMETHOD(QueryInterface)(REFIID riid, void **ppv)
1081 #endif
1082     {
1083         if (ppv == nullptr) {
1084             return E_POINTER;
1085         }
1086         (*ppv) = nullptr;
1087         HRESULT hr = S_OK;
1088         if (riid == IID_IMarshal) {
1089             return MarshalQI(riid, ppv);
1090         } else {
1091 #ifdef WINRT
1092             hr = RuntimeClassT::QueryInterface(riid, ppv);
1093 #else
1094             if (riid == IID_IUnknown || riid == IID_IMFStreamSink) {
1095                 *ppv = static_cast<IMFStreamSink*>(this);
1096                 AddRef();
1097             } else if (riid == IID_IMFMediaEventGenerator) {
1098                 *ppv = static_cast<IMFMediaEventGenerator*>(this);
1099                 AddRef();
1100             } else if (riid == IID_IMFMediaTypeHandler) {
1101                 *ppv = static_cast<IMFMediaTypeHandler*>(this);
1102                 AddRef();
1103             } else if (riid == IID_IMFAttributes) {
1104                 *ppv = static_cast<IMFAttributes*>(this);
1105                 AddRef();
1106             } else if (riid == IID_ICustomStreamSink) {
1107                 *ppv = static_cast<ICustomStreamSink*>(this);
1108                 AddRef();
1109             } else
1110                 hr = E_NOINTERFACE;
1111 #endif
1112         }
1113 
1114         return hr;
1115     }
1116 
1117 #ifdef WINRT
STDMETHOD(RuntimeClassInitialize)1118     STDMETHOD(RuntimeClassInitialize)() { return S_OK; }
1119 #else
AddRef()1120     ULONG STDMETHODCALLTYPE AddRef()
1121     {
1122         return InterlockedIncrement(&m_cRef);
1123     }
Release()1124     ULONG STDMETHODCALLTYPE Release()
1125     {
1126         ULONG cRef = InterlockedDecrement(&m_cRef);
1127         if (cRef == 0)
1128         {
1129             delete this;
1130         }
1131         return cRef;
1132     }
1133 #endif
MarshalQI(REFIID riid,LPVOID * ppv)1134     HRESULT MarshalQI(REFIID riid, LPVOID* ppv)
1135     {
1136         HRESULT hr = S_OK;
1137         if (m_spFTM == nullptr) {
1138             EnterCriticalSection(&m_critSec);
1139             if (m_spFTM == nullptr) {
1140                 hr = CoCreateFreeThreadedMarshaler((IMFStreamSink*)this, &m_spFTM);
1141             }
1142             LeaveCriticalSection(&m_critSec);
1143         }
1144 
1145         if (SUCCEEDED(hr)) {
1146             if (m_spFTM == nullptr) {
1147                 hr = E_UNEXPECTED;
1148             }
1149             else {
1150                 hr = m_spFTM.Get()->QueryInterface(riid, ppv);
1151             }
1152         }
1153         return hr;
1154     }
1155     enum State
1156     {
1157         State_TypeNotSet = 0,    // No media type is set
1158         State_Ready,             // Media type is set, Start has never been called.
1159         State_Started,
1160         State_Stopped,
1161         State_Paused,
1162         State_Count              // Number of states
1163     };
StreamSink()1164     StreamSink() : m_IsShutdown(false),
1165         m_StartTime(0), m_fGetStartTimeFromSample(false), m_fWaitingForFirstSample(false),
1166         m_state(State_TypeNotSet), m_pParent(nullptr),
1167         m_imageWidthInPixels(0), m_imageHeightInPixels(0) {
1168 #ifdef WINRT
1169         m_token.value = 0;
1170 #else
1171         m_bConnected = false;
1172 #endif
1173         InitializeCriticalSectionEx(&m_critSec, 3000, 0);
1174         ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype));
1175         CBaseAttributes::Initialize(0U);
1176         DebugPrintOut(L"StreamSink::StreamSink\n");
1177     }
~StreamSink()1178     virtual ~StreamSink() {
1179         DeleteCriticalSection(&m_critSec);
1180         assert(m_IsShutdown);
1181         DebugPrintOut(L"StreamSink::~StreamSink\n");
1182     }
1183 
Initialize()1184     HRESULT Initialize()
1185     {
1186         HRESULT hr;
1187         // Create the event queue helper.
1188         hr = MFCreateEventQueue(&m_spEventQueue);
1189         if (SUCCEEDED(hr))
1190         {
1191             _ComPtr<IMFMediaSink> pMedSink;
1192             hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf());
1193             assert(pMedSink.Get() != NULL);
1194             if (SUCCEEDED(hr)) {
1195                 hr = pMedSink.Get()->QueryInterface(IID_PPV_ARGS(&m_pParent));
1196             }
1197         }
1198         return hr;
1199     }
1200 
CheckShutdown() const1201     HRESULT CheckShutdown() const
1202     {
1203         if (m_IsShutdown)
1204         {
1205             return MF_E_SHUTDOWN;
1206         }
1207         else
1208         {
1209             return S_OK;
1210         }
1211     }
1212     // Called when the presentation clock starts.
Start(MFTIME start)1213     HRESULT Start(MFTIME start)
1214     {
1215         HRESULT hr = S_OK;
1216         EnterCriticalSection(&m_critSec);
1217         if (m_state != State_TypeNotSet) {
1218             if (start != PRESENTATION_CURRENT_POSITION)
1219             {
1220                 m_StartTime = start;        // Cache the start time.
1221                 m_fGetStartTimeFromSample = false;
1222             }
1223             else
1224             {
1225                 m_fGetStartTimeFromSample = true;
1226             }
1227             m_state = State_Started;
1228             GUID guiMajorType;
1229             m_fWaitingForFirstSample = SUCCEEDED(m_spCurrentType->GetMajorType(&guiMajorType)) && (guiMajorType == MFMediaType_Video);
1230             hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL);
1231             if (SUCCEEDED(hr)) {
1232                 hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL);
1233             }
1234         }
1235         else hr = MF_E_NOT_INITIALIZED;
1236         LeaveCriticalSection(&m_critSec);
1237         return hr;
1238     }
1239 
1240     // Called when the presentation clock pauses.
Pause()1241     HRESULT Pause()
1242     {
1243         EnterCriticalSection(&m_critSec);
1244 
1245         HRESULT hr = S_OK;
1246 
1247         if (m_state != State_Stopped && m_state != State_TypeNotSet) {
1248             m_state = State_Paused;
1249             hr = QueueEvent(MEStreamSinkPaused, GUID_NULL, hr, NULL);
1250         } else if (hr == State_TypeNotSet)
1251             hr = MF_E_NOT_INITIALIZED;
1252         else
1253             hr = MF_E_INVALIDREQUEST;
1254         LeaveCriticalSection(&m_critSec);
1255         return hr;
1256     }
1257     // Called when the presentation clock restarts.
Restart()1258     HRESULT Restart()
1259     {
1260         EnterCriticalSection(&m_critSec);
1261 
1262         HRESULT hr = S_OK;
1263 
1264         if (m_state == State_Paused) {
1265             m_state = State_Started;
1266             hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL);
1267             if (SUCCEEDED(hr)) {
1268                 hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL);
1269             }
1270         } else if (hr == State_TypeNotSet)
1271             hr = MF_E_NOT_INITIALIZED;
1272         else
1273             hr = MF_E_INVALIDREQUEST;
1274         LeaveCriticalSection(&m_critSec);
1275         return hr;
1276     }
1277     // Called when the presentation clock stops.
Stop()1278     HRESULT Stop()
1279     {
1280         EnterCriticalSection(&m_critSec);
1281 
1282         HRESULT hr = S_OK;
1283         if (m_state != State_TypeNotSet) {
1284             m_state = State_Stopped;
1285             hr = QueueEvent(MEStreamSinkStopped, GUID_NULL, hr, NULL);
1286         }
1287         else hr = MF_E_NOT_INITIALIZED;
1288         LeaveCriticalSection(&m_critSec);
1289         return hr;
1290     }
1291 
1292     // Shuts down the stream sink.
Shutdown()1293     HRESULT Shutdown()
1294     {
1295         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
1296         HRESULT hr = S_OK;
1297         assert(!m_IsShutdown);
1298         hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
1299         if (SUCCEEDED(hr)) {
1300             hr = pSampleCallback->OnShutdown();
1301         }
1302 
1303         if (m_spEventQueue) {
1304             hr = m_spEventQueue->Shutdown();
1305         }
1306         if (m_pParent)
1307             m_pParent->Release();
1308         m_spCurrentType.Reset();
1309         m_IsShutdown = TRUE;
1310 
1311         return hr;
1312     }
1313 
1314     //IMFStreamSink
GetMediaSink(__RPC__deref_out_opt IMFMediaSink ** ppMediaSink)1315     HRESULT STDMETHODCALLTYPE GetMediaSink(
1316     /* [out] */ __RPC__deref_out_opt IMFMediaSink **ppMediaSink) {
1317         if (ppMediaSink == NULL)
1318         {
1319             return E_INVALIDARG;
1320         }
1321 
1322         EnterCriticalSection(&m_critSec);
1323 
1324         HRESULT hr = CheckShutdown();
1325 
1326         if (SUCCEEDED(hr))
1327         {
1328             _ComPtr<IMFMediaSink> pMedSink;
1329             hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf());
1330             if (SUCCEEDED(hr)) {
1331                 *ppMediaSink = pMedSink.Detach();
1332             }
1333         }
1334 
1335         LeaveCriticalSection(&m_critSec);
1336         DebugPrintOut(L"StreamSink::GetMediaSink: HRESULT=%i\n", hr);
1337         return hr;
1338     }
1339 
GetIdentifier(__RPC__out DWORD * pdwIdentifier)1340     HRESULT STDMETHODCALLTYPE GetIdentifier(
1341         /* [out] */ __RPC__out DWORD *pdwIdentifier) {
1342         if (pdwIdentifier == NULL)
1343         {
1344             return E_INVALIDARG;
1345         }
1346 
1347         EnterCriticalSection(&m_critSec);
1348 
1349         HRESULT hr = CheckShutdown();
1350 
1351         if (SUCCEEDED(hr))
1352         {
1353             hr = GetUINT32(MF_STREAMSINK_ID, (UINT32*)pdwIdentifier);
1354         }
1355 
1356         LeaveCriticalSection(&m_critSec);
1357         DebugPrintOut(L"StreamSink::GetIdentifier: HRESULT=%i\n", hr);
1358         return hr;
1359     }
1360 
GetMediaTypeHandler(__RPC__deref_out_opt IMFMediaTypeHandler ** ppHandler)1361     HRESULT STDMETHODCALLTYPE GetMediaTypeHandler(
1362         /* [out] */ __RPC__deref_out_opt IMFMediaTypeHandler **ppHandler) {
1363         if (ppHandler == NULL)
1364         {
1365             return E_INVALIDARG;
1366         }
1367 
1368         EnterCriticalSection(&m_critSec);
1369 
1370         HRESULT hr = CheckShutdown();
1371 
1372         // This stream object acts as its own type handler, so we QI ourselves.
1373         if (SUCCEEDED(hr))
1374         {
1375             hr = QueryInterface(IID_IMFMediaTypeHandler, (void**)ppHandler);
1376         }
1377 
1378         LeaveCriticalSection(&m_critSec);
1379         DebugPrintOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr);
1380         return hr;
1381     }
1382 
ProcessSample(IMFSample * pSample)1383     HRESULT STDMETHODCALLTYPE ProcessSample(IMFSample *pSample) {
1384         _ComPtr<IMFMediaBuffer> pInput;
1385         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
1386         BYTE *pSrc = NULL;          // Source buffer.
1387         // Stride if the buffer does not support IMF2DBuffer
1388         LONGLONG hnsTime = 0;
1389         LONGLONG hnsDuration = 0;
1390         DWORD cbMaxLength;
1391         DWORD cbCurrentLength = 0;
1392         GUID guidMajorType;
1393         if (pSample == NULL)
1394         {
1395             return E_INVALIDARG;
1396         }
1397         HRESULT hr = S_OK;
1398 
1399         EnterCriticalSection(&m_critSec);
1400 
1401         if (m_state != State_Started && m_state != State_Paused) {
1402             if (m_state == State_TypeNotSet)
1403                 hr = MF_E_NOT_INITIALIZED;
1404             else
1405                 hr = MF_E_INVALIDREQUEST;
1406         }
1407         if (SUCCEEDED(hr))
1408             hr = CheckShutdown();
1409         if (SUCCEEDED(hr)) {
1410             hr = pSample->ConvertToContiguousBuffer(&pInput);
1411             if (SUCCEEDED(hr)) {
1412                 hr = pSample->GetSampleTime(&hnsTime);
1413             }
1414             if (SUCCEEDED(hr)) {
1415                 hr = pSample->GetSampleDuration(&hnsDuration);
1416             }
1417             if (SUCCEEDED(hr)) {
1418                 hr = GetMajorType(&guidMajorType);
1419             }
1420             if (SUCCEEDED(hr)) {
1421                 hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
1422             }
1423             if (SUCCEEDED(hr)) {
1424                 hr = pInput->Lock(&pSrc, &cbMaxLength, &cbCurrentLength);
1425             }
1426             if (SUCCEEDED(hr)) {
1427                 hr = pSampleCallback->OnProcessSample(guidMajorType, 0, hnsTime, hnsDuration, pSrc, cbCurrentLength);
1428                 pInput->Unlock();
1429             }
1430             if (SUCCEEDED(hr)) {
1431                 hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
1432             }
1433         }
1434         LeaveCriticalSection(&m_critSec);
1435         return hr;
1436     }
1437 
PlaceMarker(MFSTREAMSINK_MARKER_TYPE eMarkerType,__RPC__in const PROPVARIANT *,__RPC__in const PROPVARIANT *)1438     HRESULT STDMETHODCALLTYPE PlaceMarker(
1439         /* [in] */ MFSTREAMSINK_MARKER_TYPE eMarkerType,
1440         /* [in] */ __RPC__in const PROPVARIANT * /*pvarMarkerValue*/,
1441         /* [in] */ __RPC__in const PROPVARIANT * /*pvarContextValue*/) {
1442         eMarkerType;
1443         EnterCriticalSection(&m_critSec);
1444 
1445         HRESULT hr = S_OK;
1446         if (m_state == State_TypeNotSet)
1447             hr = MF_E_NOT_INITIALIZED;
1448 
1449         if (SUCCEEDED(hr))
1450             hr = CheckShutdown();
1451 
1452         if (SUCCEEDED(hr))
1453         {
1454             //at shutdown will receive MFSTREAMSINK_MARKER_ENDOFSEGMENT
1455             hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
1456         }
1457 
1458         LeaveCriticalSection(&m_critSec);
1459         DebugPrintOut(L"StreamSink::PlaceMarker: HRESULT=%i %s\n", hr, StreamSinkMarkerTypeMap.at(eMarkerType).c_str());
1460         return hr;
1461     }
1462 
Flush(void)1463     HRESULT STDMETHODCALLTYPE Flush(void) {
1464         EnterCriticalSection(&m_critSec);
1465 
1466         HRESULT hr = CheckShutdown();
1467 
1468         if (SUCCEEDED(hr))
1469         {
1470         }
1471 
1472         LeaveCriticalSection(&m_critSec);
1473         DebugPrintOut(L"StreamSink::Flush: HRESULT=%i\n", hr);
1474         return hr;
1475     }
1476 
1477     //IMFMediaEventGenerator
GetEvent(DWORD dwFlags,IMFMediaEvent ** ppEvent)1478     HRESULT STDMETHODCALLTYPE GetEvent(
1479         DWORD dwFlags, IMFMediaEvent **ppEvent) {
1480         // NOTE:
1481         // GetEvent can block indefinitely, so we don't hold the lock.
1482         // This requires some juggling with the event queue pointer.
1483 
1484         HRESULT hr = S_OK;
1485 
1486         _ComPtr<IMFMediaEventQueue> pQueue;
1487 
1488         {
1489             EnterCriticalSection(&m_critSec);
1490 
1491             // Check shutdown
1492             hr = CheckShutdown();
1493 
1494             // Get the pointer to the event queue.
1495             if (SUCCEEDED(hr))
1496             {
1497                 pQueue = m_spEventQueue.Get();
1498             }
1499             LeaveCriticalSection(&m_critSec);
1500         }
1501 
1502         // Now get the event.
1503         if (SUCCEEDED(hr))
1504         {
1505             hr = pQueue->GetEvent(dwFlags, ppEvent);
1506         }
1507         MediaEventType meType = MEUnknown;
1508         if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) {
1509         }
1510         HRESULT hrStatus = S_OK;
1511         if (SUCCEEDED(hr))
1512             hr = (*ppEvent)->GetStatus(&hrStatus);
1513         if (SUCCEEDED(hr))
1514             DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str());
1515         else
1516             DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i\n", hr);
1517         return hr;
1518     }
1519 
BeginGetEvent(IMFAsyncCallback * pCallback,IUnknown * punkState)1520     HRESULT STDMETHODCALLTYPE BeginGetEvent(
1521         IMFAsyncCallback *pCallback, IUnknown *punkState) {
1522         HRESULT hr = S_OK;
1523 
1524         EnterCriticalSection(&m_critSec);
1525 
1526         hr = CheckShutdown();
1527 
1528         if (SUCCEEDED(hr))
1529         {
1530             hr = m_spEventQueue->BeginGetEvent(pCallback, punkState);
1531         }
1532         LeaveCriticalSection(&m_critSec);
1533         DebugPrintOut(L"StreamSink::BeginGetEvent: HRESULT=%i\n", hr);
1534         return hr;
1535     }
1536 
EndGetEvent(IMFAsyncResult * pResult,IMFMediaEvent ** ppEvent)1537     HRESULT STDMETHODCALLTYPE EndGetEvent(
1538         IMFAsyncResult *pResult, IMFMediaEvent **ppEvent) {
1539         HRESULT hr = S_OK;
1540 
1541         EnterCriticalSection(&m_critSec);
1542 
1543         hr = CheckShutdown();
1544 
1545         if (SUCCEEDED(hr))
1546         {
1547             hr = m_spEventQueue->EndGetEvent(pResult, ppEvent);
1548         }
1549 
1550         MediaEventType meType = MEUnknown;
1551         if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) {
1552         }
1553 
1554         LeaveCriticalSection(&m_critSec);
1555         HRESULT hrStatus = S_OK;
1556         if (SUCCEEDED(hr))
1557             hr = (*ppEvent)->GetStatus(&hrStatus);
1558         if (SUCCEEDED(hr))
1559             DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str());
1560         else
1561             DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i\n", hr);
1562         return hr;
1563     }
1564 
QueueEvent(MediaEventType met,REFGUID guidExtendedType,HRESULT hrStatus,const PROPVARIANT * pvValue)1565     HRESULT STDMETHODCALLTYPE QueueEvent(
1566         MediaEventType met, REFGUID guidExtendedType,
1567         HRESULT hrStatus, const PROPVARIANT *pvValue) {
1568         HRESULT hr = S_OK;
1569 
1570         EnterCriticalSection(&m_critSec);
1571 
1572         hr = CheckShutdown();
1573 
1574         if (SUCCEEDED(hr))
1575         {
1576             hr = m_spEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
1577         }
1578 
1579         LeaveCriticalSection(&m_critSec);
1580         DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(met).c_str());
1581         DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i\n", hr);
1582         return hr;
1583     }
1584 
1585     /// IMFMediaTypeHandler methods
1586 
1587     // Check if a media type is supported.
IsMediaTypeSupported(IMFMediaType * pMediaType,IMFMediaType ** ppMediaType)1588     STDMETHODIMP IsMediaTypeSupported(
1589         /* [in] */ IMFMediaType *pMediaType,
1590         /* [out] */ IMFMediaType **ppMediaType)
1591     {
1592         if (pMediaType == nullptr)
1593         {
1594             return E_INVALIDARG;
1595         }
1596 
1597         EnterCriticalSection(&m_critSec);
1598 
1599         GUID majorType = GUID_NULL;
1600 
1601         HRESULT hr = CheckShutdown();
1602 
1603         if (SUCCEEDED(hr))
1604         {
1605             hr = pMediaType->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
1606         }
1607 
1608         // First make sure it's video or audio type.
1609         if (SUCCEEDED(hr))
1610         {
1611             if (majorType != MFMediaType_Video && majorType != MFMediaType_Audio)
1612             {
1613                 hr = MF_E_INVALIDTYPE;
1614             }
1615         }
1616 
1617         if (SUCCEEDED(hr) && m_spCurrentType != nullptr)
1618         {
1619             GUID guiNewSubtype;
1620             if (FAILED(pMediaType->GetGUID(MF_MT_SUBTYPE, &guiNewSubtype)) ||
1621                 guiNewSubtype != m_guiCurrentSubtype)
1622             {
1623                 hr = MF_E_INVALIDTYPE;
1624             }
1625         }
1626         // We don't return any "close match" types.
1627         if (ppMediaType)
1628         {
1629             *ppMediaType = nullptr;
1630         }
1631 
1632         if (ppMediaType && SUCCEEDED(hr)) {
1633             _ComPtr<IMFMediaType> pType;
1634             hr = MFCreateMediaType(ppMediaType);
1635             if (SUCCEEDED(hr)) {
1636                 hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
1637             }
1638             if (SUCCEEDED(hr)) {
1639                 hr = pType->LockStore();
1640             }
1641             bool bLocked = false;
1642             if (SUCCEEDED(hr)) {
1643                 bLocked = true;
1644                 UINT32 uiCount;
1645                 UINT32 uiTotal;
1646                 hr = pType->GetCount(&uiTotal);
1647                 for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) {
1648                     GUID guid;
1649                     PROPVARIANT propval;
1650                     hr = pType->GetItemByIndex(uiCount, &guid, &propval);
1651                     if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO ||
1652                         guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) {
1653                         hr = (*ppMediaType)->SetItem(guid, propval);
1654                         PropVariantClear(&propval);
1655                     }
1656                 }
1657             }
1658             if (bLocked) {
1659                 hr = pType->UnlockStore();
1660             }
1661         }
1662         LeaveCriticalSection(&m_critSec);
1663         DebugPrintOut(L"StreamSink::IsMediaTypeSupported: HRESULT=%i\n", hr);
1664         return hr;
1665     }
1666 
1667 
1668     // Return the number of preferred media types.
GetMediaTypeCount(DWORD * pdwTypeCount)1669     STDMETHODIMP GetMediaTypeCount(DWORD *pdwTypeCount)
1670     {
1671         if (pdwTypeCount == nullptr)
1672         {
1673             return E_INVALIDARG;
1674         }
1675 
1676         EnterCriticalSection(&m_critSec);
1677 
1678         HRESULT hr = CheckShutdown();
1679 
1680         if (SUCCEEDED(hr))
1681         {
1682             // We've got only one media type
1683             *pdwTypeCount = 1;
1684         }
1685 
1686         LeaveCriticalSection(&m_critSec);
1687         DebugPrintOut(L"StreamSink::GetMediaTypeCount: HRESULT=%i\n", hr);
1688         return hr;
1689     }
1690 
1691 
1692     // Return a preferred media type by index.
GetMediaTypeByIndex(DWORD dwIndex,IMFMediaType ** ppType)1693     STDMETHODIMP GetMediaTypeByIndex(
1694         /* [in] */ DWORD dwIndex,
1695         /* [out] */ IMFMediaType **ppType)
1696     {
1697         if (ppType == NULL) {
1698             return E_INVALIDARG;
1699         }
1700 
1701         EnterCriticalSection(&m_critSec);
1702 
1703         HRESULT hr = CheckShutdown();
1704 
1705         if (dwIndex > 0)
1706         {
1707             hr = MF_E_NO_MORE_TYPES;
1708         } else {
1709             //return preferred type based on media capture library 6 elements preferred preview type
1710             //hr = m_spCurrentType.CopyTo(ppType);
1711             if (SUCCEEDED(hr)) {
1712                 _ComPtr<IMFMediaType> pType;
1713                 hr = MFCreateMediaType(ppType);
1714                 if (SUCCEEDED(hr)) {
1715                     hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
1716                 }
1717                 if (SUCCEEDED(hr)) {
1718                     hr = pType->LockStore();
1719                 }
1720                 bool bLocked = false;
1721                 if (SUCCEEDED(hr)) {
1722                     bLocked = true;
1723                     UINT32 uiCount;
1724                     UINT32 uiTotal;
1725                     hr = pType->GetCount(&uiTotal);
1726                     for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) {
1727                         GUID guid;
1728                         PROPVARIANT propval;
1729                         hr = pType->GetItemByIndex(uiCount, &guid, &propval);
1730                         if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO ||
1731                             guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) {
1732                             hr = (*ppType)->SetItem(guid, propval);
1733                             PropVariantClear(&propval);
1734                         }
1735                     }
1736                 }
1737                 if (bLocked) {
1738                     hr = pType->UnlockStore();
1739                 }
1740             }
1741         }
1742 
1743         LeaveCriticalSection(&m_critSec);
1744         DebugPrintOut(L"StreamSink::GetMediaTypeByIndex: HRESULT=%i\n", hr);
1745         return hr;
1746     }
1747 
1748 
1749     // Set the current media type.
SetCurrentMediaType(IMFMediaType * pMediaType)1750     STDMETHODIMP SetCurrentMediaType(IMFMediaType *pMediaType)
1751     {
1752         if (pMediaType == NULL) {
1753             return E_INVALIDARG;
1754         }
1755         EnterCriticalSection(&m_critSec);
1756 
1757         HRESULT hr = S_OK;
1758         if (m_state != State_TypeNotSet && m_state != State_Ready)
1759             hr = MF_E_INVALIDREQUEST;
1760         if (SUCCEEDED(hr))
1761             hr = CheckShutdown();
1762 
1763         // We don't allow format changes after streaming starts.
1764 
1765         // We set media type already
1766         if (m_state >= State_Ready)
1767         {
1768             if (SUCCEEDED(hr))
1769             {
1770                 hr = IsMediaTypeSupported(pMediaType, NULL);
1771             }
1772         }
1773 
1774         if (SUCCEEDED(hr))
1775         {
1776             hr = MFCreateMediaType(m_spCurrentType.ReleaseAndGetAddressOf());
1777             if (SUCCEEDED(hr))
1778             {
1779                 hr = pMediaType->CopyAllItems(m_spCurrentType.Get());
1780             }
1781             if (SUCCEEDED(hr))
1782             {
1783                 hr = m_spCurrentType->GetGUID(MF_MT_SUBTYPE, &m_guiCurrentSubtype);
1784             }
1785             GUID guid;
1786             if (SUCCEEDED(hr)) {
1787                 hr = m_spCurrentType->GetMajorType(&guid);
1788             }
1789             if (SUCCEEDED(hr) && guid == MFMediaType_Video) {
1790                 hr = MFGetAttributeSize(m_spCurrentType.Get(), MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels);
1791             }
1792             if (SUCCEEDED(hr))
1793             {
1794                 m_state = State_Ready;
1795             }
1796         }
1797 
1798         LeaveCriticalSection(&m_critSec);
1799         DebugPrintOut(L"StreamSink::SetCurrentMediaType: HRESULT=%i\n", hr);
1800         return hr;
1801     }
1802 
1803     // Return the current media type, if any.
GetCurrentMediaType(IMFMediaType ** ppMediaType)1804     STDMETHODIMP GetCurrentMediaType(IMFMediaType **ppMediaType)
1805     {
1806         if (ppMediaType == NULL) {
1807             return E_INVALIDARG;
1808         }
1809 
1810         EnterCriticalSection(&m_critSec);
1811 
1812         HRESULT hr = CheckShutdown();
1813 
1814         if (SUCCEEDED(hr)) {
1815             if (m_spCurrentType == nullptr) {
1816                 hr = MF_E_NOT_INITIALIZED;
1817             }
1818         }
1819 
1820         if (SUCCEEDED(hr)) {
1821             hr = m_spCurrentType.CopyTo(ppMediaType);
1822         }
1823 
1824         LeaveCriticalSection(&m_critSec);
1825         DebugPrintOut(L"StreamSink::GetCurrentMediaType: HRESULT=%i\n", hr);
1826         return hr;
1827     }
1828 
1829 
1830     // Return the major type GUID.
GetMajorType(GUID * pguidMajorType)1831     STDMETHODIMP GetMajorType(GUID *pguidMajorType)
1832     {
1833         HRESULT hr;
1834         if (pguidMajorType == nullptr) {
1835             return E_INVALIDARG;
1836         }
1837 
1838         _ComPtr<IMFMediaType> pType;
1839         hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
1840         if (SUCCEEDED(hr)) {
1841             hr = pType->GetMajorType(pguidMajorType);
1842         }
1843         DebugPrintOut(L"StreamSink::GetMajorType: HRESULT=%i\n", hr);
1844         return hr;
1845     }
1846 private:
1847 #ifdef WINRT
1848     EventRegistrationToken m_token;
1849 #else
1850     bool m_bConnected;
1851 #endif
1852 
1853     bool m_IsShutdown;                // Flag to indicate if Shutdown() method was called.
1854     CRITICAL_SECTION m_critSec;
1855 #ifndef WINRT
1856     long m_cRef;
1857 #endif
1858     IMFAttributes*        m_pParent;
1859     _ComPtr<IMFMediaType>        m_spCurrentType;
1860     _ComPtr<IMFMediaEventQueue>  m_spEventQueue;              // Event queue
1861 
1862     _ComPtr<IUnknown>            m_spFTM;
1863     State                       m_state;
1864     bool                        m_fGetStartTimeFromSample;
1865     bool                        m_fWaitingForFirstSample;
1866     MFTIME                      m_StartTime;                 // Presentation time when the clock started.
1867     GUID                        m_guiCurrentSubtype;
1868     UINT32                      m_imageWidthInPixels;
1869     UINT32                      m_imageHeightInPixels;
1870 };
1871 
1872 // Notes:
1873 //
1874 // The List class template implements a simple double-linked list.
1875 // It uses STL's copy semantics.
1876 
1877 // There are two versions of the Clear() method:
1878 //  Clear(void) clears the list w/out cleaning up the object.
1879 //  Clear(FN fn) takes a functor object that releases the objects, if they need cleanup.
1880 
1881 // The List class supports enumeration. Example of usage:
1882 //
1883 // List<T>::POSIITON pos = list.GetFrontPosition();
1884 // while (pos != list.GetEndPosition())
1885 // {
1886 //     T item;
1887 //     hr = list.GetItemPos(&item);
1888 //     pos = list.Next(pos);
1889 // }
1890 
1891 // The ComPtrList class template derives from List<> and implements a list of COM pointers.
1892 
1893 template <class T>
1894 struct NoOp
1895 {
operator ()NoOp1896     void operator()(T& /*t*/)
1897     {
1898     }
1899 };
1900 
1901 template <class T>
1902 class List
1903 {
1904 protected:
1905 
1906     // Nodes in the linked list
1907     struct Node
1908     {
1909         Node *prev;
1910         Node *next;
1911         T    item;
1912 
NodeList::Node1913         Node() : prev(nullptr), next(nullptr)
1914         {
1915         }
1916 
NodeList::Node1917         Node(T item) : prev(nullptr), next(nullptr)
1918         {
1919             this->item = item;
1920         }
1921 
ItemList::Node1922         T Item() const { return item; }
1923     };
1924 
1925 public:
1926 
1927     // Object for enumerating the list.
1928     class POSITION
1929     {
1930         friend class List<T>;
1931 
1932     public:
POSITION()1933         POSITION() : pNode(nullptr)
1934         {
1935         }
1936 
operator ==(const POSITION & p) const1937         bool operator==(const POSITION &p) const
1938         {
1939             return pNode == p.pNode;
1940         }
1941 
operator !=(const POSITION & p) const1942         bool operator!=(const POSITION &p) const
1943         {
1944             return pNode != p.pNode;
1945         }
1946 
1947     private:
1948         const Node *pNode;
1949 
POSITION(Node * p)1950         POSITION(Node *p) : pNode(p)
1951         {
1952         }
1953     };
1954 
1955 protected:
1956     Node    m_anchor;  // Anchor node for the linked list.
1957     DWORD   m_count;   // Number of items in the list.
1958 
Front() const1959     Node* Front() const
1960     {
1961         return m_anchor.next;
1962     }
1963 
Back() const1964     Node* Back() const
1965     {
1966         return m_anchor.prev;
1967     }
1968 
InsertAfter(T item,Node * pBefore)1969     virtual HRESULT InsertAfter(T item, Node *pBefore)
1970     {
1971         if (pBefore == nullptr)
1972         {
1973             return E_POINTER;
1974         }
1975 
1976         Node *pNode = new Node(item);
1977         if (pNode == nullptr)
1978         {
1979             return E_OUTOFMEMORY;
1980         }
1981 
1982         Node *pAfter = pBefore->next;
1983 
1984         pBefore->next = pNode;
1985         pAfter->prev = pNode;
1986 
1987         pNode->prev = pBefore;
1988         pNode->next = pAfter;
1989 
1990         m_count++;
1991 
1992         return S_OK;
1993     }
1994 
GetItem(const Node * pNode,T * ppItem)1995     virtual HRESULT GetItem(const Node *pNode, T* ppItem)
1996     {
1997         if (pNode == nullptr || ppItem == nullptr)
1998         {
1999             return E_POINTER;
2000         }
2001 
2002         *ppItem = pNode->item;
2003         return S_OK;
2004     }
2005 
2006     // RemoveItem:
2007     // Removes a node and optionally returns the item.
2008     // ppItem can be nullptr.
RemoveItem(Node * pNode,T * ppItem)2009     virtual HRESULT RemoveItem(Node *pNode, T *ppItem)
2010     {
2011         if (pNode == nullptr)
2012         {
2013             return E_POINTER;
2014         }
2015 
2016         assert(pNode != &m_anchor); // We should never try to remove the anchor node.
2017         if (pNode == &m_anchor)
2018         {
2019             return E_INVALIDARG;
2020         }
2021 
2022 
2023         T item;
2024 
2025         // The next node's previous is this node's previous.
2026         pNode->next->prev = pNode->prev;
2027 
2028         // The previous node's next is this node's next.
2029         pNode->prev->next = pNode->next;
2030 
2031         item = pNode->item;
2032         delete pNode;
2033 
2034         m_count--;
2035 
2036         if (ppItem)
2037         {
2038             *ppItem = item;
2039         }
2040 
2041         return S_OK;
2042     }
2043 
2044 public:
2045 
List()2046     List()
2047     {
2048         m_anchor.next = &m_anchor;
2049         m_anchor.prev = &m_anchor;
2050 
2051         m_count = 0;
2052     }
2053 
~List()2054     virtual ~List()
2055     {
2056         Clear();
2057     }
2058 
2059     // Insertion functions
InsertBack(T item)2060     HRESULT InsertBack(T item)
2061     {
2062         return InsertAfter(item, m_anchor.prev);
2063     }
2064 
2065 
InsertFront(T item)2066     HRESULT InsertFront(T item)
2067     {
2068         return InsertAfter(item, &m_anchor);
2069     }
2070 
InsertPos(POSITION pos,T item)2071     HRESULT InsertPos(POSITION pos, T item)
2072     {
2073         if (pos.pNode == nullptr)
2074         {
2075             return InsertBack(item);
2076         }
2077 
2078         return InsertAfter(item, pos.pNode->prev);
2079     }
2080 
2081     // RemoveBack: Removes the tail of the list and returns the value.
2082     // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
RemoveBack(T * ppItem)2083     HRESULT RemoveBack(T *ppItem)
2084     {
2085         if (IsEmpty())
2086         {
2087             return E_FAIL;
2088         }
2089         else
2090         {
2091             return RemoveItem(Back(), ppItem);
2092         }
2093     }
2094 
2095     // RemoveFront: Removes the head of the list and returns the value.
2096     // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
RemoveFront(T * ppItem)2097     HRESULT RemoveFront(T *ppItem)
2098     {
2099         if (IsEmpty())
2100         {
2101             return E_FAIL;
2102         }
2103         else
2104         {
2105             return RemoveItem(Front(), ppItem);
2106         }
2107     }
2108 
2109     // GetBack: Gets the tail item.
GetBack(T * ppItem)2110     HRESULT GetBack(T *ppItem)
2111     {
2112         if (IsEmpty())
2113         {
2114             return E_FAIL;
2115         }
2116         else
2117         {
2118             return GetItem(Back(), ppItem);
2119         }
2120     }
2121 
2122     // GetFront: Gets the front item.
GetFront(T * ppItem)2123     HRESULT GetFront(T *ppItem)
2124     {
2125         if (IsEmpty())
2126         {
2127             return E_FAIL;
2128         }
2129         else
2130         {
2131             return GetItem(Front(), ppItem);
2132         }
2133     }
2134 
2135 
2136     // GetCount: Returns the number of items in the list.
GetCount() const2137     DWORD GetCount() const { return m_count; }
2138 
IsEmpty() const2139     bool IsEmpty() const
2140     {
2141         return (GetCount() == 0);
2142     }
2143 
2144     // Clear: Takes a functor object whose operator()
2145     // frees the object on the list.
2146     template <class FN>
Clear(FN & clear_fn)2147     void Clear(FN& clear_fn)
2148     {
2149         Node *n = m_anchor.next;
2150 
2151         // Delete the nodes
2152         while (n != &m_anchor)
2153         {
2154             clear_fn(n->item);
2155 
2156             Node *tmp = n->next;
2157             delete n;
2158             n = tmp;
2159         }
2160 
2161         // Reset the anchor to point at itself
2162         m_anchor.next = &m_anchor;
2163         m_anchor.prev = &m_anchor;
2164 
2165         m_count = 0;
2166     }
2167 
2168     // Clear: Clears the list. (Does not delete or release the list items.)
Clear()2169     virtual void Clear()
2170     {
2171         NoOp<T> clearOp;
2172         Clear<>(clearOp);
2173     }
2174 
2175 
2176     // Enumerator functions
2177 
FrontPosition()2178     POSITION FrontPosition()
2179     {
2180         if (IsEmpty())
2181         {
2182             return POSITION(nullptr);
2183         }
2184         else
2185         {
2186             return POSITION(Front());
2187         }
2188     }
2189 
EndPosition() const2190     POSITION EndPosition() const
2191     {
2192         return POSITION();
2193     }
2194 
GetItemPos(POSITION pos,T * ppItem)2195     HRESULT GetItemPos(POSITION pos, T *ppItem)
2196     {
2197         if (pos.pNode)
2198         {
2199             return GetItem(pos.pNode, ppItem);
2200         }
2201         else
2202         {
2203             return E_FAIL;
2204         }
2205     }
2206 
Next(const POSITION pos)2207     POSITION Next(const POSITION pos)
2208     {
2209         if (pos.pNode && (pos.pNode->next != &m_anchor))
2210         {
2211             return POSITION(pos.pNode->next);
2212         }
2213         else
2214         {
2215             return POSITION(nullptr);
2216         }
2217     }
2218 
2219     // Remove an item at a position.
2220     // The item is returns in ppItem, unless ppItem is nullptr.
2221     // NOTE: This method invalidates the POSITION object.
Remove(POSITION & pos,T * ppItem)2222     HRESULT Remove(POSITION& pos, T *ppItem)
2223     {
2224         if (pos.pNode)
2225         {
2226             // Remove const-ness temporarily...
2227             Node *pNode = const_cast<Node*>(pos.pNode);
2228 
2229             pos = POSITION();
2230 
2231             return RemoveItem(pNode, ppItem);
2232         }
2233         else
2234         {
2235             return E_INVALIDARG;
2236         }
2237     }
2238 
2239 };
2240 
2241 
2242 
2243 // Typical functors for Clear method.
2244 
2245 // ComAutoRelease: Releases COM pointers.
2246 // MemDelete: Deletes pointers to new'd memory.
2247 
2248 class ComAutoRelease
2249 {
2250 public:
operator ()(IUnknown * p)2251     void operator()(IUnknown *p)
2252     {
2253         if (p)
2254         {
2255             p->Release();
2256         }
2257     }
2258 };
2259 
2260 class MemDelete
2261 {
2262 public:
operator ()(void * p)2263     void operator()(void *p)
2264     {
2265         if (p)
2266         {
2267             delete p;
2268         }
2269     }
2270 };
2271 
2272 
2273 // ComPtrList class
2274 // Derived class that makes it safer to store COM pointers in the List<> class.
2275 // It automatically AddRef's the pointers that are inserted onto the list
2276 // (unless the insertion method fails).
2277 //
2278 // T must be a COM interface type.
2279 // example: ComPtrList<IUnknown>
2280 //
2281 // NULLABLE: If true, client can insert nullptr pointers. This means GetItem can
2282 // succeed but return a nullptr pointer. By default, the list does not allow nullptr
2283 // pointers.
2284 
2285 #ifdef _MSC_VER
2286 #pragma warning(push)
2287 #pragma warning(disable: 4127) // constant expression
2288 #endif
2289 
2290 template <class T, bool NULLABLE = FALSE>
2291 class ComPtrList : public List<T*>
2292 {
2293 public:
2294 
2295     typedef T* Ptr;
2296 
Clear()2297     void Clear()
2298     {
2299         ComAutoRelease car;
2300         List<Ptr>::Clear(car);
2301     }
2302 
~ComPtrList()2303     ~ComPtrList()
2304     {
2305         Clear();
2306     }
2307 
2308 protected:
InsertAfter(Ptr item,Node * pBefore)2309     HRESULT InsertAfter(Ptr item, Node *pBefore)
2310     {
2311         // Do not allow nullptr item pointers unless NULLABLE is true.
2312         if (item == nullptr && !NULLABLE)
2313         {
2314             return E_POINTER;
2315         }
2316 
2317         if (item)
2318         {
2319             item->AddRef();
2320         }
2321 
2322         HRESULT hr = List<Ptr>::InsertAfter(item, pBefore);
2323         if (FAILED(hr) && item != nullptr)
2324         {
2325             item->Release();
2326         }
2327         return hr;
2328     }
2329 
GetItem(const Node * pNode,Ptr * ppItem)2330     HRESULT GetItem(const Node *pNode, Ptr* ppItem)
2331     {
2332         Ptr pItem = nullptr;
2333 
2334         // The base class gives us the pointer without AddRef'ing it.
2335         // If we return the pointer to the caller, we must AddRef().
2336         HRESULT hr = List<Ptr>::GetItem(pNode, &pItem);
2337         if (SUCCEEDED(hr))
2338         {
2339             assert(pItem || NULLABLE);
2340             if (pItem)
2341             {
2342                 *ppItem = pItem;
2343                 (*ppItem)->AddRef();
2344             }
2345         }
2346         return hr;
2347     }
2348 
RemoveItem(Node * pNode,Ptr * ppItem)2349     HRESULT RemoveItem(Node *pNode, Ptr *ppItem)
2350     {
2351         // ppItem can be nullptr, but we need to get the
2352         // item so that we can release it.
2353 
2354         // If ppItem is not nullptr, we will AddRef it on the way out.
2355 
2356         Ptr pItem = nullptr;
2357 
2358         HRESULT hr = List<Ptr>::RemoveItem(pNode, &pItem);
2359 
2360         if (SUCCEEDED(hr))
2361         {
2362             assert(pItem || NULLABLE);
2363             if (ppItem && pItem)
2364             {
2365                 *ppItem = pItem;
2366                 (*ppItem)->AddRef();
2367             }
2368 
2369             if (pItem)
2370             {
2371                 pItem->Release();
2372                 pItem = nullptr;
2373             }
2374         }
2375 
2376         return hr;
2377     }
2378 };
2379 
2380 #ifdef _MSC_VER
2381 #pragma warning(pop)
2382 #endif
2383 
2384 /* Be sure to declare webcam device capability in manifest
2385   For better media capture support, add the following snippet with correct module name to the project manifest
2386     (videoio needs DLL activation class factoryentry points):
2387   <Extensions>
2388     <Extension Category="windows.activatableClass.inProcessServer">
2389       <InProcessServer>
2390         <Path>modulename</Path>
2391         <ActivatableClass ActivatableClassId="cv.MediaSink" ThreadingModel="both" />
2392       </InProcessServer>
2393     </Extension>
2394   </Extensions>*/
2395 
2396 extern const __declspec(selectany) WCHAR RuntimeClass_CV_MediaSink[] = L"cv.MediaSink";
2397 
2398 class MediaSink :
2399 #ifdef WINRT
2400     public Microsoft::WRL::RuntimeClass<
2401     Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
2402     Microsoft::WRL::Implements<ABI::Windows::Media::IMediaExtension>,
2403     IMFMediaSink,
2404     IMFClockStateSink,
2405     Microsoft::WRL::FtmBase,
2406     CBaseAttributes<>>
2407 #else
2408     public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<>
2409 #endif
2410 {
2411 #ifdef WINRT
2412     InspectableClass(RuntimeClass_CV_MediaSink, BaseTrust)
2413 public:
2414 #else
2415 public:
2416     ULONG STDMETHODCALLTYPE AddRef()
2417     {
2418         return InterlockedIncrement(&m_cRef);
2419     }
2420     ULONG STDMETHODCALLTYPE Release()
2421     {
2422         ULONG cRef = InterlockedDecrement(&m_cRef);
2423         if (cRef == 0)
2424         {
2425             delete this;
2426         }
2427         return cRef;
2428     }
2429 #if defined(_MSC_VER) && _MSC_VER >= 1700  // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012
2430     STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv)
2431 #else
2432     STDMETHOD(QueryInterface)(REFIID riid, void **ppv)
2433 #endif
2434     {
2435         if (ppv == nullptr) {
2436             return E_POINTER;
2437         }
2438         (*ppv) = nullptr;
2439         HRESULT hr = S_OK;
2440         if (riid == IID_IUnknown ||
2441             riid == IID_IMFMediaSink) {
2442             (*ppv) = static_cast<IMFMediaSink*>(this);
2443             AddRef();
2444         } else if (riid == IID_IMFClockStateSink) {
2445             (*ppv) = static_cast<IMFClockStateSink*>(this);
2446             AddRef();
2447         } else if (riid == IID_IMFAttributes) {
2448             (*ppv) = static_cast<IMFAttributes*>(this);
2449             AddRef();
2450         } else {
2451             hr = E_NOINTERFACE;
2452         }
2453 
2454         return hr;
2455     }
2456 #endif
MediaSink()2457     MediaSink() : m_IsShutdown(false), m_llStartTime(0) {
2458         CBaseAttributes<>::Initialize(0U);
2459         InitializeCriticalSectionEx(&m_critSec, 3000, 0);
2460         DebugPrintOut(L"MediaSink::MediaSink\n");
2461     }
2462 
~MediaSink()2463     virtual ~MediaSink() {
2464         DebugPrintOut(L"MediaSink::~MediaSink\n");
2465         DeleteCriticalSection(&m_critSec);
2466         assert(m_IsShutdown);
2467     }
CheckShutdown() const2468     HRESULT CheckShutdown() const
2469     {
2470         if (m_IsShutdown)
2471         {
2472             return MF_E_SHUTDOWN;
2473         }
2474         else
2475         {
2476             return S_OK;
2477         }
2478     }
2479 #ifdef WINRT
SetProperties(ABI::Windows::Foundation::Collections::IPropertySet * pConfiguration)2480     STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
2481     {
2482         HRESULT hr = S_OK;
2483         if (pConfiguration) {
2484             Microsoft::WRL::ComPtr<IInspectable> spInsp;
2485             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> spSetting;
2486             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropVal;
2487             Microsoft::WRL::ComPtr<ABI::Windows::Media::MediaProperties::IMediaEncodingProperties> pMedEncProps;
2488             UINT32 uiType = ABI::Windows::Media::Capture::MediaStreamType_VideoPreview;
2489 
2490             hr = pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
2491             if (FAILED(hr)) {
2492                 hr = E_FAIL;
2493             }
2494 
2495             if (SUCCEEDED(hr)) {
2496                 hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_SAMPLEGRABBERCALLBACK).Get(), spInsp.ReleaseAndGetAddressOf());
2497                 if (FAILED(hr)) {
2498                     hr = E_INVALIDARG;
2499                 }
2500                 if (SUCCEEDED(hr)) {
2501                     hr = SetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, spInsp.Get());
2502                 }
2503             }
2504             if (SUCCEEDED(hr)) {
2505                 hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDTYPE).Get(), spInsp.ReleaseAndGetAddressOf());
2506                 if (FAILED(hr)) {
2507                     hr = E_INVALIDARG;
2508                 }
2509                 if (SUCCEEDED(hr)) {
2510                     if (SUCCEEDED(hr = spInsp.As(&spPropVal))) {
2511                         hr = spPropVal->GetUInt32(&uiType);
2512                     }
2513                 }
2514             }
2515             if (SUCCEEDED(hr)) {
2516                 hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDENCPROPS).Get(), spInsp.ReleaseAndGetAddressOf());
2517                 if (FAILED(hr)) {
2518                     hr = E_INVALIDARG;
2519                 }
2520                 if (SUCCEEDED(hr)) {
2521                     hr = spInsp.As(&pMedEncProps);
2522                 }
2523             }
2524             if (SUCCEEDED(hr)) {
2525                 hr = SetMediaStreamProperties((ABI::Windows::Media::Capture::MediaStreamType)uiType, pMedEncProps.Get());
2526             }
2527         }
2528 
2529         return hr;
2530     }
GetStreamId(ABI::Windows::Media::Capture::MediaStreamType mediaStreamType)2531     static DWORD GetStreamId(ABI::Windows::Media::Capture::MediaStreamType mediaStreamType)
2532     {
2533         return 3 - mediaStreamType;
2534     }
AddAttribute(_In_ GUID guidKey,_In_ ABI::Windows::Foundation::IPropertyValue * pValue,_In_ IMFAttributes * pAttr)2535     static HRESULT AddAttribute(_In_ GUID guidKey, _In_ ABI::Windows::Foundation::IPropertyValue *pValue, _In_ IMFAttributes* pAttr)
2536     {
2537         HRESULT hr = S_OK;
2538         PROPVARIANT var;
2539         ABI::Windows::Foundation::PropertyType type;
2540         hr = pValue->get_Type(&type);
2541         ZeroMemory(&var, sizeof(var));
2542 
2543         if (SUCCEEDED(hr))
2544         {
2545             switch (type)
2546             {
2547             case ABI::Windows::Foundation::PropertyType_UInt8Array:
2548             {
2549                                                                       UINT32 cbBlob;
2550                                                                       BYTE *pbBlog = nullptr;
2551                                                                       hr = pValue->GetUInt8Array(&cbBlob, &pbBlog);
2552                                                                       if (SUCCEEDED(hr))
2553                                                                       {
2554                                                                           if (pbBlog == nullptr)
2555                                                                           {
2556                                                                               hr = E_INVALIDARG;
2557                                                                           }
2558                                                                           else
2559                                                                           {
2560                                                                               hr = pAttr->SetBlob(guidKey, pbBlog, cbBlob);
2561                                                                           }
2562                                                                       }
2563                                                                       CoTaskMemFree(pbBlog);
2564             }
2565                 break;
2566 
2567             case ABI::Windows::Foundation::PropertyType_Double:
2568             {
2569                                                                   DOUBLE value;
2570                                                                   hr = pValue->GetDouble(&value);
2571                                                                   if (SUCCEEDED(hr))
2572                                                                   {
2573                                                                       hr = pAttr->SetDouble(guidKey, value);
2574                                                                   }
2575             }
2576                 break;
2577 
2578             case ABI::Windows::Foundation::PropertyType_Guid:
2579             {
2580                                                                 GUID value;
2581                                                                 hr = pValue->GetGuid(&value);
2582                                                                 if (SUCCEEDED(hr))
2583                                                                 {
2584                                                                     hr = pAttr->SetGUID(guidKey, value);
2585                                                                 }
2586             }
2587                 break;
2588 
2589             case ABI::Windows::Foundation::PropertyType_String:
2590             {
2591                         Microsoft::WRL::Wrappers::HString value;
2592                         hr = pValue->GetString(value.GetAddressOf());
2593                                                                   if (SUCCEEDED(hr))
2594                                                                   {
2595                                                                       UINT32 len = 0;
2596                             LPCWSTR szValue = WindowsGetStringRawBuffer(value.Get(), &len);
2597                                                                       hr = pAttr->SetString(guidKey, szValue);
2598                                                                   }
2599             }
2600                 break;
2601 
2602             case ABI::Windows::Foundation::PropertyType_UInt32:
2603             {
2604                                                                   UINT32 value;
2605                                                                   hr = pValue->GetUInt32(&value);
2606                                                                   if (SUCCEEDED(hr))
2607                                                                   {
2608                                                                       pAttr->SetUINT32(guidKey, value);
2609                                                                   }
2610             }
2611                 break;
2612 
2613             case ABI::Windows::Foundation::PropertyType_UInt64:
2614             {
2615                                                                   UINT64 value;
2616                                                                   hr = pValue->GetUInt64(&value);
2617                                                                   if (SUCCEEDED(hr))
2618                                                                   {
2619                                                                       hr = pAttr->SetUINT64(guidKey, value);
2620                                                                   }
2621             }
2622                 break;
2623 
2624             case ABI::Windows::Foundation::PropertyType_Inspectable:
2625             {
2626                                                                        Microsoft::WRL::ComPtr<IInspectable> value;
2627                                                                        hr = TYPE_E_TYPEMISMATCH;
2628                                                                        if (SUCCEEDED(hr))
2629                                                                        {
2630                                                                            pAttr->SetUnknown(guidKey, value.Get());
2631                                                                        }
2632             }
2633                 break;
2634 
2635                 // ignore unknown values
2636             }
2637         }
2638 
2639         return hr;
2640     }
ConvertPropertiesToMediaType(_In_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties * pMEP,_Outptr_ IMFMediaType ** ppMT)2641     static HRESULT ConvertPropertiesToMediaType(_In_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *pMEP, _Outptr_ IMFMediaType **ppMT)
2642     {
2643         HRESULT hr = S_OK;
2644         _ComPtr<IMFMediaType> spMT;
2645         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<GUID, IInspectable*>> spMap;
2646         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*>*>> spIterable;
2647         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IIterator<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*>*>> spIterator;
2648 
2649         if (pMEP == nullptr || ppMT == nullptr)
2650         {
2651             return E_INVALIDARG;
2652         }
2653         *ppMT = nullptr;
2654 
2655                 hr = pMEP->get_Properties(spMap.GetAddressOf());
2656 
2657         if (SUCCEEDED(hr))
2658         {
2659             hr = spMap.As(&spIterable);
2660         }
2661         if (SUCCEEDED(hr))
2662         {
2663             hr = spIterable->First(&spIterator);
2664         }
2665         if (SUCCEEDED(hr))
2666         {
2667             MFCreateMediaType(spMT.ReleaseAndGetAddressOf());
2668         }
2669 
2670         boolean hasCurrent = false;
2671         if (SUCCEEDED(hr))
2672         {
2673             hr = spIterator->get_HasCurrent(&hasCurrent);
2674         }
2675 
2676         while (hasCurrent)
2677         {
2678             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*> > spKeyValuePair;
2679             Microsoft::WRL::ComPtr<IInspectable> spValue;
2680             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropValue;
2681             GUID guidKey;
2682 
2683             hr = spIterator->get_Current(&spKeyValuePair);
2684             if (FAILED(hr))
2685             {
2686                 break;
2687             }
2688             hr = spKeyValuePair->get_Key(&guidKey);
2689             if (FAILED(hr))
2690             {
2691                 break;
2692             }
2693             hr = spKeyValuePair->get_Value(&spValue);
2694             if (FAILED(hr))
2695             {
2696                 break;
2697             }
2698             hr = spValue.As(&spPropValue);
2699             if (FAILED(hr))
2700             {
2701                 break;
2702             }
2703             hr = AddAttribute(guidKey, spPropValue.Get(), spMT.Get());
2704             if (FAILED(hr))
2705             {
2706                 break;
2707             }
2708 
2709             hr = spIterator->MoveNext(&hasCurrent);
2710             if (FAILED(hr))
2711             {
2712                 break;
2713             }
2714         }
2715 
2716 
2717         if (SUCCEEDED(hr))
2718         {
2719             Microsoft::WRL::ComPtr<IInspectable> spValue;
2720             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropValue;
2721             GUID guiMajorType;
2722 
2723             hr = spMap->Lookup(MF_MT_MAJOR_TYPE, spValue.GetAddressOf());
2724 
2725             if (SUCCEEDED(hr))
2726             {
2727                 hr = spValue.As(&spPropValue);
2728             }
2729             if (SUCCEEDED(hr))
2730             {
2731                 hr = spPropValue->GetGuid(&guiMajorType);
2732             }
2733             if (SUCCEEDED(hr))
2734             {
2735                 if (guiMajorType != MFMediaType_Video && guiMajorType != MFMediaType_Audio)
2736                 {
2737                     hr = E_UNEXPECTED;
2738                 }
2739             }
2740         }
2741 
2742         if (SUCCEEDED(hr))
2743         {
2744             *ppMT = spMT.Detach();
2745         }
2746 
2747         return hr;
2748     }
2749             //this should be passed through SetProperties!
SetMediaStreamProperties(ABI::Windows::Media::Capture::MediaStreamType MediaStreamType,_In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties * mediaEncodingProperties)2750             HRESULT SetMediaStreamProperties(ABI::Windows::Media::Capture::MediaStreamType MediaStreamType,
2751         _In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *mediaEncodingProperties)
2752     {
2753         HRESULT hr = S_OK;
2754         _ComPtr<IMFMediaType> spMediaType;
2755 
2756         if (MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoPreview &&
2757             MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoRecord &&
2758             MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_Audio)
2759         {
2760             return E_INVALIDARG;
2761         }
2762 
2763         RemoveStreamSink(GetStreamId(MediaStreamType));
2764 
2765         if (mediaEncodingProperties != nullptr)
2766         {
2767             _ComPtr<IMFStreamSink> spStreamSink;
2768             hr = ConvertPropertiesToMediaType(mediaEncodingProperties, &spMediaType);
2769             if (SUCCEEDED(hr))
2770             {
2771                 hr = AddStreamSink(GetStreamId(MediaStreamType), nullptr, spStreamSink.GetAddressOf());
2772             }
2773             if (SUCCEEDED(hr)) {
2774                 hr = SetUnknown(MF_MEDIASINK_PREFERREDTYPE, spMediaType.Detach());
2775             }
2776         }
2777 
2778         return hr;
2779     }
2780 #endif
2781     //IMFMediaSink
GetCharacteristics(__RPC__out DWORD * pdwCharacteristics)2782     HRESULT STDMETHODCALLTYPE GetCharacteristics(
2783         /* [out] */ __RPC__out DWORD *pdwCharacteristics) {
2784         HRESULT hr;
2785         if (pdwCharacteristics == NULL) return E_INVALIDARG;
2786         EnterCriticalSection(&m_critSec);
2787         if (SUCCEEDED(hr = CheckShutdown())) {
2788                     //if had an activation object for the sink, shut down would be managed and MF_STREAM_SINK_SUPPORTS_ROTATION appears to be setable to TRUE
2789                     *pdwCharacteristics = MEDIASINK_FIXED_STREAMS;// | MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE;
2790         }
2791         LeaveCriticalSection(&m_critSec);
2792         DebugPrintOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr);
2793         return hr;
2794     }
2795 
AddStreamSink(DWORD dwStreamSinkIdentifier,IMFMediaType *,IMFStreamSink ** ppStreamSink)2796     HRESULT STDMETHODCALLTYPE AddStreamSink(
2797         DWORD dwStreamSinkIdentifier, IMFMediaType * /*pMediaType*/, IMFStreamSink **ppStreamSink) {
2798         _ComPtr<IMFStreamSink> spMFStream;
2799         _ComPtr<ICustomStreamSink> pStream;
2800         EnterCriticalSection(&m_critSec);
2801         HRESULT hr = CheckShutdown();
2802 
2803         if (SUCCEEDED(hr))
2804         {
2805             hr = GetStreamSinkById(dwStreamSinkIdentifier, &spMFStream);
2806         }
2807 
2808         if (SUCCEEDED(hr))
2809         {
2810             hr = MF_E_STREAMSINK_EXISTS;
2811         }
2812         else
2813         {
2814             hr = S_OK;
2815         }
2816 
2817         if (SUCCEEDED(hr))
2818         {
2819 #ifdef WINRT
2820             pStream = Microsoft::WRL::Make<StreamSink>();
2821             if (pStream == nullptr) {
2822                 hr = E_OUTOFMEMORY;
2823             }
2824             if (SUCCEEDED(hr))
2825                 hr = pStream.As<IMFStreamSink>(&spMFStream);
2826 #else
2827             StreamSink* pSink = new StreamSink();
2828             if (pSink) {
2829                 hr = pSink->QueryInterface(IID_IMFStreamSink, (void**)spMFStream.GetAddressOf());
2830                 if (SUCCEEDED(hr)) {
2831                     hr = spMFStream.As(&pStream);
2832                 }
2833                 if (FAILED(hr)) delete pSink;
2834             }
2835 #endif
2836         }
2837 
2838         // Initialize the stream.
2839         _ComPtr<IMFAttributes> pAttr;
2840         if (SUCCEEDED(hr)) {
2841             hr = pStream.As(&pAttr);
2842         }
2843         if (SUCCEEDED(hr)) {
2844             hr = pAttr->SetUINT32(MF_STREAMSINK_ID, dwStreamSinkIdentifier);
2845             if (SUCCEEDED(hr)) {
2846                 hr = pAttr->SetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, (IMFMediaSink*)this);
2847             }
2848         }
2849         if (SUCCEEDED(hr)) {
2850             hr = pStream->Initialize();
2851         }
2852 
2853         if (SUCCEEDED(hr))
2854         {
2855             ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
2856             ComPtrList<IMFStreamSink>::POSITION posEnd = m_streams.EndPosition();
2857 
2858             // Insert in proper position
2859             for (; pos != posEnd; pos = m_streams.Next(pos))
2860             {
2861                 DWORD dwCurrId;
2862                 _ComPtr<IMFStreamSink> spCurr;
2863                 hr = m_streams.GetItemPos(pos, &spCurr);
2864                 if (FAILED(hr))
2865                 {
2866                     break;
2867                 }
2868                 hr = spCurr->GetIdentifier(&dwCurrId);
2869                 if (FAILED(hr))
2870                 {
2871                     break;
2872                 }
2873 
2874                 if (dwCurrId > dwStreamSinkIdentifier)
2875                 {
2876                     break;
2877                 }
2878             }
2879 
2880             if (SUCCEEDED(hr))
2881             {
2882                 hr = m_streams.InsertPos(pos, spMFStream.Get());
2883             }
2884         }
2885 
2886         if (SUCCEEDED(hr))
2887         {
2888             *ppStreamSink = spMFStream.Detach();
2889         }
2890         LeaveCriticalSection(&m_critSec);
2891         DebugPrintOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr);
2892         return hr;
2893     }
2894 
RemoveStreamSink(DWORD dwStreamSinkIdentifier)2895     HRESULT STDMETHODCALLTYPE RemoveStreamSink(DWORD dwStreamSinkIdentifier) {
2896         EnterCriticalSection(&m_critSec);
2897         HRESULT hr = CheckShutdown();
2898         ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
2899         ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
2900         _ComPtr<IMFStreamSink> spStream;
2901 
2902         if (SUCCEEDED(hr))
2903         {
2904             for (; pos != endPos; pos = m_streams.Next(pos))
2905             {
2906                 hr = m_streams.GetItemPos(pos, &spStream);
2907                 DWORD dwId;
2908 
2909                 if (FAILED(hr))
2910                 {
2911                     break;
2912                 }
2913 
2914                 hr = spStream->GetIdentifier(&dwId);
2915                 if (FAILED(hr) || dwId == dwStreamSinkIdentifier)
2916                 {
2917                     break;
2918                 }
2919             }
2920 
2921             if (pos == endPos)
2922             {
2923                 hr = MF_E_INVALIDSTREAMNUMBER;
2924             }
2925         }
2926 
2927         if (SUCCEEDED(hr))
2928         {
2929             hr = m_streams.Remove(pos, nullptr);
2930                     _ComPtr<ICustomStreamSink> spCustomSink;
2931 #ifdef WINRT
2932                     spCustomSink = static_cast<StreamSink*>(spStream.Get());
2933                     hr = S_OK;
2934 #else
2935                     hr = spStream.As(&spCustomSink);
2936 #endif
2937                     if (SUCCEEDED(hr))
2938                         hr = spCustomSink->Shutdown();
2939         }
2940         LeaveCriticalSection(&m_critSec);
2941         DebugPrintOut(L"MediaSink::RemoveStreamSink: HRESULT=%i\n", hr);
2942         return hr;
2943     }
2944 
GetStreamSinkCount(DWORD * pStreamSinkCount)2945     HRESULT STDMETHODCALLTYPE GetStreamSinkCount(DWORD *pStreamSinkCount) {
2946         if (pStreamSinkCount == NULL)
2947         {
2948             return E_INVALIDARG;
2949         }
2950 
2951         EnterCriticalSection(&m_critSec);
2952 
2953         HRESULT hr = CheckShutdown();
2954 
2955         if (SUCCEEDED(hr))
2956         {
2957             *pStreamSinkCount = m_streams.GetCount();
2958         }
2959 
2960         LeaveCriticalSection(&m_critSec);
2961         DebugPrintOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr);
2962         return hr;
2963     }
2964 
GetStreamSinkByIndex(DWORD dwIndex,IMFStreamSink ** ppStreamSink)2965     HRESULT STDMETHODCALLTYPE GetStreamSinkByIndex(
2966         DWORD dwIndex, IMFStreamSink **ppStreamSink) {
2967         if (ppStreamSink == NULL)
2968         {
2969             return E_INVALIDARG;
2970         }
2971 
2972         _ComPtr<IMFStreamSink> spStream;
2973         EnterCriticalSection(&m_critSec);
2974         DWORD cStreams = m_streams.GetCount();
2975 
2976         if (dwIndex >= cStreams)
2977         {
2978             return MF_E_INVALIDINDEX;
2979         }
2980 
2981         HRESULT hr = CheckShutdown();
2982 
2983         if (SUCCEEDED(hr))
2984         {
2985             ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
2986             ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
2987             DWORD dwCurrent = 0;
2988 
2989             for (; pos != endPos && dwCurrent < dwIndex; pos = m_streams.Next(pos), ++dwCurrent)
2990             {
2991                 // Just move to proper position
2992             }
2993 
2994             if (pos == endPos)
2995             {
2996                 hr = MF_E_UNEXPECTED;
2997             }
2998             else
2999             {
3000                 hr = m_streams.GetItemPos(pos, &spStream);
3001             }
3002         }
3003 
3004         if (SUCCEEDED(hr))
3005         {
3006             *ppStreamSink = spStream.Detach();
3007         }
3008         LeaveCriticalSection(&m_critSec);
3009         DebugPrintOut(L"MediaSink::GetStreamSinkByIndex: HRESULT=%i\n", hr);
3010         return hr;
3011     }
3012 
GetStreamSinkById(DWORD dwStreamSinkIdentifier,IMFStreamSink ** ppStreamSink)3013     HRESULT STDMETHODCALLTYPE GetStreamSinkById(
3014         DWORD dwStreamSinkIdentifier, IMFStreamSink **ppStreamSink) {
3015         if (ppStreamSink == NULL)
3016         {
3017             return E_INVALIDARG;
3018         }
3019 
3020         EnterCriticalSection(&m_critSec);
3021         HRESULT hr = CheckShutdown();
3022         _ComPtr<IMFStreamSink> spResult;
3023 
3024         if (SUCCEEDED(hr))
3025         {
3026             ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
3027             ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
3028 
3029             for (; pos != endPos; pos = m_streams.Next(pos))
3030             {
3031                 _ComPtr<IMFStreamSink> spStream;
3032                 hr = m_streams.GetItemPos(pos, &spStream);
3033                 DWORD dwId;
3034 
3035                 if (FAILED(hr))
3036                 {
3037                     break;
3038                 }
3039 
3040                 hr = spStream->GetIdentifier(&dwId);
3041                 if (FAILED(hr))
3042                 {
3043                     break;
3044                 }
3045                 else if (dwId == dwStreamSinkIdentifier)
3046                 {
3047                     spResult = spStream;
3048                     break;
3049                 }
3050             }
3051 
3052             if (pos == endPos)
3053             {
3054                 hr = MF_E_INVALIDSTREAMNUMBER;
3055             }
3056         }
3057 
3058         if (SUCCEEDED(hr))
3059         {
3060             assert(spResult);
3061             *ppStreamSink = spResult.Detach();
3062         }
3063         LeaveCriticalSection(&m_critSec);
3064         DebugPrintOut(L"MediaSink::GetStreamSinkById: HRESULT=%i\n", hr);
3065         return hr;
3066     }
3067 
SetPresentationClock(IMFPresentationClock * pPresentationClock)3068     HRESULT STDMETHODCALLTYPE SetPresentationClock(
3069         IMFPresentationClock *pPresentationClock) {
3070         EnterCriticalSection(&m_critSec);
3071 
3072         HRESULT hr = CheckShutdown();
3073 
3074         // If we already have a clock, remove ourselves from that clock's
3075         // state notifications.
3076         if (SUCCEEDED(hr)) {
3077             if (m_spClock) {
3078                 hr = m_spClock->RemoveClockStateSink(this);
3079             }
3080         }
3081 
3082         // Register ourselves to get state notifications from the new clock.
3083         if (SUCCEEDED(hr)) {
3084             if (pPresentationClock) {
3085                 hr = pPresentationClock->AddClockStateSink(this);
3086             }
3087         }
3088 
3089         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
3090         if (SUCCEEDED(hr)) {
3091             // Release the pointer to the old clock.
3092             // Store the pointer to the new clock.
3093             m_spClock = pPresentationClock;
3094             hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
3095         }
3096         LeaveCriticalSection(&m_critSec);
3097         if (SUCCEEDED(hr))
3098             hr = pSampleCallback->OnSetPresentationClock(pPresentationClock);
3099         DebugPrintOut(L"MediaSink::SetPresentationClock: HRESULT=%i\n", hr);
3100         return hr;
3101     }
3102 
GetPresentationClock(IMFPresentationClock ** ppPresentationClock)3103     HRESULT STDMETHODCALLTYPE GetPresentationClock(
3104         IMFPresentationClock **ppPresentationClock) {
3105         if (ppPresentationClock == NULL) {
3106             return E_INVALIDARG;
3107         }
3108 
3109         EnterCriticalSection(&m_critSec);
3110 
3111         HRESULT hr = CheckShutdown();
3112 
3113         if (SUCCEEDED(hr)) {
3114             if (!m_spClock) {
3115                 hr = MF_E_NO_CLOCK; // There is no presentation clock.
3116             } else {
3117                 // Return the pointer to the caller.
3118                 hr = m_spClock.CopyTo(ppPresentationClock);
3119             }
3120         }
3121         LeaveCriticalSection(&m_critSec);
3122         DebugPrintOut(L"MediaSink::GetPresentationClock: HRESULT=%i\n", hr);
3123         return hr;
3124     }
3125 
Shutdown(void)3126     HRESULT STDMETHODCALLTYPE Shutdown(void) {
3127         EnterCriticalSection(&m_critSec);
3128 
3129         HRESULT hr = CheckShutdown();
3130 
3131         if (SUCCEEDED(hr)) {
3132             ForEach(m_streams, ShutdownFunc());
3133             m_streams.Clear();
3134             m_spClock.ReleaseAndGetAddressOf();
3135 
3136                     _ComPtr<IMFMediaType> pType;
3137                     hr = CBaseAttributes<>::GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)pType.GetAddressOf());
3138                     if (SUCCEEDED(hr)) {
3139             hr = DeleteItem(MF_MEDIASINK_PREFERREDTYPE);
3140                     }
3141             m_IsShutdown = true;
3142         }
3143 
3144         LeaveCriticalSection(&m_critSec);
3145         DebugPrintOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr);
3146         return hr;
3147     }
3148     class ShutdownFunc
3149     {
3150     public:
operator ()(IMFStreamSink * pStream) const3151         HRESULT operator()(IMFStreamSink *pStream) const
3152         {
3153                     _ComPtr<ICustomStreamSink> spCustomSink;
3154                     HRESULT hr;
3155 #ifdef WINRT
3156                     spCustomSink = static_cast<StreamSink*>(pStream);
3157 #else
3158                     hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf()));
3159                     if (FAILED(hr)) return hr;
3160 #endif
3161                     hr = spCustomSink->Shutdown();
3162                     return hr;
3163         }
3164     };
3165 
3166     class StartFunc
3167     {
3168     public:
StartFunc(LONGLONG llStartTime)3169         StartFunc(LONGLONG llStartTime)
3170             : _llStartTime(llStartTime)
3171         {
3172         }
3173 
operator ()(IMFStreamSink * pStream) const3174         HRESULT operator()(IMFStreamSink *pStream) const
3175         {
3176                     _ComPtr<ICustomStreamSink> spCustomSink;
3177                     HRESULT hr;
3178 #ifdef WINRT
3179                     spCustomSink = static_cast<StreamSink*>(pStream);
3180 #else
3181                     hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf()));
3182                     if (FAILED(hr)) return hr;
3183 #endif
3184                     hr = spCustomSink->Start(_llStartTime);
3185                     return hr;
3186         }
3187 
3188         LONGLONG _llStartTime;
3189     };
3190 
3191     class StopFunc
3192     {
3193     public:
operator ()(IMFStreamSink * pStream) const3194         HRESULT operator()(IMFStreamSink *pStream) const
3195         {
3196                     _ComPtr<ICustomStreamSink> spCustomSink;
3197                     HRESULT hr;
3198 #ifdef WINRT
3199                     spCustomSink = static_cast<StreamSink*>(pStream);
3200 #else
3201                     hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf()));
3202                     if (FAILED(hr)) return hr;
3203 #endif
3204                     hr = spCustomSink->Stop();
3205                     return hr;
3206         }
3207     };
3208 
3209     template <class T, class TFunc>
ForEach(ComPtrList<T> & col,TFunc fn)3210     HRESULT ForEach(ComPtrList<T> &col, TFunc fn)
3211     {
3212         ComPtrList<T>::POSITION pos = col.FrontPosition();
3213         ComPtrList<T>::POSITION endPos = col.EndPosition();
3214         HRESULT hr = S_OK;
3215 
3216         for (; pos != endPos; pos = col.Next(pos))
3217         {
3218             _ComPtr<T> spStream;
3219 
3220             hr = col.GetItemPos(pos, &spStream);
3221             if (FAILED(hr))
3222             {
3223                 break;
3224             }
3225 
3226             hr = fn(spStream.Get());
3227         }
3228 
3229         return hr;
3230     }
3231     //IMFClockStateSink
OnClockStart(MFTIME hnsSystemTime,LONGLONG llClockStartOffset)3232     HRESULT STDMETHODCALLTYPE OnClockStart(
3233         MFTIME hnsSystemTime,
3234         LONGLONG llClockStartOffset) {
3235         EnterCriticalSection(&m_critSec);
3236         HRESULT hr = CheckShutdown();
3237 
3238         if (SUCCEEDED(hr))
3239         {
3240             // Start each stream.
3241             m_llStartTime = llClockStartOffset;
3242             hr = ForEach(m_streams, StartFunc(llClockStartOffset));
3243         }
3244         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
3245         if (SUCCEEDED(hr))
3246             hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
3247         LeaveCriticalSection(&m_critSec);
3248         if (SUCCEEDED(hr))
3249             hr = pSampleCallback->OnClockStart(hnsSystemTime, llClockStartOffset);
3250         DebugPrintOut(L"MediaSink::OnClockStart: HRESULT=%i\n", hr);
3251         return hr;
3252     }
3253 
OnClockStop(MFTIME hnsSystemTime)3254     HRESULT STDMETHODCALLTYPE OnClockStop(
3255         MFTIME hnsSystemTime) {
3256         EnterCriticalSection(&m_critSec);
3257         HRESULT hr = CheckShutdown();
3258 
3259         if (SUCCEEDED(hr))
3260         {
3261             // Stop each stream
3262             hr = ForEach(m_streams, StopFunc());
3263         }
3264         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
3265         if (SUCCEEDED(hr))
3266             hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
3267         LeaveCriticalSection(&m_critSec);
3268         if (SUCCEEDED(hr))
3269             hr = pSampleCallback->OnClockStop(hnsSystemTime);
3270         DebugPrintOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr);
3271         return hr;
3272     }
3273 
OnClockPause(MFTIME hnsSystemTime)3274     HRESULT STDMETHODCALLTYPE OnClockPause(
3275         MFTIME hnsSystemTime) {
3276         HRESULT hr;
3277         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
3278         hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
3279         if (SUCCEEDED(hr))
3280             hr = pSampleCallback->OnClockPause(hnsSystemTime);
3281         DebugPrintOut(L"MediaSink::OnClockPause: HRESULT=%i\n", hr);
3282         return hr;
3283     }
3284 
OnClockRestart(MFTIME hnsSystemTime)3285     HRESULT STDMETHODCALLTYPE OnClockRestart(
3286         MFTIME hnsSystemTime) {
3287            HRESULT hr;
3288         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
3289         hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
3290         if (SUCCEEDED(hr))
3291             hr = pSampleCallback->OnClockRestart(hnsSystemTime);
3292         DebugPrintOut(L"MediaSink::OnClockRestart: HRESULT=%i\n", hr);
3293         return hr;
3294     }
3295 
OnClockSetRate(MFTIME hnsSystemTime,float flRate)3296     HRESULT STDMETHODCALLTYPE OnClockSetRate(
3297         MFTIME hnsSystemTime,
3298         float flRate) {
3299            HRESULT hr;
3300         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
3301         hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
3302         if (SUCCEEDED(hr))
3303             hr = pSampleCallback->OnClockSetRate(hnsSystemTime, flRate);
3304         DebugPrintOut(L"MediaSink::OnClockSetRate: HRESULT=%i\n", hr);
3305         return hr;
3306     }
3307 private:
3308 #ifndef WINRT
3309     long m_cRef;
3310 #endif
3311     CRITICAL_SECTION            m_critSec;
3312     bool                        m_IsShutdown;
3313     ComPtrList<IMFStreamSink>    m_streams;
3314     _ComPtr<IMFPresentationClock>    m_spClock;
3315     LONGLONG                        m_llStartTime;
3316 };
3317 
3318 #ifdef WINRT
3319 ActivatableClass(MediaSink);
3320 #endif
3321