1 /* DirectShow Sample Grabber object (QEDIT.DLL) 2 * 3 * Copyright 2009 Paul Chitescu 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <assert.h> 21 #include <stdarg.h> 22 23 #define COBJMACROS 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winuser.h" 28 #include "ole2.h" 29 30 #include "qedit_private.h" 31 #include "wine/debug.h" 32 #include "wine/strmbase.h" 33 34 WINE_DEFAULT_DEBUG_CHANNEL(qedit); 35 36 static const WCHAR vendor_name[] = { 'W', 'i', 'n', 'e', 0 }; 37 static const WCHAR pin_in_name[] = { 'I', 'n', 0 }; 38 static const WCHAR pin_out_name[] = { 'O', 'u', 't', 0 }; 39 40 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype, BOOL past); 41 42 /* Single media type enumerator */ 43 typedef struct _ME_Impl { 44 IEnumMediaTypes IEnumMediaTypes_iface; 45 LONG refCount; 46 BOOL past; 47 AM_MEDIA_TYPE mtype; 48 } ME_Impl; 49 50 51 /* IEnumMediaTypes interface implementation */ 52 53 static inline ME_Impl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface) 54 { 55 return CONTAINING_RECORD(iface, ME_Impl, IEnumMediaTypes_iface); 56 } 57 58 static HRESULT WINAPI Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, 59 void **ret_iface) 60 { 61 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 62 63 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ret_iface); 64 65 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumMediaTypes)) { 66 *ret_iface = iface; 67 IEnumMediaTypes_AddRef(iface); 68 return S_OK; 69 } 70 *ret_iface = NULL; 71 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ret_iface); 72 return E_NOINTERFACE; 73 } 74 75 static ULONG WINAPI Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface) 76 { 77 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 78 ULONG refCount = InterlockedIncrement(&This->refCount); 79 80 TRACE("(%p) new ref = %u\n", This, refCount); 81 return refCount; 82 } 83 84 static ULONG WINAPI Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface) 85 { 86 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 87 ULONG refCount = InterlockedDecrement(&This->refCount); 88 89 TRACE("(%p) new ref = %u\n", This, refCount); 90 if (refCount == 0) 91 { 92 CoTaskMemFree(This->mtype.pbFormat); 93 CoTaskMemFree(This); 94 } 95 return refCount; 96 } 97 98 /* IEnumMediaTypes */ 99 static HRESULT WINAPI Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes, 100 AM_MEDIA_TYPE **types, ULONG *fetched) 101 { 102 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 103 ULONG count = 0; 104 105 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched); 106 if (!nTypes) 107 return E_INVALIDARG; 108 if (!types || ((nTypes != 1) && !fetched)) 109 return E_POINTER; 110 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) { 111 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); 112 *mtype = This->mtype; 113 if (mtype->cbFormat) { 114 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat); 115 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat); 116 } 117 *types = mtype; 118 This->past = TRUE; 119 count = 1; 120 } 121 if (fetched) 122 *fetched = count; 123 return (count == nTypes) ? S_OK : S_FALSE; 124 } 125 126 static HRESULT WINAPI Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes) 127 { 128 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 129 130 TRACE("(%p)->(%u)\n", This, nTypes); 131 if (nTypes) 132 This->past = TRUE; 133 return This->past ? S_FALSE : S_OK; 134 } 135 136 static HRESULT WINAPI Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface) 137 { 138 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 139 140 TRACE("(%p)->()\n", This); 141 This->past = FALSE; 142 return S_OK; 143 } 144 145 static HRESULT WINAPI Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me) 146 { 147 ME_Impl *This = impl_from_IEnumMediaTypes(iface); 148 149 TRACE("(%p)->(%p)\n", This, me); 150 if (!me) 151 return E_POINTER; 152 *me = mediaenum_create(&This->mtype, This->past); 153 if (!*me) 154 return E_OUTOFMEMORY; 155 return S_OK; 156 } 157 158 159 /* Virtual tables and constructor */ 160 161 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable = 162 { 163 Single_IEnumMediaTypes_QueryInterface, 164 Single_IEnumMediaTypes_AddRef, 165 Single_IEnumMediaTypes_Release, 166 Single_IEnumMediaTypes_Next, 167 Single_IEnumMediaTypes_Skip, 168 Single_IEnumMediaTypes_Reset, 169 Single_IEnumMediaTypes_Clone, 170 }; 171 172 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype, BOOL past) 173 { 174 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl)); 175 176 if (!obj) 177 return NULL; 178 ZeroMemory(obj, sizeof(*obj)); 179 obj->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypes_VTable; 180 obj->refCount = 1; 181 obj->past = past; 182 if (mtype) { 183 obj->mtype = *mtype; 184 obj->mtype.pUnk = NULL; 185 if (mtype->cbFormat) { 186 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat); 187 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat); 188 } 189 else 190 obj->mtype.pbFormat = NULL; 191 } 192 else 193 obj->mtype.majortype = GUID_NULL; 194 195 return &obj->IEnumMediaTypes_iface; 196 } 197 198 199 /* Sample Grabber pin implementation */ 200 typedef struct _SG_Pin { 201 IPin IPin_iface; 202 PIN_DIRECTION dir; 203 WCHAR const *name; 204 struct _SG_Impl *sg; 205 IPin *pair; 206 } SG_Pin; 207 208 static inline SG_Pin *impl_from_IPin(IPin *iface) 209 { 210 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface); 211 } 212 213 /* Sample Grabber filter implementation */ 214 typedef struct _SG_Impl { 215 IUnknown IUnknown_inner; 216 BaseFilter filter; 217 ISampleGrabber ISampleGrabber_iface; 218 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */ 219 IUnknown* seekthru_unk; 220 IUnknown *outer_unk; 221 AM_MEDIA_TYPE mtype; 222 SG_Pin pin_in; 223 SG_Pin pin_out; 224 IMemInputPin IMemInputPin_iface; 225 IMemAllocator *allocator; 226 IMemInputPin *memOutput; 227 ISampleGrabberCB *grabberIface; 228 LONG grabberMethod; 229 LONG oneShot; 230 LONG bufferLen; 231 void* bufferData; 232 } SG_Impl; 233 234 enum { 235 OneShot_None, 236 OneShot_Wait, 237 OneShot_Past, 238 }; 239 240 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface) 241 { 242 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner); 243 } 244 245 static inline SG_Impl *impl_from_BaseFilter(BaseFilter *iface) 246 { 247 return CONTAINING_RECORD(iface, SG_Impl, filter); 248 } 249 250 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface) 251 { 252 return CONTAINING_RECORD(iface, SG_Impl, filter.IBaseFilter_iface); 253 } 254 255 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface) 256 { 257 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface); 258 } 259 260 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface) 261 { 262 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface); 263 } 264 265 266 /* Cleanup at end of life */ 267 static void SampleGrabber_cleanup(SG_Impl *This) 268 { 269 TRACE("(%p)\n", This); 270 if (This->filter.filterInfo.pGraph) 271 WARN("(%p) still joined to filter graph %p\n", This, This->filter.filterInfo.pGraph); 272 if (This->allocator) 273 IMemAllocator_Release(This->allocator); 274 if (This->memOutput) 275 IMemInputPin_Release(This->memOutput); 276 if (This->grabberIface) 277 ISampleGrabberCB_Release(This->grabberIface); 278 CoTaskMemFree(This->mtype.pbFormat); 279 CoTaskMemFree(This->bufferData); 280 if(This->seekthru_unk) 281 IUnknown_Release(This->seekthru_unk); 282 } 283 284 /* SampleGrabber inner IUnknown */ 285 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 286 { 287 SG_Impl *This = impl_from_IUnknown(iface); 288 289 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 290 291 *ppv = NULL; 292 if (IsEqualIID(riid, &IID_IUnknown)) 293 *ppv = &This->IUnknown_inner; 294 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) || 295 IsEqualIID(riid, &IID_IBaseFilter)) 296 *ppv = &This->filter.IBaseFilter_iface; 297 else if (IsEqualIID(riid, &IID_ISampleGrabber)) 298 *ppv = &This->ISampleGrabber_iface; 299 else if (IsEqualIID(riid, &IID_IMediaPosition)) 300 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv); 301 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 302 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv); 303 else 304 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv); 305 306 if (!*ppv) 307 return E_NOINTERFACE; 308 309 IUnknown_AddRef((IUnknown*)*ppv); 310 return S_OK; 311 } 312 313 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface) 314 { 315 SG_Impl *This = impl_from_IUnknown(iface); 316 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface); 317 318 TRACE("(%p) ref=%d\n", This, ref); 319 320 return ref; 321 } 322 323 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface) 324 { 325 SG_Impl *This = impl_from_IUnknown(iface); 326 ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface); 327 328 TRACE("(%p) ref=%d\n", This, ref); 329 330 if (ref == 0) 331 { 332 SampleGrabber_cleanup(This); 333 CoTaskMemFree(This); 334 } 335 return ref; 336 } 337 338 static const IUnknownVtbl samplegrabber_vtbl = 339 { 340 SampleGrabber_QueryInterface, 341 SampleGrabber_AddRef, 342 SampleGrabber_Release, 343 }; 344 345 static IPin *WINAPI SampleGrabber_GetPin(BaseFilter *iface, int pos) 346 { 347 SG_Impl *This = impl_from_BaseFilter(iface); 348 IPin *pin; 349 350 if (pos == 0) 351 pin = &This->pin_in.IPin_iface; 352 else if (pos == 1) 353 pin = &This->pin_out.IPin_iface; 354 else 355 return NULL; 356 357 IPin_AddRef(pin); 358 return pin; 359 } 360 361 static LONG WINAPI SampleGrabber_GetPinCount(BaseFilter *iface) 362 { 363 return 2; 364 } 365 366 static const BaseFilterFuncTable basefunc_vtbl = { 367 SampleGrabber_GetPin, 368 SampleGrabber_GetPinCount 369 }; 370 371 /* Helper that buffers data and/or calls installed sample callbacks */ 372 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample) 373 { 374 double time = 0.0; 375 REFERENCE_TIME tStart, tEnd; 376 if (This->bufferLen >= 0) { 377 BYTE *data = 0; 378 LONG size = IMediaSample_GetActualDataLength(sample); 379 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) { 380 if (!data) 381 size = 0; 382 EnterCriticalSection(&This->filter.csFilter); 383 if (This->bufferLen != size) { 384 CoTaskMemFree(This->bufferData); 385 This->bufferData = size ? CoTaskMemAlloc(size) : NULL; 386 This->bufferLen = size; 387 } 388 if (size) 389 CopyMemory(This->bufferData, data, size); 390 LeaveCriticalSection(&This->filter.csFilter); 391 } 392 } 393 if (!This->grabberIface) 394 return; 395 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd))) 396 time = 1e-7 * tStart; 397 switch (This->grabberMethod) { 398 case 0: 399 { 400 ULONG ref = IMediaSample_AddRef(sample); 401 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample); 402 ref = IMediaSample_Release(sample) + 1 - ref; 403 if (ref) 404 { 405 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref); 406 /* ugly as hell but some apps are sooo buggy */ 407 while (ref--) 408 IMediaSample_Release(sample); 409 } 410 } 411 break; 412 case 1: 413 { 414 BYTE *data = 0; 415 LONG size = IMediaSample_GetActualDataLength(sample); 416 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data) 417 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size); 418 } 419 break; 420 case -1: 421 break; 422 default: 423 FIXME("unsupported method %d\n", This->grabberMethod); 424 /* do not bother us again */ 425 This->grabberMethod = -1; 426 } 427 } 428 429 430 /* SampleGrabber implementation of IBaseFilter interface */ 431 432 /* IUnknown */ 433 static HRESULT WINAPI 434 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) 435 { 436 SG_Impl *This = impl_from_IBaseFilter(iface); 437 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 438 } 439 440 /* IUnknown */ 441 static ULONG WINAPI 442 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface) 443 { 444 SG_Impl *This = impl_from_IBaseFilter(iface); 445 return IUnknown_AddRef(This->outer_unk); 446 } 447 448 /* IUnknown */ 449 static ULONG WINAPI 450 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface) 451 { 452 SG_Impl *This = impl_from_IBaseFilter(iface); 453 return IUnknown_Release(This->outer_unk); 454 } 455 456 /* IMediaFilter */ 457 static HRESULT WINAPI 458 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface) 459 { 460 SG_Impl *This = impl_from_IBaseFilter(iface); 461 TRACE("(%p)\n", This); 462 This->filter.state = State_Stopped; 463 return S_OK; 464 } 465 466 /* IMediaFilter */ 467 static HRESULT WINAPI 468 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface) 469 { 470 SG_Impl *This = impl_from_IBaseFilter(iface); 471 TRACE("(%p)\n", This); 472 This->filter.state = State_Paused; 473 return S_OK; 474 } 475 476 /* IMediaFilter */ 477 static HRESULT WINAPI 478 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart) 479 { 480 SG_Impl *This = impl_from_IBaseFilter(iface); 481 TRACE("(%p)\n", This); 482 This->filter.state = State_Running; 483 return S_OK; 484 } 485 486 /* IBaseFilter */ 487 static HRESULT WINAPI 488 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin) 489 { 490 SG_Impl *This = impl_from_IBaseFilter(iface); 491 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin); 492 if (!id || !pin) 493 return E_POINTER; 494 if (!lstrcmpiW(id,pin_in_name)) 495 { 496 *pin = &This->pin_in.IPin_iface; 497 IPin_AddRef(*pin); 498 return S_OK; 499 } 500 else if (!lstrcmpiW(id,pin_out_name)) 501 { 502 *pin = &This->pin_out.IPin_iface; 503 IPin_AddRef(*pin); 504 return S_OK; 505 } 506 *pin = NULL; 507 return VFW_E_NOT_FOUND; 508 } 509 510 /* IBaseFilter */ 511 static HRESULT WINAPI 512 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name) 513 { 514 SG_Impl *This = impl_from_IBaseFilter(iface); 515 516 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name)); 517 518 BaseFilterImpl_JoinFilterGraph(iface, graph, name); 519 This->oneShot = OneShot_None; 520 521 return S_OK; 522 } 523 524 /* IBaseFilter */ 525 static HRESULT WINAPI 526 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor) 527 { 528 TRACE("(%p)\n", vendor); 529 if (!vendor) 530 return E_POINTER; 531 *vendor = CoTaskMemAlloc(sizeof(vendor_name)); 532 CopyMemory(*vendor, vendor_name, sizeof(vendor_name)); 533 return S_OK; 534 } 535 536 537 /* SampleGrabber implementation of ISampleGrabber interface */ 538 539 /* IUnknown */ 540 static HRESULT WINAPI 541 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv) 542 { 543 SG_Impl *This = impl_from_ISampleGrabber(iface); 544 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 545 } 546 547 /* IUnknown */ 548 static ULONG WINAPI 549 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface) 550 { 551 SG_Impl *This = impl_from_ISampleGrabber(iface); 552 return IUnknown_AddRef(This->outer_unk); 553 } 554 555 /* IUnknown */ 556 static ULONG WINAPI 557 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface) 558 { 559 SG_Impl *This = impl_from_ISampleGrabber(iface); 560 return IUnknown_Release(This->outer_unk); 561 } 562 563 /* ISampleGrabber */ 564 static HRESULT WINAPI 565 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot) 566 { 567 SG_Impl *This = impl_from_ISampleGrabber(iface); 568 TRACE("(%p)->(%u)\n", This, oneShot); 569 This->oneShot = oneShot ? OneShot_Wait : OneShot_None; 570 return S_OK; 571 } 572 573 /* ISampleGrabber */ 574 static HRESULT WINAPI 575 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type) 576 { 577 SG_Impl *This = impl_from_ISampleGrabber(iface); 578 TRACE("(%p)->(%p)\n", This, type); 579 if (!type) 580 return E_POINTER; 581 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n", 582 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype), 583 type->lSampleSize, 584 debugstr_guid(&type->formattype), type->cbFormat); 585 CoTaskMemFree(This->mtype.pbFormat); 586 This->mtype = *type; 587 This->mtype.pUnk = NULL; 588 if (type->cbFormat) { 589 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat); 590 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat); 591 } 592 else 593 This->mtype.pbFormat = NULL; 594 return S_OK; 595 } 596 597 /* ISampleGrabber */ 598 static HRESULT WINAPI 599 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type) 600 { 601 SG_Impl *This = impl_from_ISampleGrabber(iface); 602 TRACE("(%p)->(%p)\n", This, type); 603 if (!type) 604 return E_POINTER; 605 if (!This->pin_in.pair) 606 return VFW_E_NOT_CONNECTED; 607 *type = This->mtype; 608 if (type->cbFormat) { 609 type->pbFormat = CoTaskMemAlloc(type->cbFormat); 610 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat); 611 } 612 return S_OK; 613 } 614 615 /* ISampleGrabber */ 616 static HRESULT WINAPI 617 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm) 618 { 619 SG_Impl *This = impl_from_ISampleGrabber(iface); 620 TRACE("(%p)->(%u)\n", This, bufferEm); 621 EnterCriticalSection(&This->filter.csFilter); 622 if (bufferEm) { 623 if (This->bufferLen < 0) 624 This->bufferLen = 0; 625 } 626 else 627 This->bufferLen = -1; 628 LeaveCriticalSection(&This->filter.csFilter); 629 return S_OK; 630 } 631 632 /* ISampleGrabber */ 633 static HRESULT WINAPI 634 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer) 635 { 636 SG_Impl *This = impl_from_ISampleGrabber(iface); 637 HRESULT ret = S_OK; 638 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer); 639 if (!bufSize) 640 return E_POINTER; 641 EnterCriticalSection(&This->filter.csFilter); 642 if (!This->pin_in.pair) 643 ret = VFW_E_NOT_CONNECTED; 644 else if (This->bufferLen < 0) 645 ret = E_INVALIDARG; 646 else if (This->bufferLen == 0) 647 ret = VFW_E_WRONG_STATE; 648 else { 649 if (buffer) { 650 if (*bufSize >= This->bufferLen) 651 CopyMemory(buffer, This->bufferData, This->bufferLen); 652 else 653 ret = E_OUTOFMEMORY; 654 } 655 *bufSize = This->bufferLen; 656 } 657 LeaveCriticalSection(&This->filter.csFilter); 658 return ret; 659 } 660 661 /* ISampleGrabber */ 662 static HRESULT WINAPI 663 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample) 664 { 665 /* MS doesn't implement it either, no one should call it */ 666 WARN("(%p): not implemented\n", sample); 667 return E_NOTIMPL; 668 } 669 670 /* ISampleGrabber */ 671 static HRESULT WINAPI 672 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod) 673 { 674 SG_Impl *This = impl_from_ISampleGrabber(iface); 675 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod); 676 if (This->grabberIface) 677 ISampleGrabberCB_Release(This->grabberIface); 678 This->grabberIface = cb; 679 This->grabberMethod = whichMethod; 680 if (cb) 681 ISampleGrabberCB_AddRef(cb); 682 return S_OK; 683 } 684 685 686 /* SampleGrabber implementation of IMemInputPin interface */ 687 688 /* IUnknown */ 689 static HRESULT WINAPI 690 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv) 691 { 692 SG_Impl *This = impl_from_IMemInputPin(iface); 693 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 694 } 695 696 /* IUnknown */ 697 static ULONG WINAPI 698 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface) 699 { 700 SG_Impl *This = impl_from_IMemInputPin(iface); 701 return IUnknown_AddRef(This->outer_unk); 702 } 703 704 /* IUnknown */ 705 static ULONG WINAPI 706 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface) 707 { 708 SG_Impl *This = impl_from_IMemInputPin(iface); 709 return IUnknown_Release(This->outer_unk); 710 } 711 712 /* IMemInputPin */ 713 static HRESULT WINAPI 714 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator) 715 { 716 SG_Impl *This = impl_from_IMemInputPin(iface); 717 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator); 718 if (!allocator) 719 return E_POINTER; 720 *allocator = This->allocator; 721 if (!*allocator) 722 return VFW_E_NO_ALLOCATOR; 723 IMemAllocator_AddRef(*allocator); 724 return S_OK; 725 } 726 727 /* IMemInputPin */ 728 static HRESULT WINAPI 729 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly) 730 { 731 SG_Impl *This = impl_from_IMemInputPin(iface); 732 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator); 733 if (This->allocator == allocator) 734 return S_OK; 735 if (This->allocator) 736 IMemAllocator_Release(This->allocator); 737 This->allocator = allocator; 738 if (allocator) 739 IMemAllocator_AddRef(allocator); 740 return S_OK; 741 } 742 743 /* IMemInputPin */ 744 static HRESULT WINAPI 745 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props) 746 { 747 SG_Impl *This = impl_from_IMemInputPin(iface); 748 FIXME("(%p)->(%p): semi-stub\n", This, props); 749 if (!props) 750 return E_POINTER; 751 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL; 752 } 753 754 /* IMemInputPin */ 755 static HRESULT WINAPI 756 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample) 757 { 758 SG_Impl *This = impl_from_IMemInputPin(iface); 759 HRESULT hr; 760 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface); 761 if (!sample) 762 return E_POINTER; 763 if (This->oneShot == OneShot_Past) 764 return S_FALSE; 765 SampleGrabber_callback(This, sample); 766 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK; 767 if (This->oneShot == OneShot_Wait) { 768 This->oneShot = OneShot_Past; 769 hr = S_FALSE; 770 if (This->pin_out.pair) 771 IPin_EndOfStream(This->pin_out.pair); 772 } 773 return hr; 774 } 775 776 /* IMemInputPin */ 777 static HRESULT WINAPI 778 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed) 779 { 780 SG_Impl *This = impl_from_IMemInputPin(iface); 781 LONG idx; 782 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface); 783 if (!samples || !nProcessed) 784 return E_POINTER; 785 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past)) 786 return S_FALSE; 787 for (idx = 0; idx < nSamples; idx++) 788 SampleGrabber_callback(This, samples[idx]); 789 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK; 790 } 791 792 /* IMemInputPin */ 793 static HRESULT WINAPI 794 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface) 795 { 796 SG_Impl *This = impl_from_IMemInputPin(iface); 797 TRACE("(%p)\n", This); 798 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK; 799 } 800 801 802 /* SampleGrabber member pin implementation */ 803 804 /* IUnknown */ 805 static ULONG WINAPI 806 SampleGrabber_IPin_AddRef(IPin *iface) 807 { 808 SG_Pin *This = impl_from_IPin(iface); 809 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface); 810 } 811 812 /* IUnknown */ 813 static ULONG WINAPI 814 SampleGrabber_IPin_Release(IPin *iface) 815 { 816 SG_Pin *This = impl_from_IPin(iface); 817 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface); 818 } 819 820 /* IUnknown */ 821 static HRESULT WINAPI 822 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv) 823 { 824 SG_Pin *This = impl_from_IPin(iface); 825 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 826 827 *ppv = NULL; 828 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) 829 *ppv = iface; 830 else if (IsEqualIID(riid, &IID_IMemInputPin)) 831 *ppv = &This->sg->IMemInputPin_iface; 832 else if (IsEqualIID(riid, &IID_IMediaSeeking)) 833 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv); 834 else if (IsEqualIID(riid, &IID_IMediaPosition)) 835 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv); 836 else { 837 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv); 838 return E_NOINTERFACE; 839 } 840 841 IUnknown_AddRef((IUnknown*)*ppv); 842 return S_OK; 843 } 844 845 /* IPin - input pin */ 846 static HRESULT WINAPI 847 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype) 848 { 849 WARN("(%p, %p): unexpected\n", receiver, mtype); 850 return E_UNEXPECTED; 851 } 852 853 /* IPin - output pin */ 854 static HRESULT WINAPI 855 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type) 856 { 857 SG_Pin *This = impl_from_IPin(iface); 858 HRESULT hr; 859 860 TRACE("(%p)->(%p, %p)\n", This, receiver, type); 861 if (!receiver) 862 return E_POINTER; 863 if (This->pair) 864 return VFW_E_ALREADY_CONNECTED; 865 if (This->sg->filter.state != State_Stopped) 866 return VFW_E_NOT_STOPPED; 867 if (type) { 868 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n", 869 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype), 870 type->lSampleSize, 871 debugstr_guid(&type->formattype), type->cbFormat); 872 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) && 873 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype)) 874 return VFW_E_TYPE_NOT_ACCEPTED; 875 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) && 876 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype)) 877 return VFW_E_TYPE_NOT_ACCEPTED; 878 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) && 879 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) && 880 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype)) 881 return VFW_E_TYPE_NOT_ACCEPTED; 882 } 883 else 884 type = &This->sg->mtype; 885 if (!IsEqualGUID(&type->formattype, &FORMAT_None) && 886 !IsEqualGUID(&type->formattype, &GUID_NULL) && 887 !type->pbFormat) 888 return VFW_E_TYPE_NOT_ACCEPTED; 889 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type); 890 if (FAILED(hr)) 891 return hr; 892 This->pair = receiver; 893 if (This->sg->memOutput) { 894 IMemInputPin_Release(This->sg->memOutput); 895 This->sg->memOutput = NULL; 896 } 897 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput)); 898 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput); 899 return S_OK; 900 } 901 902 /* IPin - input pin */ 903 static HRESULT WINAPI 904 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type) 905 { 906 SG_Pin *This = impl_from_IPin(iface); 907 908 TRACE("(%p)->(%p, %p)\n", This, connector, type); 909 if (!connector) 910 return E_POINTER; 911 if (This->pair) 912 return VFW_E_ALREADY_CONNECTED; 913 if (This->sg->filter.state != State_Stopped) 914 return VFW_E_NOT_STOPPED; 915 if (type) { 916 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n", 917 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype), 918 type->lSampleSize, 919 debugstr_guid(&type->formattype), type->cbFormat); 920 if (!IsEqualGUID(&type->formattype, &FORMAT_None) && 921 !IsEqualGUID(&type->formattype, &GUID_NULL) && 922 !type->pbFormat) 923 return VFW_E_INVALIDMEDIATYPE; 924 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) && 925 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype)) 926 return VFW_E_TYPE_NOT_ACCEPTED; 927 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) && 928 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype)) 929 return VFW_E_TYPE_NOT_ACCEPTED; 930 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) && 931 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) && 932 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype)) 933 return VFW_E_TYPE_NOT_ACCEPTED; 934 CoTaskMemFree(This->sg->mtype.pbFormat); 935 This->sg->mtype = *type; 936 This->sg->mtype.pUnk = NULL; 937 if (type->cbFormat) { 938 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat); 939 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat); 940 } 941 else 942 This->sg->mtype.pbFormat = NULL; 943 } 944 This->pair = connector; 945 TRACE("(%p) Accepted IPin %p\n", This, connector); 946 return S_OK; 947 } 948 949 /* IPin - output pin */ 950 static HRESULT WINAPI 951 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype) 952 { 953 WARN("(%p, %p): unexpected\n", connector, mtype); 954 return E_UNEXPECTED; 955 } 956 957 /* IPin - input pin */ 958 static HRESULT WINAPI 959 SampleGrabber_In_IPin_Disconnect(IPin *iface) 960 { 961 SG_Pin *This = impl_from_IPin(iface); 962 963 TRACE("(%p)->() pair = %p\n", This, This->pair); 964 if (This->sg->filter.state != State_Stopped) 965 return VFW_E_NOT_STOPPED; 966 if (This->pair) { 967 This->pair = NULL; 968 return S_OK; 969 } 970 return S_FALSE; 971 } 972 973 /* IPin - output pin */ 974 static HRESULT WINAPI 975 SampleGrabber_Out_IPin_Disconnect(IPin *iface) 976 { 977 SG_Pin *This = impl_from_IPin(iface); 978 979 TRACE("(%p)->() pair = %p\n", This, This->pair); 980 if (This->sg->filter.state != State_Stopped) 981 return VFW_E_NOT_STOPPED; 982 if (This->pair) { 983 This->pair = NULL; 984 if (This->sg->memOutput) { 985 IMemInputPin_Release(This->sg->memOutput); 986 This->sg->memOutput = NULL; 987 } 988 return S_OK; 989 } 990 return S_FALSE; 991 } 992 993 /* IPin */ 994 static HRESULT WINAPI 995 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin) 996 { 997 SG_Pin *This = impl_from_IPin(iface); 998 999 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair); 1000 if (!pin) 1001 return E_POINTER; 1002 *pin = This->pair; 1003 if (*pin) { 1004 IPin_AddRef(*pin); 1005 return S_OK; 1006 } 1007 return VFW_E_NOT_CONNECTED; 1008 } 1009 1010 /* IPin */ 1011 static HRESULT WINAPI 1012 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype) 1013 { 1014 SG_Pin *This = impl_from_IPin(iface); 1015 1016 TRACE("(%p)->(%p)\n", This, mtype); 1017 if (!mtype) 1018 return E_POINTER; 1019 if (!This->pair) 1020 return VFW_E_NOT_CONNECTED; 1021 *mtype = This->sg->mtype; 1022 if (mtype->cbFormat) { 1023 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat); 1024 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat); 1025 } 1026 return S_OK; 1027 } 1028 1029 /* IPin */ 1030 static HRESULT WINAPI 1031 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info) 1032 { 1033 SG_Pin *This = impl_from_IPin(iface); 1034 1035 TRACE("(%p)->(%p)\n", This, info); 1036 if (!info) 1037 return E_POINTER; 1038 info->pFilter = &This->sg->filter.IBaseFilter_iface; 1039 IBaseFilter_AddRef(info->pFilter); 1040 info->dir = This->dir; 1041 lstrcpynW(info->achName,This->name,MAX_PIN_NAME); 1042 return S_OK; 1043 } 1044 1045 /* IPin */ 1046 static HRESULT WINAPI 1047 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir) 1048 { 1049 SG_Pin *This = impl_from_IPin(iface); 1050 1051 TRACE("(%p)->(%p)\n", This, dir); 1052 if (!dir) 1053 return E_POINTER; 1054 *dir = This->dir; 1055 return S_OK; 1056 } 1057 1058 /* IPin */ 1059 static HRESULT WINAPI 1060 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id) 1061 { 1062 SG_Pin *This = impl_from_IPin(iface); 1063 1064 int len; 1065 TRACE("(%p)->(%p)\n", This, id); 1066 if (!id) 1067 return E_POINTER; 1068 len = sizeof(WCHAR)*(1+lstrlenW(This->name)); 1069 *id = CoTaskMemAlloc(len); 1070 CopyMemory(*id, This->name, len); 1071 return S_OK; 1072 } 1073 1074 /* IPin */ 1075 static HRESULT WINAPI 1076 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype) 1077 { 1078 TRACE("(%p)\n", mtype); 1079 return S_OK; 1080 } 1081 1082 /* IPin */ 1083 static HRESULT WINAPI 1084 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes) 1085 { 1086 SG_Pin *This = impl_from_IPin(iface); 1087 1088 TRACE("(%p)->(%p)\n", This, mtypes); 1089 if (!mtypes) 1090 return E_POINTER; 1091 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL, FALSE); 1092 return *mtypes ? S_OK : E_OUTOFMEMORY; 1093 } 1094 1095 /* IPin - input pin */ 1096 static HRESULT WINAPI 1097 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins) 1098 { 1099 SG_Pin *This = impl_from_IPin(iface); 1100 1101 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0)); 1102 if (!nPins) 1103 return E_POINTER; 1104 if (*nPins) { 1105 if (!pins) 1106 return E_POINTER; 1107 IPin_AddRef(&This->sg->pin_out.IPin_iface); 1108 *pins = &This->sg->pin_out.IPin_iface; 1109 *nPins = 1; 1110 return S_OK; 1111 } 1112 *nPins = 1; 1113 return S_FALSE; 1114 } 1115 1116 /* IPin - output pin */ 1117 static HRESULT WINAPI 1118 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins) 1119 { 1120 WARN("(%p, %p): unexpected\n", pins, nPins); 1121 if (nPins) 1122 *nPins = 0; 1123 return E_NOTIMPL; 1124 } 1125 1126 /* IPin */ 1127 static HRESULT WINAPI 1128 SampleGrabber_IPin_EndOfStream(IPin *iface) 1129 { 1130 FIXME(": stub\n"); 1131 return S_OK; 1132 } 1133 1134 /* IPin */ 1135 static HRESULT WINAPI 1136 SampleGrabber_IPin_BeginFlush(IPin *iface) 1137 { 1138 FIXME(": stub\n"); 1139 return S_OK; 1140 } 1141 1142 /* IPin */ 1143 static HRESULT WINAPI 1144 SampleGrabber_IPin_EndFlush(IPin *iface) 1145 { 1146 FIXME(": stub\n"); 1147 return S_OK; 1148 } 1149 1150 /* IPin */ 1151 static HRESULT WINAPI 1152 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate) 1153 { 1154 FIXME(": stub\n"); 1155 return S_OK; 1156 } 1157 1158 1159 /* SampleGrabber vtables and constructor */ 1160 1161 static const IBaseFilterVtbl IBaseFilter_VTable = 1162 { 1163 SampleGrabber_IBaseFilter_QueryInterface, 1164 SampleGrabber_IBaseFilter_AddRef, 1165 SampleGrabber_IBaseFilter_Release, 1166 BaseFilterImpl_GetClassID, 1167 SampleGrabber_IBaseFilter_Stop, 1168 SampleGrabber_IBaseFilter_Pause, 1169 SampleGrabber_IBaseFilter_Run, 1170 BaseFilterImpl_GetState, 1171 BaseFilterImpl_SetSyncSource, 1172 BaseFilterImpl_GetSyncSource, 1173 BaseFilterImpl_EnumPins, 1174 SampleGrabber_IBaseFilter_FindPin, 1175 BaseFilterImpl_QueryFilterInfo, 1176 SampleGrabber_IBaseFilter_JoinFilterGraph, 1177 SampleGrabber_IBaseFilter_QueryVendorInfo, 1178 }; 1179 1180 static const ISampleGrabberVtbl ISampleGrabber_VTable = 1181 { 1182 SampleGrabber_ISampleGrabber_QueryInterface, 1183 SampleGrabber_ISampleGrabber_AddRef, 1184 SampleGrabber_ISampleGrabber_Release, 1185 SampleGrabber_ISampleGrabber_SetOneShot, 1186 SampleGrabber_ISampleGrabber_SetMediaType, 1187 SampleGrabber_ISampleGrabber_GetConnectedMediaType, 1188 SampleGrabber_ISampleGrabber_SetBufferSamples, 1189 SampleGrabber_ISampleGrabber_GetCurrentBuffer, 1190 SampleGrabber_ISampleGrabber_GetCurrentSample, 1191 SampleGrabber_ISampleGrabber_SetCallback, 1192 }; 1193 1194 static const IMemInputPinVtbl IMemInputPin_VTable = 1195 { 1196 SampleGrabber_IMemInputPin_QueryInterface, 1197 SampleGrabber_IMemInputPin_AddRef, 1198 SampleGrabber_IMemInputPin_Release, 1199 SampleGrabber_IMemInputPin_GetAllocator, 1200 SampleGrabber_IMemInputPin_NotifyAllocator, 1201 SampleGrabber_IMemInputPin_GetAllocatorRequirements, 1202 SampleGrabber_IMemInputPin_Receive, 1203 SampleGrabber_IMemInputPin_ReceiveMultiple, 1204 SampleGrabber_IMemInputPin_ReceiveCanBlock, 1205 }; 1206 1207 static const IPinVtbl IPin_In_VTable = 1208 { 1209 SampleGrabber_IPin_QueryInterface, 1210 SampleGrabber_IPin_AddRef, 1211 SampleGrabber_IPin_Release, 1212 SampleGrabber_In_IPin_Connect, 1213 SampleGrabber_In_IPin_ReceiveConnection, 1214 SampleGrabber_In_IPin_Disconnect, 1215 SampleGrabber_IPin_ConnectedTo, 1216 SampleGrabber_IPin_ConnectionMediaType, 1217 SampleGrabber_IPin_QueryPinInfo, 1218 SampleGrabber_IPin_QueryDirection, 1219 SampleGrabber_IPin_QueryId, 1220 SampleGrabber_IPin_QueryAccept, 1221 SampleGrabber_IPin_EnumMediaTypes, 1222 SampleGrabber_In_IPin_QueryInternalConnections, 1223 SampleGrabber_IPin_EndOfStream, 1224 SampleGrabber_IPin_BeginFlush, 1225 SampleGrabber_IPin_EndFlush, 1226 SampleGrabber_IPin_NewSegment, 1227 }; 1228 1229 static const IPinVtbl IPin_Out_VTable = 1230 { 1231 SampleGrabber_IPin_QueryInterface, 1232 SampleGrabber_IPin_AddRef, 1233 SampleGrabber_IPin_Release, 1234 SampleGrabber_Out_IPin_Connect, 1235 SampleGrabber_Out_IPin_ReceiveConnection, 1236 SampleGrabber_Out_IPin_Disconnect, 1237 SampleGrabber_IPin_ConnectedTo, 1238 SampleGrabber_IPin_ConnectionMediaType, 1239 SampleGrabber_IPin_QueryPinInfo, 1240 SampleGrabber_IPin_QueryDirection, 1241 SampleGrabber_IPin_QueryId, 1242 SampleGrabber_IPin_QueryAccept, 1243 SampleGrabber_IPin_EnumMediaTypes, 1244 SampleGrabber_Out_IPin_QueryInternalConnections, 1245 SampleGrabber_IPin_EndOfStream, 1246 SampleGrabber_IPin_BeginFlush, 1247 SampleGrabber_IPin_EndFlush, 1248 SampleGrabber_IPin_NewSegment, 1249 }; 1250 1251 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv) 1252 { 1253 SG_Impl* obj = NULL; 1254 ISeekingPassThru *passthru; 1255 HRESULT hr; 1256 1257 TRACE("(%p,%p)\n", pUnkOuter, ppv); 1258 1259 obj = CoTaskMemAlloc(sizeof(SG_Impl)); 1260 if (NULL == obj) { 1261 *ppv = NULL; 1262 return E_OUTOFMEMORY; 1263 } 1264 ZeroMemory(obj, sizeof(SG_Impl)); 1265 1266 BaseFilter_Init(&obj->filter, &IBaseFilter_VTable, &CLSID_SampleGrabber, 1267 (DWORD_PTR)(__FILE__ ": SG_Impl.csFilter"), &basefunc_vtbl); 1268 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl; 1269 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable; 1270 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable; 1271 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable; 1272 obj->pin_in.dir = PINDIR_INPUT; 1273 obj->pin_in.name = pin_in_name; 1274 obj->pin_in.sg = obj; 1275 obj->pin_in.pair = NULL; 1276 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable; 1277 obj->pin_out.dir = PINDIR_OUTPUT; 1278 obj->pin_out.name = pin_out_name; 1279 obj->pin_out.sg = obj; 1280 obj->pin_out.pair = NULL; 1281 obj->mtype.majortype = GUID_NULL; 1282 obj->mtype.subtype = MEDIASUBTYPE_None; 1283 obj->mtype.formattype = FORMAT_None; 1284 obj->allocator = NULL; 1285 obj->memOutput = NULL; 1286 obj->grabberIface = NULL; 1287 obj->grabberMethod = -1; 1288 obj->oneShot = OneShot_None; 1289 obj->bufferLen = -1; 1290 obj->bufferData = NULL; 1291 1292 if (pUnkOuter) 1293 obj->outer_unk = pUnkOuter; 1294 else 1295 obj->outer_unk = &obj->IUnknown_inner; 1296 1297 hr = CoCreateInstance(&CLSID_SeekingPassThru, &obj->IUnknown_inner, CLSCTX_INPROC_SERVER, 1298 &IID_IUnknown, (void**)&obj->seekthru_unk); 1299 if(hr) 1300 return hr; 1301 IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru); 1302 ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface); 1303 ISeekingPassThru_Release(passthru); 1304 1305 *ppv = &obj->IUnknown_inner; 1306 return S_OK; 1307 } 1308