1 /* 2 * Copyright 2013 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <stdarg.h> 20 21 #define COBJMACROS 22 23 #include "windef.h" 24 #include "winbase.h" 25 #include "dshow.h" 26 #include "vfw.h" 27 #include "aviriff.h" 28 29 #include "qcap_main.h" 30 31 #include "wine/debug.h" 32 #include "wine/heap.h" 33 34 WINE_DEFAULT_DEBUG_CHANNEL(qcap); 35 36 typedef struct { 37 BaseFilter filter; 38 IPersistPropertyBag IPersistPropertyBag_iface; 39 40 BaseInputPin *in; 41 BaseOutputPin *out; 42 43 DWORD fcc_handler; 44 HIC hic; 45 46 VIDEOINFOHEADER *videoinfo; 47 size_t videoinfo_size; 48 DWORD driver_flags; 49 DWORD max_frame_size; 50 51 DWORD frame_cnt; 52 } AVICompressor; 53 54 static inline AVICompressor *impl_from_BaseFilter(BaseFilter *filter) 55 { 56 return CONTAINING_RECORD(filter, AVICompressor, filter); 57 } 58 59 static inline AVICompressor *impl_from_IBaseFilter(IBaseFilter *iface) 60 { 61 BaseFilter *filter = CONTAINING_RECORD(iface, BaseFilter, IBaseFilter_iface); 62 return impl_from_BaseFilter(filter); 63 } 64 65 static inline AVICompressor *impl_from_BasePin(BasePin *pin) 66 { 67 return impl_from_IBaseFilter(pin->pinInfo.pFilter); 68 } 69 70 static HRESULT ensure_driver(AVICompressor *This) 71 { 72 if(This->hic) 73 return S_OK; 74 75 This->hic = ICOpen(FCC('v','i','d','c'), This->fcc_handler, ICMODE_COMPRESS); 76 if(!This->hic) { 77 FIXME("ICOpen failed\n"); 78 return E_FAIL; 79 } 80 81 return S_OK; 82 } 83 84 static HRESULT fill_format_info(AVICompressor *This, VIDEOINFOHEADER *src_videoinfo) 85 { 86 DWORD size; 87 ICINFO icinfo; 88 HRESULT hres; 89 90 hres = ensure_driver(This); 91 if(hres != S_OK) 92 return hres; 93 94 size = ICGetInfo(This->hic, &icinfo, sizeof(icinfo)); 95 if(size != sizeof(icinfo)) 96 return E_FAIL; 97 98 size = ICCompressGetFormatSize(This->hic, &src_videoinfo->bmiHeader); 99 if(!size) { 100 FIXME("ICCompressGetFormatSize failed\n"); 101 return E_FAIL; 102 } 103 104 size += FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader); 105 This->videoinfo = heap_alloc(size); 106 if(!This->videoinfo) 107 return E_OUTOFMEMORY; 108 109 This->videoinfo_size = size; 110 This->driver_flags = icinfo.dwFlags; 111 memset(This->videoinfo, 0, sizeof(*This->videoinfo)); 112 ICCompressGetFormat(This->hic, &src_videoinfo->bmiHeader, &This->videoinfo->bmiHeader); 113 114 This->videoinfo->dwBitRate = 10000000/src_videoinfo->AvgTimePerFrame * This->videoinfo->bmiHeader.biSizeImage * 8; 115 This->videoinfo->AvgTimePerFrame = src_videoinfo->AvgTimePerFrame; 116 This->max_frame_size = This->videoinfo->bmiHeader.biSizeImage; 117 return S_OK; 118 } 119 120 static HRESULT WINAPI AVICompressor_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) 121 { 122 AVICompressor *This = impl_from_IBaseFilter(iface); 123 124 if(IsEqualIID(riid, &IID_IUnknown)) { 125 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 126 *ppv = &This->filter.IBaseFilter_iface; 127 }else if(IsEqualIID(riid, &IID_IPersist)) { 128 TRACE("(%p)->(IID_IPersist %p)\n", This, ppv); 129 *ppv = &This->filter.IBaseFilter_iface; 130 }else if(IsEqualIID(riid, &IID_IMediaFilter)) { 131 TRACE("(%p)->(IID_IMediaFilter %p)\n", This, ppv); 132 *ppv = &This->filter.IBaseFilter_iface; 133 }else if(IsEqualIID(riid, &IID_IBaseFilter)) { 134 TRACE("(%p)->(IID_IBaseFilter %p)\n", This, ppv); 135 *ppv = &This->filter.IBaseFilter_iface; 136 }else if(IsEqualIID(riid, &IID_IPersistPropertyBag)) { 137 TRACE("(%p)->(IID_IPersistPropertyBag %p)\n", This, ppv); 138 *ppv = &This->IPersistPropertyBag_iface; 139 }else { 140 FIXME("no interface for %s\n", debugstr_guid(riid)); 141 *ppv = NULL; 142 return E_NOINTERFACE; 143 } 144 145 IUnknown_AddRef((IUnknown*)*ppv); 146 return S_OK; 147 148 } 149 150 static ULONG WINAPI AVICompressor_Release(IBaseFilter *iface) 151 { 152 AVICompressor *This = impl_from_IBaseFilter(iface); 153 ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface); 154 155 TRACE("(%p) ref=%d\n", This, ref); 156 157 if(!ref) { 158 if(This->hic) 159 ICClose(This->hic); 160 heap_free(This->videoinfo); 161 if(This->in) 162 BaseInputPinImpl_Release(&This->in->pin.IPin_iface); 163 if(This->out) 164 BaseOutputPinImpl_Release(&This->out->pin.IPin_iface); 165 heap_free(This); 166 } 167 168 return ref; 169 } 170 171 static HRESULT WINAPI AVICompressor_Stop(IBaseFilter *iface) 172 { 173 AVICompressor *This = impl_from_IBaseFilter(iface); 174 175 TRACE("(%p)\n", This); 176 177 if(This->filter.state == State_Stopped) 178 return S_OK; 179 180 ICCompressEnd(This->hic); 181 This->filter.state = State_Stopped; 182 return S_OK; 183 } 184 185 static HRESULT WINAPI AVICompressor_Pause(IBaseFilter *iface) 186 { 187 AVICompressor *This = impl_from_IBaseFilter(iface); 188 FIXME("(%p)\n", This); 189 return E_NOTIMPL; 190 } 191 192 static HRESULT WINAPI AVICompressor_Run(IBaseFilter *iface, REFERENCE_TIME tStart) 193 { 194 AVICompressor *This = impl_from_IBaseFilter(iface); 195 HRESULT hres; 196 197 TRACE("(%p)->(%s)\n", This, wine_dbgstr_longlong(tStart)); 198 199 if(This->filter.state == State_Running) 200 return S_OK; 201 202 hres = IMemAllocator_Commit(This->out->pAllocator); 203 if(FAILED(hres)) { 204 FIXME("Commit failed: %08x\n", hres); 205 return hres; 206 } 207 208 This->frame_cnt = 0; 209 210 This->filter.state = State_Running; 211 return S_OK; 212 } 213 214 static HRESULT WINAPI AVICompressor_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin) 215 { 216 AVICompressor *This = impl_from_IBaseFilter(iface); 217 FIXME("(%p)->(%s %p)\n", This, debugstr_w(Id), ppPin); 218 return VFW_E_NOT_FOUND; 219 } 220 221 static HRESULT WINAPI AVICompressor_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo) 222 { 223 AVICompressor *This = impl_from_IBaseFilter(iface); 224 FIXME("(%p)->(%p)\n", This, pInfo); 225 return E_NOTIMPL; 226 } 227 228 static HRESULT WINAPI AVICompressor_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo) 229 { 230 AVICompressor *This = impl_from_IBaseFilter(iface); 231 FIXME("(%p)->(%p)\n", This, pVendorInfo); 232 return E_NOTIMPL; 233 } 234 235 static const IBaseFilterVtbl AVICompressorVtbl = { 236 AVICompressor_QueryInterface, 237 BaseFilterImpl_AddRef, 238 AVICompressor_Release, 239 BaseFilterImpl_GetClassID, 240 AVICompressor_Stop, 241 AVICompressor_Pause, 242 AVICompressor_Run, 243 BaseFilterImpl_GetState, 244 BaseFilterImpl_SetSyncSource, 245 BaseFilterImpl_GetSyncSource, 246 BaseFilterImpl_EnumPins, 247 AVICompressor_FindPin, 248 AVICompressor_QueryFilterInfo, 249 BaseFilterImpl_JoinFilterGraph, 250 AVICompressor_QueryVendorInfo 251 }; 252 253 static IPin* WINAPI AVICompressor_GetPin(BaseFilter *iface, int pos) 254 { 255 AVICompressor *This = impl_from_BaseFilter(iface); 256 IPin *ret; 257 258 TRACE("(%p)->(%d)\n", This, pos); 259 260 switch(pos) { 261 case 0: 262 ret = &This->in->pin.IPin_iface; 263 break; 264 case 1: 265 ret = &This->out->pin.IPin_iface; 266 break; 267 default: 268 TRACE("No pin %d\n", pos); 269 return NULL; 270 }; 271 272 IPin_AddRef(ret); 273 return ret; 274 } 275 276 static LONG WINAPI AVICompressor_GetPinCount(BaseFilter *iface) 277 { 278 return 2; 279 } 280 281 static const BaseFilterFuncTable filter_func_table = { 282 AVICompressor_GetPin, 283 AVICompressor_GetPinCount 284 }; 285 286 static AVICompressor *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface) 287 { 288 return CONTAINING_RECORD(iface, AVICompressor, IPersistPropertyBag_iface); 289 } 290 291 static HRESULT WINAPI AVICompressorPropertyBag_QueryInterface(IPersistPropertyBag *iface, REFIID riid, void **ppv) 292 { 293 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 294 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 295 } 296 297 static ULONG WINAPI AVICompressorPropertyBag_AddRef(IPersistPropertyBag *iface) 298 { 299 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 300 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 301 } 302 303 static ULONG WINAPI AVICompressorPropertyBag_Release(IPersistPropertyBag *iface) 304 { 305 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 306 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 307 } 308 309 static HRESULT WINAPI AVICompressorPropertyBag_GetClassID(IPersistPropertyBag *iface, CLSID *pClassID) 310 { 311 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 312 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID); 313 } 314 315 static HRESULT WINAPI AVICompressorPropertyBag_InitNew(IPersistPropertyBag *iface) 316 { 317 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 318 FIXME("(%p)->()\n", This); 319 return E_NOTIMPL; 320 } 321 322 static HRESULT WINAPI AVICompressorPropertyBag_Load(IPersistPropertyBag *iface, IPropertyBag *pPropBag, IErrorLog *pErrorLog) 323 { 324 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 325 BSTR str; 326 VARIANT v; 327 HRESULT hres; 328 329 static const WCHAR fcc_handlerW[] = {'F','c','c','H','a','n','d','l','e','r',0}; 330 331 TRACE("(%p)->(%p %p)\n", This, pPropBag, pErrorLog); 332 333 V_VT(&v) = VT_EMPTY; 334 hres = IPropertyBag_Read(pPropBag, fcc_handlerW, &v, NULL); 335 if(FAILED(hres)) { 336 WARN("Could not read FccHandler: %08x\n", hres); 337 return hres; 338 } 339 340 if(V_VT(&v) != VT_BSTR) { 341 FIXME("Got vt %d\n", V_VT(&v)); 342 VariantClear(&v); 343 return E_FAIL; 344 } 345 346 str = V_BSTR(&v); 347 TRACE("FccHandler = %s\n", debugstr_w(str)); 348 if(SysStringLen(str) != 4) { 349 FIXME("Invalid FccHandler len\n"); 350 SysFreeString(str); 351 return E_FAIL; 352 } 353 354 This->fcc_handler = FCC(str[0], str[1], str[2], str[3]); 355 SysFreeString(str); 356 return S_OK; 357 } 358 359 static HRESULT WINAPI AVICompressorPropertyBag_Save(IPersistPropertyBag *iface, IPropertyBag *pPropBag, 360 BOOL fClearDirty, BOOL fSaveAllProperties) 361 { 362 AVICompressor *This = impl_from_IPersistPropertyBag(iface); 363 FIXME("(%p)->(%p %x %x)\n", This, pPropBag, fClearDirty, fSaveAllProperties); 364 return E_NOTIMPL; 365 } 366 367 static const IPersistPropertyBagVtbl PersistPropertyBagVtbl = { 368 AVICompressorPropertyBag_QueryInterface, 369 AVICompressorPropertyBag_AddRef, 370 AVICompressorPropertyBag_Release, 371 AVICompressorPropertyBag_GetClassID, 372 AVICompressorPropertyBag_InitNew, 373 AVICompressorPropertyBag_Load, 374 AVICompressorPropertyBag_Save 375 }; 376 377 static inline AVICompressor *impl_from_IPin(IPin *iface) 378 { 379 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface); 380 return impl_from_IBaseFilter(bp->pinInfo.pFilter); 381 } 382 383 static HRESULT WINAPI AVICompressorIn_QueryInterface(IPin *iface, REFIID riid, void **ppv) 384 { 385 return BaseInputPinImpl_QueryInterface(iface, riid, ppv); 386 } 387 388 static ULONG WINAPI AVICompressorIn_AddRef(IPin *iface) 389 { 390 AVICompressor *This = impl_from_IPin(iface); 391 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 392 } 393 394 static ULONG WINAPI AVICompressorIn_Release(IPin *iface) 395 { 396 AVICompressor *This = impl_from_IPin(iface); 397 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 398 } 399 400 static HRESULT WINAPI AVICompressorIn_ReceiveConnection(IPin *iface, 401 IPin *pConnector, const AM_MEDIA_TYPE *pmt) 402 { 403 AVICompressor *This = impl_from_IPin(iface); 404 HRESULT hres; 405 406 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", This, pConnector, pmt); 407 dump_AM_MEDIA_TYPE(pmt); 408 409 hres = BaseInputPinImpl_ReceiveConnection(iface, pConnector, pmt); 410 if(FAILED(hres)) 411 return hres; 412 413 hres = fill_format_info(This, (VIDEOINFOHEADER*)pmt->pbFormat); 414 if(FAILED(hres)) 415 BasePinImpl_Disconnect(iface); 416 return hres; 417 } 418 419 static HRESULT WINAPI AVICompressorIn_Disconnect(IPin *iface) 420 { 421 AVICompressor *This = impl_from_IPin(iface); 422 HRESULT hres; 423 424 TRACE("(%p)\n", This); 425 426 hres = BasePinImpl_Disconnect(iface); 427 if(FAILED(hres)) 428 return hres; 429 430 heap_free(This->videoinfo); 431 This->videoinfo = NULL; 432 return S_OK; 433 } 434 435 static const IPinVtbl AVICompressorInputPinVtbl = { 436 AVICompressorIn_QueryInterface, 437 AVICompressorIn_AddRef, 438 AVICompressorIn_Release, 439 BaseInputPinImpl_Connect, 440 AVICompressorIn_ReceiveConnection, 441 AVICompressorIn_Disconnect, 442 BasePinImpl_ConnectedTo, 443 BasePinImpl_ConnectionMediaType, 444 BasePinImpl_QueryPinInfo, 445 BasePinImpl_QueryDirection, 446 BasePinImpl_QueryId, 447 BasePinImpl_QueryAccept, 448 BasePinImpl_EnumMediaTypes, 449 BasePinImpl_QueryInternalConnections, 450 BaseInputPinImpl_EndOfStream, 451 BaseInputPinImpl_BeginFlush, 452 BaseInputPinImpl_EndFlush, 453 BaseInputPinImpl_NewSegment 454 }; 455 456 static HRESULT WINAPI AVICompressorIn_CheckMediaType(BasePin *base, const AM_MEDIA_TYPE *pmt) 457 { 458 AVICompressor *This = impl_from_BasePin(base); 459 VIDEOINFOHEADER *videoinfo; 460 HRESULT hres; 461 DWORD res; 462 463 TRACE("(%p)->(AM_MEDIA_TYPE(%p))\n", base, pmt); 464 dump_AM_MEDIA_TYPE(pmt); 465 466 if(!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) 467 return S_FALSE; 468 469 if(!IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) { 470 FIXME("formattype %s unsupported\n", debugstr_guid(&pmt->formattype)); 471 return S_FALSE; 472 } 473 474 hres = ensure_driver(This); 475 if(hres != S_OK) 476 return hres; 477 478 videoinfo = (VIDEOINFOHEADER*)pmt->pbFormat; 479 res = ICCompressQuery(This->hic, &videoinfo->bmiHeader, NULL); 480 return res == ICERR_OK ? S_OK : S_FALSE; 481 } 482 483 static LONG WINAPI AVICompressorIn_GetMediaTypeVersion(BasePin *base) 484 { 485 return 0; 486 } 487 488 static HRESULT WINAPI AVICompressorIn_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt) 489 { 490 TRACE("(%p)->(%d %p)\n", base, iPosition, amt); 491 return S_FALSE; 492 } 493 494 static HRESULT WINAPI AVICompressorIn_Receive(BaseInputPin *base, IMediaSample *pSample) 495 { 496 AVICompressor *This = impl_from_BasePin(&base->pin); 497 VIDEOINFOHEADER *src_videoinfo; 498 REFERENCE_TIME start, stop; 499 IMediaSample *out_sample; 500 AM_MEDIA_TYPE *mt; 501 IMediaSample2 *sample2; 502 DWORD comp_flags = 0; 503 BOOL is_preroll; 504 BOOL sync_point; 505 BYTE *ptr, *buf; 506 DWORD res; 507 HRESULT hres; 508 509 TRACE("(%p)->(%p)\n", base, pSample); 510 511 if(!This->hic) { 512 FIXME("Driver not loaded\n"); 513 return E_UNEXPECTED; 514 } 515 516 hres = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&sample2); 517 if(SUCCEEDED(hres)) { 518 FIXME("Use IMediaSample2\n"); 519 IMediaSample2_Release(sample2); 520 } 521 522 is_preroll = IMediaSample_IsPreroll(pSample) == S_OK; 523 sync_point = IMediaSample_IsSyncPoint(pSample) == S_OK; 524 525 hres = IMediaSample_GetTime(pSample, &start, &stop); 526 if(FAILED(hres)) { 527 WARN("GetTime failed: %08x\n", hres); 528 return hres; 529 } 530 531 hres = IMediaSample_GetMediaType(pSample, &mt); 532 if(FAILED(hres)) 533 return hres; 534 535 hres = IMediaSample_GetPointer(pSample, &ptr); 536 if(FAILED(hres)) { 537 WARN("GetPointer failed: %08x\n", hres); 538 return hres; 539 } 540 541 hres = BaseOutputPinImpl_GetDeliveryBuffer(This->out, &out_sample, &start, &stop, 0); 542 if(FAILED(hres)) 543 return hres; 544 545 hres = IMediaSample_GetPointer(out_sample, &buf); 546 if(FAILED(hres)) 547 return hres; 548 549 if((This->driver_flags & VIDCF_TEMPORAL) && !(This->driver_flags & VIDCF_FASTTEMPORALC)) 550 FIXME("Unsupported temporal compression\n"); 551 552 src_videoinfo = (VIDEOINFOHEADER*)This->in->pin.mtCurrent.pbFormat; 553 This->videoinfo->bmiHeader.biSizeImage = This->max_frame_size; 554 res = ICCompress(This->hic, sync_point ? ICCOMPRESS_KEYFRAME : 0, &This->videoinfo->bmiHeader, buf, 555 &src_videoinfo->bmiHeader, ptr, 0, &comp_flags, This->frame_cnt, 0, 0, NULL, NULL); 556 if(res != ICERR_OK) { 557 WARN("ICCompress failed: %d\n", res); 558 IMediaSample_Release(out_sample); 559 return E_FAIL; 560 } 561 562 IMediaSample_SetActualDataLength(out_sample, This->videoinfo->bmiHeader.biSizeImage); 563 IMediaSample_SetPreroll(out_sample, is_preroll); 564 IMediaSample_SetSyncPoint(out_sample, (comp_flags&AVIIF_KEYFRAME) != 0); 565 IMediaSample_SetDiscontinuity(out_sample, (IMediaSample_IsDiscontinuity(pSample) == S_OK)); 566 567 if (IMediaSample_GetMediaTime(pSample, &start, &stop) == S_OK) 568 IMediaSample_SetMediaTime(out_sample, &start, &stop); 569 else 570 IMediaSample_SetMediaTime(out_sample, NULL, NULL); 571 572 hres = BaseOutputPinImpl_Deliver(This->out, out_sample); 573 if(FAILED(hres)) 574 WARN("Deliver failed: %08x\n", hres); 575 576 IMediaSample_Release(out_sample); 577 This->frame_cnt++; 578 return hres; 579 } 580 581 static const BaseInputPinFuncTable AVICompressorBaseInputPinVtbl = { 582 { 583 AVICompressorIn_CheckMediaType, 584 NULL, 585 AVICompressorIn_GetMediaTypeVersion, 586 AVICompressorIn_GetMediaType 587 }, 588 AVICompressorIn_Receive 589 }; 590 591 static HRESULT WINAPI AVICompressorOut_QueryInterface(IPin *iface, REFIID riid, void **ppv) 592 { 593 return BaseInputPinImpl_QueryInterface(iface, riid, ppv); 594 } 595 596 static ULONG WINAPI AVICompressorOut_AddRef(IPin *iface) 597 { 598 AVICompressor *This = impl_from_IPin(iface); 599 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 600 } 601 602 static ULONG WINAPI AVICompressorOut_Release(IPin *iface) 603 { 604 AVICompressor *This = impl_from_IPin(iface); 605 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 606 } 607 608 static const IPinVtbl AVICompressorOutputPinVtbl = { 609 AVICompressorOut_QueryInterface, 610 AVICompressorOut_AddRef, 611 AVICompressorOut_Release, 612 BaseOutputPinImpl_Connect, 613 BaseOutputPinImpl_ReceiveConnection, 614 BaseOutputPinImpl_Disconnect, 615 BasePinImpl_ConnectedTo, 616 BasePinImpl_ConnectionMediaType, 617 BasePinImpl_QueryPinInfo, 618 BasePinImpl_QueryDirection, 619 BasePinImpl_QueryId, 620 BasePinImpl_QueryAccept, 621 BasePinImpl_EnumMediaTypes, 622 BasePinImpl_QueryInternalConnections, 623 BaseOutputPinImpl_EndOfStream, 624 BaseOutputPinImpl_BeginFlush, 625 BaseOutputPinImpl_EndFlush, 626 BasePinImpl_NewSegment 627 }; 628 629 static LONG WINAPI AVICompressorOut_GetMediaTypeVersion(BasePin *base) 630 { 631 FIXME("(%p)\n", base); 632 return 0; 633 } 634 635 static HRESULT WINAPI AVICompressorOut_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt) 636 { 637 AVICompressor *This = impl_from_IBaseFilter(base->pinInfo.pFilter); 638 639 TRACE("(%p)->(%d %p)\n", base, iPosition, amt); 640 641 if(iPosition || !This->videoinfo) 642 return S_FALSE; 643 644 amt->majortype = MEDIATYPE_Video; 645 amt->subtype = MEDIASUBTYPE_PCM; 646 amt->bFixedSizeSamples = FALSE; 647 amt->bTemporalCompression = (This->driver_flags & VIDCF_TEMPORAL) != 0; 648 amt->lSampleSize = This->in->pin.mtCurrent.lSampleSize; 649 amt->formattype = FORMAT_VideoInfo; 650 amt->pUnk = NULL; 651 amt->cbFormat = This->videoinfo_size; 652 amt->pbFormat = (BYTE*)This->videoinfo; 653 return S_OK; 654 } 655 656 static HRESULT WINAPI AVICompressorOut_DecideBufferSize(BaseOutputPin *base, IMemAllocator *alloc, ALLOCATOR_PROPERTIES *ppropInputRequest) 657 { 658 AVICompressor *This = impl_from_BasePin(&base->pin); 659 ALLOCATOR_PROPERTIES actual; 660 661 TRACE("(%p)\n", This); 662 663 if (!ppropInputRequest->cBuffers) 664 ppropInputRequest->cBuffers = 1; 665 if (ppropInputRequest->cbBuffer < This->max_frame_size) 666 ppropInputRequest->cbBuffer = This->max_frame_size; 667 if (!ppropInputRequest->cbAlign) 668 ppropInputRequest->cbAlign = 1; 669 670 return IMemAllocator_SetProperties(alloc, ppropInputRequest, &actual); 671 } 672 673 static HRESULT WINAPI AVICompressorOut_DecideAllocator(BaseOutputPin *base, 674 IMemInputPin *pPin, IMemAllocator **pAlloc) 675 { 676 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc); 677 return BaseOutputPinImpl_DecideAllocator(base, pPin, pAlloc); 678 } 679 680 static HRESULT WINAPI AVICompressorOut_BreakConnect(BaseOutputPin *base) 681 { 682 FIXME("(%p)\n", base); 683 return E_NOTIMPL; 684 } 685 686 static const BaseOutputPinFuncTable AVICompressorBaseOutputPinVtbl = { 687 { 688 NULL, 689 BaseOutputPinImpl_AttemptConnection, 690 AVICompressorOut_GetMediaTypeVersion, 691 AVICompressorOut_GetMediaType 692 }, 693 AVICompressorOut_DecideBufferSize, 694 AVICompressorOut_DecideAllocator, 695 AVICompressorOut_BreakConnect 696 }; 697 698 IUnknown* WINAPI QCAP_createAVICompressor(IUnknown *outer, HRESULT *phr) 699 { 700 PIN_INFO in_pin_info = {NULL, PINDIR_INPUT, {'I','n','p','u','t',0}}; 701 PIN_INFO out_pin_info = {NULL, PINDIR_OUTPUT, {'O','u','t','p','u','t',0}}; 702 AVICompressor *compressor; 703 HRESULT hres; 704 705 TRACE("\n"); 706 707 compressor = heap_alloc_zero(sizeof(*compressor)); 708 if(!compressor) { 709 *phr = E_NOINTERFACE; 710 return NULL; 711 } 712 713 BaseFilter_Init(&compressor->filter, &AVICompressorVtbl, &CLSID_AVICo, 714 (DWORD_PTR)(__FILE__ ": AVICompressor.csFilter"), &filter_func_table); 715 716 compressor->IPersistPropertyBag_iface.lpVtbl = &PersistPropertyBagVtbl; 717 718 in_pin_info.pFilter = &compressor->filter.IBaseFilter_iface; 719 hres = BaseInputPin_Construct(&AVICompressorInputPinVtbl, sizeof(BaseInputPin), &in_pin_info, 720 &AVICompressorBaseInputPinVtbl, &compressor->filter.csFilter, NULL, (IPin**)&compressor->in); 721 if(FAILED(hres)) { 722 IBaseFilter_Release(&compressor->filter.IBaseFilter_iface); 723 *phr = hres; 724 return NULL; 725 } 726 727 out_pin_info.pFilter = &compressor->filter.IBaseFilter_iface; 728 hres = BaseOutputPin_Construct(&AVICompressorOutputPinVtbl, sizeof(BaseOutputPin), &out_pin_info, 729 &AVICompressorBaseOutputPinVtbl, &compressor->filter.csFilter, (IPin**)&compressor->out); 730 if(FAILED(hres)) { 731 IBaseFilter_Release(&compressor->filter.IBaseFilter_iface); 732 *phr = hres; 733 return NULL; 734 } 735 736 *phr = S_OK; 737 return (IUnknown*)&compressor->filter.IBaseFilter_iface; 738 } 739