1 /* 2 * Implementation of IAMMultiMediaStream Interface 3 * 4 * Copyright 2004, 2012 Christian Costa 5 * Copyright 2006 Ivan Leo Puoti 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "wine/debug.h" 23 24 #define COBJMACROS 25 26 #include "winbase.h" 27 #include "wingdi.h" 28 29 #include "amstream_private.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(amstream); 32 33 typedef struct { 34 IAMMultiMediaStream IAMMultiMediaStream_iface; 35 LONG ref; 36 IGraphBuilder* pFilterGraph; 37 IMediaSeeking* media_seeking; 38 IMediaControl* media_control; 39 IMediaStreamFilter *media_stream_filter; 40 IPin* ipin; 41 ULONG nbStreams; 42 IAMMediaStream **pStreams; 43 STREAM_TYPE StreamType; 44 OAEVENT event; 45 } IAMMultiMediaStreamImpl; 46 47 static inline IAMMultiMediaStreamImpl *impl_from_IAMMultiMediaStream(IAMMultiMediaStream *iface) 48 { 49 return CONTAINING_RECORD(iface, IAMMultiMediaStreamImpl, IAMMultiMediaStream_iface); 50 } 51 52 static const struct IAMMultiMediaStreamVtbl AM_Vtbl; 53 54 HRESULT AM_create(IUnknown *pUnkOuter, LPVOID *ppObj) 55 { 56 IAMMultiMediaStreamImpl* object; 57 58 TRACE("(%p,%p)\n", pUnkOuter, ppObj); 59 60 if( pUnkOuter ) 61 return CLASS_E_NOAGGREGATION; 62 63 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAMMultiMediaStreamImpl)); 64 if (!object) 65 return E_OUTOFMEMORY; 66 67 object->IAMMultiMediaStream_iface.lpVtbl = &AM_Vtbl; 68 object->ref = 1; 69 70 *ppObj = &object->IAMMultiMediaStream_iface; 71 72 return S_OK; 73 } 74 75 /*** IUnknown methods ***/ 76 static HRESULT WINAPI IAMMultiMediaStreamImpl_QueryInterface(IAMMultiMediaStream* iface, REFIID riid, void** ppvObject) 77 { 78 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 79 80 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject); 81 82 if (IsEqualGUID(riid, &IID_IUnknown) || 83 IsEqualGUID(riid, &IID_IMultiMediaStream) || 84 IsEqualGUID(riid, &IID_IAMMultiMediaStream)) 85 { 86 IAMMultiMediaStream_AddRef(iface); 87 *ppvObject = iface; 88 return S_OK; 89 } 90 91 ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject); 92 93 return E_NOINTERFACE; 94 } 95 96 static ULONG WINAPI IAMMultiMediaStreamImpl_AddRef(IAMMultiMediaStream* iface) 97 { 98 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 99 100 TRACE("(%p/%p)\n", iface, This); 101 102 return InterlockedIncrement(&This->ref); 103 } 104 105 static ULONG WINAPI IAMMultiMediaStreamImpl_Release(IAMMultiMediaStream* iface) 106 { 107 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 108 ULONG ref = InterlockedDecrement(&This->ref); 109 ULONG i; 110 111 TRACE("(%p/%p)\n", iface, This); 112 113 if (!ref) 114 { 115 for(i = 0; i < This->nbStreams; i++) 116 IAMMediaStream_Release(This->pStreams[i]); 117 CoTaskMemFree(This->pStreams); 118 if (This->ipin) 119 IPin_Release(This->ipin); 120 if (This->media_stream_filter) 121 IMediaStreamFilter_Release(This->media_stream_filter); 122 if (This->media_seeking) 123 IMediaSeeking_Release(This->media_seeking); 124 if (This->media_control) 125 IMediaControl_Release(This->media_control); 126 if (This->pFilterGraph) 127 IGraphBuilder_Release(This->pFilterGraph); 128 HeapFree(GetProcessHeap(), 0, This); 129 } 130 131 return ref; 132 } 133 134 /*** IMultiMediaStream methods ***/ 135 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetInformation(IAMMultiMediaStream* iface, DWORD* pdwFlags, STREAM_TYPE* pStreamType) 136 { 137 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 138 139 FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pdwFlags, pStreamType); 140 141 return E_NOTIMPL; 142 } 143 144 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetMediaStream(IAMMultiMediaStream* iface, REFMSPID idPurpose, IMediaStream** ppMediaStream) 145 { 146 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 147 MSPID PurposeId; 148 unsigned int i; 149 150 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_guid(idPurpose), ppMediaStream); 151 152 for (i = 0; i < This->nbStreams; i++) 153 { 154 IAMMediaStream_GetInformation(This->pStreams[i], &PurposeId, NULL); 155 if (IsEqualIID(&PurposeId, idPurpose)) 156 { 157 *ppMediaStream = (IMediaStream*)This->pStreams[i]; 158 IMediaStream_AddRef(*ppMediaStream); 159 return S_OK; 160 } 161 } 162 163 return MS_E_NOSTREAM; 164 } 165 166 static HRESULT WINAPI IAMMultiMediaStreamImpl_EnumMediaStreams(IAMMultiMediaStream* iface, LONG Index, IMediaStream** ppMediaStream) 167 { 168 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 169 170 FIXME("(%p/%p)->(%d,%p) stub!\n", This, iface, Index, ppMediaStream); 171 172 return E_NOTIMPL; 173 } 174 175 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetState(IAMMultiMediaStream* iface, STREAM_STATE* pCurrentState) 176 { 177 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 178 179 FIXME("(%p/%p)->(%p) stub!\n", This, iface, pCurrentState); 180 181 return E_NOTIMPL; 182 } 183 184 static HRESULT WINAPI IAMMultiMediaStreamImpl_SetState(IAMMultiMediaStream* iface, STREAM_STATE new_state) 185 { 186 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 187 HRESULT hr = E_INVALIDARG; 188 189 TRACE("(%p/%p)->(%u)\n", This, iface, new_state); 190 191 if (new_state == STREAMSTATE_RUN) 192 hr = IMediaControl_Run(This->media_control); 193 else if (new_state == STREAMSTATE_STOP) 194 hr = IMediaControl_Stop(This->media_control); 195 196 return hr; 197 } 198 199 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetTime(IAMMultiMediaStream* iface, STREAM_TIME* pCurrentTime) 200 { 201 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 202 203 FIXME("(%p/%p)->(%p) stub!\n", This, iface, pCurrentTime); 204 205 return E_NOTIMPL; 206 } 207 208 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetDuration(IAMMultiMediaStream* iface, STREAM_TIME* pDuration) 209 { 210 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 211 212 FIXME("(%p/%p)->(%p) stub!\n", This, iface, pDuration); 213 214 return E_NOTIMPL; 215 } 216 217 static HRESULT WINAPI IAMMultiMediaStreamImpl_Seek(IAMMultiMediaStream* iface, STREAM_TIME seek_time) 218 { 219 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 220 221 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(seek_time)); 222 223 return IMediaSeeking_SetPositions(This->media_seeking, &seek_time, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning); 224 } 225 226 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetEndOfStream(IAMMultiMediaStream* iface, HANDLE* phEOS) 227 { 228 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 229 230 FIXME("(%p/%p)->(%p) stub!\n", This, iface, phEOS); 231 232 return E_NOTIMPL; 233 } 234 235 /*** IAMMultiMediaStream methods ***/ 236 static HRESULT WINAPI IAMMultiMediaStreamImpl_Initialize(IAMMultiMediaStream* iface, STREAM_TYPE StreamType, DWORD dwFlags, IGraphBuilder* pFilterGraph) 237 { 238 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 239 HRESULT hr = S_OK; 240 const WCHAR filternameW[] = {'M','e','d','i','a','S','t','r','e','a','m','F','i','l','t','e','r',0}; 241 242 TRACE("(%p/%p)->(%x,%x,%p)\n", This, iface, (DWORD)StreamType, dwFlags, pFilterGraph); 243 244 if (pFilterGraph) 245 { 246 This->pFilterGraph = pFilterGraph; 247 IGraphBuilder_AddRef(This->pFilterGraph); 248 } 249 else 250 { 251 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&This->pFilterGraph); 252 } 253 254 if (SUCCEEDED(hr)) 255 { 256 This->StreamType = StreamType; 257 hr = IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IMediaSeeking, (void**)&This->media_seeking); 258 if (SUCCEEDED(hr)) 259 hr = IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IMediaControl, (void**)&This->media_control); 260 if (SUCCEEDED(hr)) 261 hr = CoCreateInstance(&CLSID_MediaStreamFilter, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaStreamFilter, (void**)&This->media_stream_filter); 262 if (SUCCEEDED(hr)) 263 hr = IGraphBuilder_AddFilter(This->pFilterGraph, (IBaseFilter*)This->media_stream_filter, filternameW); 264 if (SUCCEEDED(hr)) 265 { 266 IMediaEventEx* media_event = NULL; 267 hr = IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IMediaEventEx, (void**)&media_event); 268 if (SUCCEEDED(hr)) 269 hr = IMediaEventEx_GetEventHandle(media_event, &This->event); 270 if (SUCCEEDED(hr)) 271 hr = IMediaEventEx_SetNotifyFlags(media_event, AM_MEDIAEVENT_NONOTIFY); 272 if (media_event) 273 IMediaEventEx_Release(media_event); 274 } 275 } 276 277 if (FAILED(hr)) 278 { 279 if (This->media_stream_filter) 280 IMediaStreamFilter_Release(This->media_stream_filter); 281 This->media_stream_filter = NULL; 282 if (This->media_seeking) 283 IMediaSeeking_Release(This->media_seeking); 284 This->media_seeking = NULL; 285 if (This->media_control) 286 IMediaControl_Release(This->media_control); 287 This->media_control = NULL; 288 if (This->pFilterGraph) 289 IGraphBuilder_Release(This->pFilterGraph); 290 This->pFilterGraph = NULL; 291 } 292 293 return hr; 294 } 295 296 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetFilterGraph(IAMMultiMediaStream* iface, IGraphBuilder** ppGraphBuilder) 297 { 298 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 299 300 TRACE("(%p/%p)->(%p)\n", This, iface, ppGraphBuilder); 301 302 if (!ppGraphBuilder) 303 return E_POINTER; 304 305 if (This->pFilterGraph) 306 return IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IGraphBuilder, (void**)ppGraphBuilder); 307 else 308 *ppGraphBuilder = NULL; 309 310 return S_OK; 311 } 312 313 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetFilter(IAMMultiMediaStream* iface, IMediaStreamFilter** ppFilter) 314 { 315 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 316 317 TRACE("(%p/%p)->(%p)\n", This, iface, ppFilter); 318 319 if (!ppFilter) 320 return E_POINTER; 321 322 *ppFilter = This->media_stream_filter; 323 if (*ppFilter) 324 IMediaStreamFilter_AddRef(*ppFilter); 325 326 return S_OK; 327 } 328 329 static HRESULT WINAPI IAMMultiMediaStreamImpl_AddMediaStream(IAMMultiMediaStream* iface, IUnknown* stream_object, const MSPID* PurposeId, 330 DWORD dwFlags, IMediaStream** ppNewStream) 331 { 332 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 333 HRESULT hr; 334 IAMMediaStream* pStream; 335 IAMMediaStream** pNewStreams; 336 337 TRACE("(%p/%p)->(%p,%s,%x,%p)\n", This, iface, stream_object, debugstr_guid(PurposeId), dwFlags, ppNewStream); 338 339 if (!IsEqualGUID(PurposeId, &MSPID_PrimaryVideo) && !IsEqualGUID(PurposeId, &MSPID_PrimaryAudio)) 340 return MS_E_PURPOSEID; 341 342 if (stream_object) 343 FIXME("Specifying a stream object in params is not yet supported\n"); 344 345 if (dwFlags & AMMSF_ADDDEFAULTRENDERER) 346 { 347 if (IsEqualGUID(PurposeId, &MSPID_PrimaryVideo)) 348 { 349 /* Default renderer not supported by video stream */ 350 return MS_E_PURPOSEID; 351 } 352 else 353 { 354 IBaseFilter* dsoundrender_filter; 355 356 /* Create the default renderer for audio */ 357 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&dsoundrender_filter); 358 if (SUCCEEDED(hr)) 359 { 360 hr = IGraphBuilder_AddFilter(This->pFilterGraph, dsoundrender_filter, NULL); 361 IBaseFilter_Release(dsoundrender_filter); 362 } 363 364 /* No media stream created when the default renderer is used */ 365 return hr; 366 } 367 } 368 369 if (IsEqualGUID(PurposeId, &MSPID_PrimaryVideo)) 370 hr = ddrawmediastream_create((IMultiMediaStream*)iface, PurposeId, This->StreamType, &pStream); 371 else 372 hr = audiomediastream_create((IMultiMediaStream*)iface, PurposeId, This->StreamType, &pStream); 373 if (SUCCEEDED(hr)) 374 { 375 pNewStreams = CoTaskMemRealloc(This->pStreams, (This->nbStreams+1) * sizeof(IAMMediaStream*)); 376 if (!pNewStreams) 377 { 378 IAMMediaStream_Release(pStream); 379 return E_OUTOFMEMORY; 380 } 381 This->pStreams = pNewStreams; 382 This->pStreams[This->nbStreams] = pStream; 383 This->nbStreams++; 384 385 if (ppNewStream) 386 *ppNewStream = (IMediaStream*)pStream; 387 } 388 389 if (SUCCEEDED(hr)) 390 { 391 /* Add stream to the media stream filter */ 392 IMediaStreamFilter_AddMediaStream(This->media_stream_filter, pStream); 393 } 394 395 return hr; 396 } 397 398 static HRESULT WINAPI IAMMultiMediaStreamImpl_OpenFile(IAMMultiMediaStream* iface, LPCWSTR filename, DWORD flags) 399 { 400 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 401 HRESULT ret = S_OK; 402 IBaseFilter *BaseFilter = NULL; 403 IEnumPins *EnumPins = NULL; 404 IPin *ipin; 405 PIN_DIRECTION pin_direction; 406 const WCHAR sourceW[] = {'S','o','u','r','c','e',0}; 407 408 TRACE("(%p/%p)->(%s,%x)\n", This, iface, debugstr_w(filename), flags); 409 410 if (!filename) 411 return E_POINTER; 412 413 /* If Initialize was not called before, we do it here */ 414 if (!This->pFilterGraph) 415 ret = IAMMultiMediaStream_Initialize(iface, STREAMTYPE_READ, 0, NULL); 416 417 if (SUCCEEDED(ret)) 418 ret = IGraphBuilder_AddSourceFilter(This->pFilterGraph, filename, sourceW, &BaseFilter); 419 420 if (SUCCEEDED(ret)) 421 ret = IBaseFilter_EnumPins(BaseFilter, &EnumPins); 422 423 if (SUCCEEDED(ret)) 424 ret = IEnumPins_Next(EnumPins, 1, &ipin, NULL); 425 426 if (SUCCEEDED(ret)) 427 { 428 ret = IPin_QueryDirection(ipin, &pin_direction); 429 if (ret == S_OK && pin_direction == PINDIR_OUTPUT) 430 This->ipin = ipin; 431 } 432 433 if (SUCCEEDED(ret) && !(flags & AMMSF_NORENDER)) 434 ret = IGraphBuilder_Render(This->pFilterGraph, This->ipin); 435 436 if (EnumPins) 437 IEnumPins_Release(EnumPins); 438 if (BaseFilter) 439 IBaseFilter_Release(BaseFilter); 440 return ret; 441 } 442 443 static HRESULT WINAPI IAMMultiMediaStreamImpl_OpenMoniker(IAMMultiMediaStream* iface, IBindCtx* pCtx, IMoniker* pMoniker, DWORD dwFlags) 444 { 445 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 446 447 FIXME("(%p/%p)->(%p,%p,%x) stub!\n", This, iface, pCtx, pMoniker, dwFlags); 448 449 return E_NOTIMPL; 450 } 451 452 static HRESULT WINAPI IAMMultiMediaStreamImpl_Render(IAMMultiMediaStream* iface, DWORD dwFlags) 453 { 454 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface); 455 456 FIXME("(%p/%p)->(%x) partial stub!\n", This, iface, dwFlags); 457 458 if(dwFlags != AMMSF_NOCLOCK) 459 return E_INVALIDARG; 460 461 return IGraphBuilder_Render(This->pFilterGraph, This->ipin); 462 } 463 464 static const IAMMultiMediaStreamVtbl AM_Vtbl = 465 { 466 IAMMultiMediaStreamImpl_QueryInterface, 467 IAMMultiMediaStreamImpl_AddRef, 468 IAMMultiMediaStreamImpl_Release, 469 IAMMultiMediaStreamImpl_GetInformation, 470 IAMMultiMediaStreamImpl_GetMediaStream, 471 IAMMultiMediaStreamImpl_EnumMediaStreams, 472 IAMMultiMediaStreamImpl_GetState, 473 IAMMultiMediaStreamImpl_SetState, 474 IAMMultiMediaStreamImpl_GetTime, 475 IAMMultiMediaStreamImpl_GetDuration, 476 IAMMultiMediaStreamImpl_Seek, 477 IAMMultiMediaStreamImpl_GetEndOfStream, 478 IAMMultiMediaStreamImpl_Initialize, 479 IAMMultiMediaStreamImpl_GetFilterGraph, 480 IAMMultiMediaStreamImpl_GetFilter, 481 IAMMultiMediaStreamImpl_AddMediaStream, 482 IAMMultiMediaStreamImpl_OpenFile, 483 IAMMultiMediaStreamImpl_OpenMoniker, 484 IAMMultiMediaStreamImpl_Render 485 }; 486