1 /* 2 * Copyright (C) 2013 Piotr 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 #include <stdio.h> 21 22 #define COBJMACROS 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "wtypes.h" 27 #include "dshow.h" 28 #include "vfw.h" 29 #include "aviriff.h" 30 31 #include "qcap_main.h" 32 33 #include "wine/debug.h" 34 35 WINE_DEFAULT_DEBUG_CHANNEL(qcap); 36 37 #define MAX_PIN_NO 128 38 #define AVISUPERINDEX_ENTRIES 2000 39 #define AVISTDINDEX_ENTRIES 4000 40 #define ALIGN(x) ((x+1)/2*2) 41 42 typedef struct { 43 BaseOutputPin pin; 44 IQualityControl IQualityControl_iface; 45 46 int cur_stream; 47 LONGLONG cur_time; 48 49 int buf_pos; 50 BYTE buf[65536]; 51 52 int movi_off; 53 int out_pos; 54 int size; 55 IStream *stream; 56 } AviMuxOut; 57 58 typedef struct { 59 BaseInputPin pin; 60 IAMStreamControl IAMStreamControl_iface; 61 IPropertyBag IPropertyBag_iface; 62 IQualityControl IQualityControl_iface; 63 64 REFERENCE_TIME avg_time_per_frame; 65 REFERENCE_TIME stop; 66 int stream_id; 67 LONGLONG stream_time; 68 69 /* strl chunk */ 70 AVISTREAMHEADER strh; 71 struct { 72 FOURCC fcc; 73 DWORD cb; 74 BYTE data[1]; 75 } *strf; 76 AVISUPERINDEX *indx; 77 #ifdef __REACTOS__ 78 BYTE indx_data[FIELD_OFFSET(AVISUPERINDEX, aIndex) + AVISUPERINDEX_ENTRIES * sizeof(struct _avisuperindex_entry)]; 79 #else 80 BYTE indx_data[FIELD_OFFSET(AVISUPERINDEX, aIndex[AVISUPERINDEX_ENTRIES])]; 81 #endif 82 83 /* movi chunk */ 84 int ix_off; 85 AVISTDINDEX *ix; 86 #ifdef __REACTOS__ 87 BYTE ix_data[FIELD_OFFSET(AVISTDINDEX, aIndex) + AVISTDINDEX_ENTRIES * sizeof(struct _avisuperindex_entry)]; 88 #else 89 BYTE ix_data[FIELD_OFFSET(AVISTDINDEX, aIndex[AVISTDINDEX_ENTRIES])]; 90 #endif 91 92 IMediaSample *samples_head; 93 IMemAllocator *samples_allocator; 94 } AviMuxIn; 95 96 typedef struct { 97 BaseFilter filter; 98 IConfigAviMux IConfigAviMux_iface; 99 IConfigInterleaving IConfigInterleaving_iface; 100 IMediaSeeking IMediaSeeking_iface; 101 IPersistMediaPropertyBag IPersistMediaPropertyBag_iface; 102 ISpecifyPropertyPages ISpecifyPropertyPages_iface; 103 104 InterleavingMode mode; 105 REFERENCE_TIME interleave; 106 REFERENCE_TIME preroll; 107 108 AviMuxOut *out; 109 int input_pin_no; 110 AviMuxIn *in[MAX_PIN_NO-1]; 111 112 REFERENCE_TIME start, stop; 113 AVIMAINHEADER avih; 114 115 int idx1_entries; 116 int idx1_size; 117 AVIINDEXENTRY *idx1; 118 } AviMux; 119 120 static HRESULT create_input_pin(AviMux*); 121 122 static inline AviMux* impl_from_BaseFilter(BaseFilter *filter) 123 { 124 return CONTAINING_RECORD(filter, AviMux, filter); 125 } 126 127 static IPin* WINAPI AviMux_GetPin(BaseFilter *iface, int pos) 128 { 129 AviMux *This = impl_from_BaseFilter(iface); 130 131 TRACE("(%p)->(%d)\n", This, pos); 132 133 if(pos == 0) { 134 IPin_AddRef(&This->out->pin.pin.IPin_iface); 135 return &This->out->pin.pin.IPin_iface; 136 }else if(pos>0 && pos<=This->input_pin_no) { 137 IPin_AddRef(&This->in[pos-1]->pin.pin.IPin_iface); 138 return &This->in[pos-1]->pin.pin.IPin_iface; 139 } 140 141 return NULL; 142 } 143 144 static LONG WINAPI AviMux_GetPinCount(BaseFilter *iface) 145 { 146 AviMux *This = impl_from_BaseFilter(iface); 147 TRACE("(%p)\n", This); 148 return This->input_pin_no+1; 149 } 150 151 static const BaseFilterFuncTable filter_func_table = { 152 AviMux_GetPin, 153 AviMux_GetPinCount 154 }; 155 156 static inline AviMux* impl_from_IBaseFilter(IBaseFilter *iface) 157 { 158 BaseFilter *filter = CONTAINING_RECORD(iface, BaseFilter, IBaseFilter_iface); 159 return impl_from_BaseFilter(filter); 160 } 161 162 static HRESULT WINAPI AviMux_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv) 163 { 164 AviMux *This = impl_from_IBaseFilter(iface); 165 166 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 167 168 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersist) || 169 IsEqualIID(riid, &IID_IMediaFilter) || IsEqualIID(riid, &IID_IBaseFilter)) 170 *ppv = &This->filter.IBaseFilter_iface; 171 else if(IsEqualIID(riid, &IID_IConfigAviMux)) 172 *ppv = &This->IConfigAviMux_iface; 173 else if(IsEqualIID(riid, &IID_IConfigInterleaving)) 174 *ppv = &This->IConfigInterleaving_iface; 175 else if(IsEqualIID(riid, &IID_IMediaSeeking)) 176 *ppv = &This->IMediaSeeking_iface; 177 else if(IsEqualIID(riid, &IID_IPersistMediaPropertyBag)) 178 *ppv = &This->IPersistMediaPropertyBag_iface; 179 else if(IsEqualIID(riid, &IID_ISpecifyPropertyPages)) 180 *ppv = &This->ISpecifyPropertyPages_iface; 181 else { 182 FIXME("no interface for %s\n", debugstr_guid(riid)); 183 *ppv = NULL; 184 return E_NOINTERFACE; 185 } 186 187 IUnknown_AddRef((IUnknown*)*ppv); 188 return S_OK; 189 } 190 191 static ULONG WINAPI AviMux_Release(IBaseFilter *iface) 192 { 193 AviMux *This = impl_from_IBaseFilter(iface); 194 ULONG ref = BaseFilterImpl_Release(iface); 195 196 TRACE("(%p) new refcount: %u\n", This, ref); 197 198 if(!ref) { 199 int i; 200 201 BaseOutputPinImpl_Release(&This->out->pin.pin.IPin_iface); 202 203 for(i=0; i<This->input_pin_no; i++) { 204 IPin_Disconnect(&This->in[i]->pin.pin.IPin_iface); 205 IMemAllocator_Release(This->in[i]->samples_allocator); 206 This->in[i]->samples_allocator = NULL; 207 BaseInputPinImpl_Release(&This->in[i]->pin.pin.IPin_iface); 208 } 209 210 HeapFree(GetProcessHeap(), 0, This->idx1); 211 HeapFree(GetProcessHeap(), 0, This); 212 ObjectRefCount(FALSE); 213 } 214 return ref; 215 } 216 217 static HRESULT out_flush(AviMux *This) 218 { 219 ULONG written; 220 HRESULT hr; 221 222 if(!This->out->buf_pos) 223 return S_OK; 224 225 hr = IStream_Write(This->out->stream, This->out->buf, This->out->buf_pos, &written); 226 if(FAILED(hr)) 227 return hr; 228 if(written != This->out->buf_pos) 229 return E_FAIL; 230 231 This->out->buf_pos = 0; 232 return S_OK; 233 } 234 235 static HRESULT out_seek(AviMux *This, int pos) 236 { 237 LARGE_INTEGER li; 238 HRESULT hr; 239 240 hr = out_flush(This); 241 if(FAILED(hr)) 242 return hr; 243 244 li.QuadPart = pos; 245 hr = IStream_Seek(This->out->stream, li, STREAM_SEEK_SET, NULL); 246 if(FAILED(hr)) 247 return hr; 248 249 This->out->out_pos = pos; 250 if(This->out->out_pos > This->out->size) 251 This->out->size = This->out->out_pos; 252 return hr; 253 } 254 255 static HRESULT out_write(AviMux *This, const void *data, int size) 256 { 257 int chunk_size; 258 HRESULT hr; 259 260 while(1) { 261 if(size > sizeof(This->out->buf)-This->out->buf_pos) 262 chunk_size = sizeof(This->out->buf)-This->out->buf_pos; 263 else 264 chunk_size = size; 265 266 memcpy(This->out->buf + This->out->buf_pos, data, chunk_size); 267 size -= chunk_size; 268 data = (const BYTE*)data + chunk_size; 269 This->out->buf_pos += chunk_size; 270 This->out->out_pos += chunk_size; 271 if(This->out->out_pos > This->out->size) 272 This->out->size = This->out->out_pos; 273 274 if(!size) 275 break; 276 hr = out_flush(This); 277 if(FAILED(hr)) 278 return hr; 279 } 280 281 return S_OK; 282 } 283 284 static inline HRESULT idx1_add_entry(AviMux *avimux, DWORD ckid, DWORD flags, DWORD off, DWORD len) 285 { 286 if(avimux->idx1_entries == avimux->idx1_size) { 287 AVIINDEXENTRY *new_idx = HeapReAlloc(GetProcessHeap(), 0, avimux->idx1, 288 sizeof(*avimux->idx1)*2*avimux->idx1_size); 289 if(!new_idx) 290 return E_OUTOFMEMORY; 291 292 avimux->idx1_size *= 2; 293 avimux->idx1 = new_idx; 294 } 295 296 avimux->idx1[avimux->idx1_entries].ckid = ckid; 297 avimux->idx1[avimux->idx1_entries].dwFlags = flags; 298 avimux->idx1[avimux->idx1_entries].dwChunkOffset = off; 299 avimux->idx1[avimux->idx1_entries].dwChunkLength = len; 300 avimux->idx1_entries++; 301 return S_OK; 302 } 303 304 static HRESULT flush_queue(AviMux *avimux, AviMuxIn *avimuxin, BOOL closing) 305 { 306 IMediaSample *sample, **prev, **head_prev; 307 BYTE *data; 308 RIFFCHUNK rf; 309 DWORD size; 310 DWORD flags; 311 HRESULT hr; 312 313 if(avimux->out->cur_stream != avimuxin->stream_id) 314 return S_OK; 315 316 while(avimuxin->samples_head) { 317 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev); 318 if(FAILED(hr)) 319 return hr; 320 head_prev--; 321 322 hr = IMediaSample_GetPointer(*head_prev, (BYTE**)&prev); 323 if(FAILED(hr)) 324 return hr; 325 prev--; 326 327 sample = *head_prev; 328 size = IMediaSample_GetActualDataLength(sample); 329 hr = IMediaSample_GetPointer(sample, &data); 330 if(FAILED(hr)) 331 return hr; 332 flags = IMediaSample_IsDiscontinuity(sample)==S_OK ? AM_SAMPLE_TIMEDISCONTINUITY : 0; 333 if(IMediaSample_IsSyncPoint(sample) == S_OK) 334 flags |= AM_SAMPLE_SPLICEPOINT; 335 336 if(avimuxin->stream_time + (closing ? 0 : avimuxin->strh.dwScale) > avimux->out->cur_time && 337 !(flags & AM_SAMPLE_TIMEDISCONTINUITY)) { 338 if(closing) 339 break; 340 341 avimux->out->cur_stream++; 342 if(avimux->out->cur_stream >= avimux->input_pin_no-1) { 343 avimux->out->cur_time += avimux->interleave; 344 avimux->out->cur_stream = 0; 345 } 346 avimuxin = avimux->in[avimux->out->cur_stream]; 347 continue; 348 } 349 350 if(avimuxin->ix->nEntriesInUse == AVISTDINDEX_ENTRIES) { 351 /* TODO: use output pins Deliver/Receive method */ 352 hr = out_seek(avimux, avimuxin->ix_off); 353 if(FAILED(hr)) 354 return hr; 355 hr = out_write(avimux, avimuxin->ix, sizeof(avimuxin->ix_data)); 356 if(FAILED(hr)) 357 return hr; 358 359 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].qwOffset = avimuxin->ix_off; 360 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwSize = sizeof(avimuxin->ix_data); 361 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwDuration = AVISTDINDEX_ENTRIES; 362 avimuxin->indx->nEntriesInUse++; 363 364 memset(avimuxin->ix->aIndex, 0, sizeof(avimuxin->ix->aIndex)*avimuxin->ix->nEntriesInUse); 365 avimuxin->ix->nEntriesInUse = 0; 366 avimuxin->ix->qwBaseOffset = 0; 367 368 avimuxin->ix_off = avimux->out->size; 369 avimux->out->size += sizeof(avimuxin->ix_data); 370 } 371 372 if(*head_prev == avimuxin->samples_head) 373 avimuxin->samples_head = NULL; 374 else 375 *head_prev = *prev; 376 377 avimuxin->stream_time += avimuxin->strh.dwScale; 378 avimuxin->strh.dwLength++; 379 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) { 380 if(!avimuxin->ix->qwBaseOffset) 381 avimuxin->ix->qwBaseOffset = avimux->out->size; 382 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwOffset = avimux->out->size 383 + sizeof(RIFFCHUNK) - avimuxin->ix->qwBaseOffset; 384 385 hr = out_seek(avimux, avimux->out->size); 386 if(FAILED(hr)) { 387 IMediaSample_Release(sample); 388 return hr; 389 } 390 } 391 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwSize = size | 392 (flags & AM_SAMPLE_SPLICEPOINT ? 0 : AVISTDINDEX_DELTAFRAME); 393 avimuxin->ix->nEntriesInUse++; 394 395 rf.fcc = FCC('0'+avimuxin->stream_id/10, '0'+avimuxin->stream_id%10, 396 'd', flags & AM_SAMPLE_SPLICEPOINT ? 'b' : 'c'); 397 rf.cb = size; 398 hr = idx1_add_entry(avimux, rf.fcc, flags & AM_SAMPLE_SPLICEPOINT ? AVIIF_KEYFRAME : 0, 399 flags & AM_SAMPLE_TIMEDISCONTINUITY ? 400 avimux->idx1[avimux->idx1_entries-1].dwChunkOffset : avimux->out->size, size); 401 if(FAILED(hr)) { 402 IMediaSample_Release(sample); 403 return hr; 404 } 405 406 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) { 407 hr = out_write(avimux, &rf, sizeof(rf)); 408 if(FAILED(hr)) { 409 IMediaSample_Release(sample); 410 return hr; 411 } 412 hr = out_write(avimux, data, size); 413 if(FAILED(hr)) { 414 IMediaSample_Release(sample); 415 return hr; 416 } 417 flags = 0; 418 hr = out_write(avimux, &flags, ALIGN(rf.cb)-rf.cb); 419 if(FAILED(hr)) { 420 IMediaSample_Release(sample); 421 return hr; 422 } 423 } 424 IMediaSample_Release(sample); 425 } 426 return S_OK; 427 } 428 429 static HRESULT queue_sample(AviMux *avimux, AviMuxIn *avimuxin, IMediaSample *sample) 430 { 431 IMediaSample **prev, **head_prev; 432 HRESULT hr; 433 434 hr = IMediaSample_GetPointer(sample, (BYTE**)&prev); 435 if(FAILED(hr)) 436 return hr; 437 prev--; 438 439 if(avimuxin->samples_head) { 440 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev); 441 if(FAILED(hr)) 442 return hr; 443 head_prev--; 444 445 *prev = *head_prev; 446 *head_prev = sample; 447 }else { 448 *prev = sample; 449 } 450 avimuxin->samples_head = sample; 451 IMediaSample_AddRef(sample); 452 453 return flush_queue(avimux, avimuxin, FALSE); 454 } 455 456 static HRESULT WINAPI AviMux_Stop(IBaseFilter *iface) 457 { 458 AviMux *This = impl_from_IBaseFilter(iface); 459 HRESULT hr; 460 int i; 461 462 TRACE("(%p)\n", This); 463 464 if(This->filter.state == State_Stopped) 465 return S_OK; 466 467 if(This->out->stream) { 468 AVIEXTHEADER dmlh; 469 RIFFCHUNK rc; 470 RIFFLIST rl; 471 int idx1_off, empty_stream; 472 473 empty_stream = This->out->cur_stream; 474 for(i=empty_stream+1; ; i++) { 475 if(i >= This->input_pin_no-1) 476 i = 0; 477 if(i == empty_stream) 478 break; 479 480 This->out->cur_stream = i; 481 hr = flush_queue(This, This->in[This->out->cur_stream], TRUE); 482 if(FAILED(hr)) 483 return hr; 484 } 485 486 idx1_off = This->out->size; 487 rc.fcc = ckidAVIOLDINDEX; 488 rc.cb = This->idx1_entries * sizeof(*This->idx1); 489 hr = out_write(This, &rc, sizeof(rc)); 490 if(FAILED(hr)) 491 return hr; 492 hr = out_write(This, This->idx1, This->idx1_entries * sizeof(*This->idx1)); 493 if(FAILED(hr)) 494 return hr; 495 /* native writes 8 '\0' characters after the end of RIFF data */ 496 i = 0; 497 hr = out_write(This, &i, sizeof(i)); 498 if(FAILED(hr)) 499 return hr; 500 hr = out_write(This, &i, sizeof(i)); 501 if(FAILED(hr)) 502 return hr; 503 504 for(i=0; i<This->input_pin_no; i++) { 505 if(!This->in[i]->pin.pin.pConnectedTo) 506 continue; 507 508 hr = out_seek(This, This->in[i]->ix_off); 509 if(FAILED(hr)) 510 return hr; 511 512 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].qwOffset = This->in[i]->ix_off; 513 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwSize = sizeof(This->in[i]->ix_data); 514 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration = This->in[i]->strh.dwLength; 515 if(This->in[i]->indx->nEntriesInUse) { 516 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration -= 517 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse-1].dwDuration; 518 } 519 This->in[i]->indx->nEntriesInUse++; 520 hr = out_write(This, This->in[i]->ix, sizeof(This->in[i]->ix_data)); 521 if(FAILED(hr)) 522 return hr; 523 } 524 525 hr = out_seek(This, 0); 526 if(FAILED(hr)) 527 return hr; 528 529 rl.fcc = FCC('R','I','F','F'); 530 rl.cb = This->out->size-sizeof(RIFFCHUNK)-2*sizeof(int); 531 rl.fccListType = FCC('A','V','I',' '); 532 hr = out_write(This, &rl, sizeof(rl)); 533 if(FAILED(hr)) 534 return hr; 535 536 rl.fcc = FCC('L','I','S','T'); 537 rl.cb = This->out->movi_off - sizeof(RIFFLIST) - sizeof(RIFFCHUNK); 538 rl.fccListType = FCC('h','d','r','l'); 539 hr = out_write(This, &rl, sizeof(rl)); 540 if(FAILED(hr)) 541 return hr; 542 543 /* FIXME: set This->avih.dwMaxBytesPerSec value */ 544 This->avih.dwTotalFrames = (This->stop-This->start) / 10 / This->avih.dwMicroSecPerFrame; 545 hr = out_write(This, &This->avih, sizeof(This->avih)); 546 if(FAILED(hr)) 547 return hr; 548 549 for(i=0; i<This->input_pin_no; i++) { 550 if(!This->in[i]->pin.pin.pConnectedTo) 551 continue; 552 553 rl.cb = sizeof(FOURCC) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK) + 554 This->in[i]->strf->cb + sizeof(This->in[i]->indx_data); 555 rl.fccListType = ckidSTREAMLIST; 556 hr = out_write(This, &rl, sizeof(rl)); 557 if(FAILED(hr)) 558 return hr; 559 560 hr = out_write(This, &This->in[i]->strh, sizeof(AVISTREAMHEADER)); 561 if(FAILED(hr)) 562 return hr; 563 564 hr = out_write(This, This->in[i]->strf, sizeof(RIFFCHUNK) + This->in[i]->strf->cb); 565 if(FAILED(hr)) 566 return hr; 567 568 hr = out_write(This, This->in[i]->indx, sizeof(This->in[i]->indx_data)); 569 if(FAILED(hr)) 570 return hr; 571 } 572 573 rl.cb = sizeof(dmlh) + sizeof(FOURCC); 574 rl.fccListType = ckidODML; 575 hr = out_write(This, &rl, sizeof(rl)); 576 if(FAILED(hr)) 577 return hr; 578 579 memset(&dmlh, 0, sizeof(dmlh)); 580 dmlh.fcc = ckidAVIEXTHEADER; 581 dmlh.cb = sizeof(dmlh) - sizeof(RIFFCHUNK); 582 dmlh.dwGrandFrames = This->in[0]->strh.dwLength; 583 hr = out_write(This, &dmlh, sizeof(dmlh)); 584 585 rl.cb = idx1_off - This->out->movi_off - sizeof(RIFFCHUNK); 586 rl.fccListType = FCC('m','o','v','i'); 587 out_write(This, &rl, sizeof(rl)); 588 out_flush(This); 589 590 IStream_Release(This->out->stream); 591 This->out->stream = NULL; 592 } 593 594 This->filter.state = State_Stopped; 595 return S_OK; 596 } 597 598 static HRESULT WINAPI AviMux_Pause(IBaseFilter *iface) 599 { 600 AviMux *This = impl_from_IBaseFilter(iface); 601 FIXME("(%p)\n", This); 602 return E_NOTIMPL; 603 } 604 605 static HRESULT WINAPI AviMux_Run(IBaseFilter *iface, REFERENCE_TIME tStart) 606 { 607 AviMux *This = impl_from_IBaseFilter(iface); 608 HRESULT hr; 609 int i, stream_id; 610 611 TRACE("(%p)->(%s)\n", This, wine_dbgstr_longlong(tStart)); 612 613 if(This->filter.state == State_Running) 614 return S_OK; 615 616 if(This->mode != INTERLEAVE_FULL) { 617 FIXME("mode not supported (%d)\n", This->mode); 618 return E_NOTIMPL; 619 } 620 621 if(tStart) 622 FIXME("tStart parameter ignored\n"); 623 624 for(i=0; i<This->input_pin_no; i++) { 625 IMediaSeeking *ms; 626 LONGLONG cur, stop; 627 628 if(!This->in[i]->pin.pin.pConnectedTo) 629 continue; 630 631 hr = IPin_QueryInterface(This->in[i]->pin.pin.pConnectedTo, 632 &IID_IMediaSeeking, (void**)&ms); 633 if(FAILED(hr)) 634 continue; 635 636 hr = IMediaSeeking_GetPositions(ms, &cur, &stop); 637 if(FAILED(hr)) { 638 IMediaSeeking_Release(ms); 639 continue; 640 } 641 642 FIXME("Use IMediaSeeking to fill stream header\n"); 643 IMediaSeeking_Release(ms); 644 } 645 646 if(This->out->pin.pMemInputPin) { 647 hr = IMemInputPin_QueryInterface(This->out->pin.pMemInputPin, 648 &IID_IStream, (void**)&This->out->stream); 649 if(FAILED(hr)) 650 return hr; 651 } 652 653 This->idx1_entries = 0; 654 if(!This->idx1_size) { 655 This->idx1_size = 1024; 656 This->idx1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->idx1)*This->idx1_size); 657 if(!This->idx1) 658 return E_OUTOFMEMORY; 659 } 660 661 This->out->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER); 662 This->start = -1; 663 This->stop = -1; 664 memset(&This->avih, 0, sizeof(This->avih)); 665 for(i=0; i<This->input_pin_no; i++) { 666 if(!This->in[i]->pin.pin.pConnectedTo) 667 continue; 668 669 This->avih.dwStreams++; 670 This->out->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK) 671 + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data); 672 673 This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000); 674 This->in[i]->strh.dwRate = This->interleave; 675 676 hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator); 677 if(FAILED(hr)) { 678 if(This->out->stream) { 679 IStream_Release(This->out->stream); 680 This->out->stream = NULL; 681 } 682 return hr; 683 } 684 } 685 686 This->out->movi_off = This->out->size; 687 This->out->size += sizeof(RIFFLIST); 688 689 idx1_add_entry(This, FCC('7','F','x','x'), 0, This->out->movi_off+sizeof(RIFFLIST), 0); 690 691 stream_id = 0; 692 for(i=0; i<This->input_pin_no; i++) { 693 if(!This->in[i]->pin.pin.pConnectedTo) 694 continue; 695 696 This->in[i]->ix_off = This->out->size; 697 This->out->size += sizeof(This->in[i]->ix_data); 698 This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10); 699 This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK); 700 This->in[i]->ix->wLongsPerEntry = 2; 701 This->in[i]->ix->bIndexSubType = 0; 702 This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS; 703 This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b'); 704 This->in[i]->ix->qwBaseOffset = 0; 705 706 This->in[i]->indx->fcc = ckidAVISUPERINDEX; 707 This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK); 708 This->in[i]->indx->wLongsPerEntry = 4; 709 This->in[i]->indx->bIndexSubType = 0; 710 This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES; 711 This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId; 712 This->in[i]->stream_id = stream_id++; 713 } 714 715 This->out->buf_pos = 0; 716 This->out->out_pos = 0; 717 718 This->avih.fcc = ckidMAINAVIHEADER; 719 This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK); 720 /* TODO: Use first video stream */ 721 This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10; 722 This->avih.dwPaddingGranularity = 1; 723 This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX; 724 This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth; 725 This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight; 726 727 This->filter.state = State_Running; 728 return S_OK; 729 } 730 731 static HRESULT WINAPI AviMux_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum) 732 { 733 AviMux *This = impl_from_IBaseFilter(iface); 734 TRACE("(%p)->(%p)\n", This, ppEnum); 735 return BaseFilterImpl_EnumPins(iface, ppEnum); 736 } 737 738 static HRESULT WINAPI AviMux_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin) 739 { 740 AviMux *This = impl_from_IBaseFilter(iface); 741 int i; 742 743 TRACE("(%p)->(%s %p)\n", This, debugstr_w(Id), ppPin); 744 745 if(!Id || !ppPin) 746 return E_POINTER; 747 748 if(!lstrcmpiW(Id, This->out->pin.pin.pinInfo.achName)) { 749 IPin_AddRef(&This->out->pin.pin.IPin_iface); 750 *ppPin = &This->out->pin.pin.IPin_iface; 751 return S_OK; 752 } 753 754 for(i=0; i<This->input_pin_no; i++) { 755 if(lstrcmpiW(Id, This->in[i]->pin.pin.pinInfo.achName)) 756 continue; 757 758 IPin_AddRef(&This->in[i]->pin.pin.IPin_iface); 759 *ppPin = &This->in[i]->pin.pin.IPin_iface; 760 return S_OK; 761 } 762 763 return VFW_E_NOT_FOUND; 764 } 765 766 static HRESULT WINAPI AviMux_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo) 767 { 768 AviMux *This = impl_from_IBaseFilter(iface); 769 FIXME("(%p)->(%p)\n", This, pInfo); 770 return E_NOTIMPL; 771 } 772 773 static HRESULT WINAPI AviMux_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo) 774 { 775 AviMux *This = impl_from_IBaseFilter(iface); 776 FIXME("(%p)->(%p)\n", This, pVendorInfo); 777 return E_NOTIMPL; 778 } 779 780 static const IBaseFilterVtbl AviMuxVtbl = { 781 AviMux_QueryInterface, 782 BaseFilterImpl_AddRef, 783 AviMux_Release, 784 BaseFilterImpl_GetClassID, 785 AviMux_Stop, 786 AviMux_Pause, 787 AviMux_Run, 788 BaseFilterImpl_GetState, 789 BaseFilterImpl_SetSyncSource, 790 BaseFilterImpl_GetSyncSource, 791 AviMux_EnumPins, 792 AviMux_FindPin, 793 AviMux_QueryFilterInfo, 794 BaseFilterImpl_JoinFilterGraph, 795 AviMux_QueryVendorInfo 796 }; 797 798 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface) 799 { 800 return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface); 801 } 802 803 static HRESULT WINAPI ConfigAviMux_QueryInterface( 804 IConfigAviMux *iface, REFIID riid, void **ppv) 805 { 806 AviMux *This = impl_from_IConfigAviMux(iface); 807 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 808 } 809 810 static ULONG WINAPI ConfigAviMux_AddRef(IConfigAviMux *iface) 811 { 812 AviMux *This = impl_from_IConfigAviMux(iface); 813 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 814 } 815 816 static ULONG WINAPI ConfigAviMux_Release(IConfigAviMux *iface) 817 { 818 AviMux *This = impl_from_IConfigAviMux(iface); 819 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 820 } 821 822 static HRESULT WINAPI ConfigAviMux_SetMasterStream(IConfigAviMux *iface, LONG iStream) 823 { 824 AviMux *This = impl_from_IConfigAviMux(iface); 825 FIXME("(%p)->(%d)\n", This, iStream); 826 return E_NOTIMPL; 827 } 828 829 static HRESULT WINAPI ConfigAviMux_GetMasterStream(IConfigAviMux *iface, LONG *pStream) 830 { 831 AviMux *This = impl_from_IConfigAviMux(iface); 832 FIXME("(%p)->(%p)\n", This, pStream); 833 return E_NOTIMPL; 834 } 835 836 static HRESULT WINAPI ConfigAviMux_SetOutputCompatibilityIndex( 837 IConfigAviMux *iface, BOOL fOldIndex) 838 { 839 AviMux *This = impl_from_IConfigAviMux(iface); 840 FIXME("(%p)->(%x)\n", This, fOldIndex); 841 return E_NOTIMPL; 842 } 843 844 static HRESULT WINAPI ConfigAviMux_GetOutputCompatibilityIndex( 845 IConfigAviMux *iface, BOOL *pfOldIndex) 846 { 847 AviMux *This = impl_from_IConfigAviMux(iface); 848 FIXME("(%p)->(%p)\n", This, pfOldIndex); 849 return E_NOTIMPL; 850 } 851 852 static const IConfigAviMuxVtbl ConfigAviMuxVtbl = { 853 ConfigAviMux_QueryInterface, 854 ConfigAviMux_AddRef, 855 ConfigAviMux_Release, 856 ConfigAviMux_SetMasterStream, 857 ConfigAviMux_GetMasterStream, 858 ConfigAviMux_SetOutputCompatibilityIndex, 859 ConfigAviMux_GetOutputCompatibilityIndex 860 }; 861 862 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface) 863 { 864 return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface); 865 } 866 867 static HRESULT WINAPI ConfigInterleaving_QueryInterface( 868 IConfigInterleaving *iface, REFIID riid, void **ppv) 869 { 870 AviMux *This = impl_from_IConfigInterleaving(iface); 871 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 872 } 873 874 static ULONG WINAPI ConfigInterleaving_AddRef(IConfigInterleaving *iface) 875 { 876 AviMux *This = impl_from_IConfigInterleaving(iface); 877 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 878 } 879 880 static ULONG WINAPI ConfigInterleaving_Release(IConfigInterleaving *iface) 881 { 882 AviMux *This = impl_from_IConfigInterleaving(iface); 883 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 884 } 885 886 static HRESULT WINAPI ConfigInterleaving_put_Mode( 887 IConfigInterleaving *iface, InterleavingMode mode) 888 { 889 AviMux *This = impl_from_IConfigInterleaving(iface); 890 891 TRACE("(%p)->(%d)\n", This, mode); 892 893 if(mode>INTERLEAVE_NONE_BUFFERED) 894 return E_INVALIDARG; 895 896 if(This->mode != mode) { 897 if(This->out->pin.pin.pConnectedTo) { 898 HRESULT hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, 899 &This->out->pin.pin.IPin_iface); 900 if(FAILED(hr)) 901 return hr; 902 } 903 904 This->mode = mode; 905 } 906 907 return S_OK; 908 } 909 910 static HRESULT WINAPI ConfigInterleaving_get_Mode( 911 IConfigInterleaving *iface, InterleavingMode *pMode) 912 { 913 AviMux *This = impl_from_IConfigInterleaving(iface); 914 FIXME("(%p)->(%p)\n", This, pMode); 915 return E_NOTIMPL; 916 } 917 918 static HRESULT WINAPI ConfigInterleaving_put_Interleaving(IConfigInterleaving *iface, 919 const REFERENCE_TIME *prtInterleave, const REFERENCE_TIME *prtPreroll) 920 { 921 AviMux *This = impl_from_IConfigInterleaving(iface); 922 923 TRACE("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll); 924 925 if(prtInterleave) 926 This->interleave = *prtInterleave; 927 if(prtPreroll) 928 This->preroll = *prtPreroll; 929 return S_OK; 930 } 931 932 static HRESULT WINAPI ConfigInterleaving_get_Interleaving(IConfigInterleaving *iface, 933 REFERENCE_TIME *prtInterleave, REFERENCE_TIME *prtPreroll) 934 { 935 AviMux *This = impl_from_IConfigInterleaving(iface); 936 FIXME("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll); 937 return E_NOTIMPL; 938 } 939 940 static const IConfigInterleavingVtbl ConfigInterleavingVtbl = { 941 ConfigInterleaving_QueryInterface, 942 ConfigInterleaving_AddRef, 943 ConfigInterleaving_Release, 944 ConfigInterleaving_put_Mode, 945 ConfigInterleaving_get_Mode, 946 ConfigInterleaving_put_Interleaving, 947 ConfigInterleaving_get_Interleaving 948 }; 949 950 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface) 951 { 952 return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface); 953 } 954 955 static HRESULT WINAPI MediaSeeking_QueryInterface( 956 IMediaSeeking *iface, REFIID riid, void **ppv) 957 { 958 AviMux *This = impl_from_IMediaSeeking(iface); 959 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 960 } 961 962 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface) 963 { 964 AviMux *This = impl_from_IMediaSeeking(iface); 965 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 966 } 967 968 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface) 969 { 970 AviMux *This = impl_from_IMediaSeeking(iface); 971 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 972 } 973 974 static HRESULT WINAPI MediaSeeking_GetCapabilities( 975 IMediaSeeking *iface, DWORD *pCapabilities) 976 { 977 AviMux *This = impl_from_IMediaSeeking(iface); 978 FIXME("(%p)->(%p)\n", This, pCapabilities); 979 return E_NOTIMPL; 980 } 981 982 static HRESULT WINAPI MediaSeeking_CheckCapabilities( 983 IMediaSeeking *iface, DWORD *pCapabilities) 984 { 985 AviMux *This = impl_from_IMediaSeeking(iface); 986 FIXME("(%p)->(%p)\n", This, pCapabilities); 987 return E_NOTIMPL; 988 } 989 990 static HRESULT WINAPI MediaSeeking_IsFormatSupported( 991 IMediaSeeking *iface, const GUID *pFormat) 992 { 993 AviMux *This = impl_from_IMediaSeeking(iface); 994 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat)); 995 return E_NOTIMPL; 996 } 997 998 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat( 999 IMediaSeeking *iface, GUID *pFormat) 1000 { 1001 AviMux *This = impl_from_IMediaSeeking(iface); 1002 FIXME("(%p)->(%p)\n", This, pFormat); 1003 return E_NOTIMPL; 1004 } 1005 1006 static HRESULT WINAPI MediaSeeking_GetTimeFormat( 1007 IMediaSeeking *iface, GUID *pFormat) 1008 { 1009 AviMux *This = impl_from_IMediaSeeking(iface); 1010 FIXME("(%p)->(%p)\n", This, pFormat); 1011 return E_NOTIMPL; 1012 } 1013 1014 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat( 1015 IMediaSeeking *iface, const GUID *pFormat) 1016 { 1017 AviMux *This = impl_from_IMediaSeeking(iface); 1018 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat)); 1019 return E_NOTIMPL; 1020 } 1021 1022 static HRESULT WINAPI MediaSeeking_SetTimeFormat( 1023 IMediaSeeking *iface, const GUID *pFormat) 1024 { 1025 AviMux *This = impl_from_IMediaSeeking(iface); 1026 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat)); 1027 return E_NOTIMPL; 1028 } 1029 1030 static HRESULT WINAPI MediaSeeking_GetDuration( 1031 IMediaSeeking *iface, LONGLONG *pDuration) 1032 { 1033 AviMux *This = impl_from_IMediaSeeking(iface); 1034 FIXME("(%p)->(%p)\n", This, pDuration); 1035 return E_NOTIMPL; 1036 } 1037 1038 static HRESULT WINAPI MediaSeeking_GetStopPosition( 1039 IMediaSeeking *iface, LONGLONG *pStop) 1040 { 1041 AviMux *This = impl_from_IMediaSeeking(iface); 1042 FIXME("(%p)->(%p)\n", This, pStop); 1043 return E_NOTIMPL; 1044 } 1045 1046 static HRESULT WINAPI MediaSeeking_GetCurrentPosition( 1047 IMediaSeeking *iface, LONGLONG *pCurrent) 1048 { 1049 AviMux *This = impl_from_IMediaSeeking(iface); 1050 FIXME("(%p)->(%p)\n", This, pCurrent); 1051 return E_NOTIMPL; 1052 } 1053 1054 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget, 1055 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat) 1056 { 1057 AviMux *This = impl_from_IMediaSeeking(iface); 1058 FIXME("(%p)->(%p %s %s %s)\n", This, pTarget, debugstr_guid(pTargetFormat), 1059 wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat)); 1060 return E_NOTIMPL; 1061 } 1062 1063 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent, 1064 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags) 1065 { 1066 AviMux *This = impl_from_IMediaSeeking(iface); 1067 FIXME("(%p)->(%p %x %p %x)\n", This, pCurrent, dwCurrentFlags, pStop, dwStopFlags); 1068 return E_NOTIMPL; 1069 } 1070 1071 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface, 1072 LONGLONG *pCurrent, LONGLONG *pStop) 1073 { 1074 AviMux *This = impl_from_IMediaSeeking(iface); 1075 FIXME("(%p)->(%p %p)\n", This, pCurrent, pStop); 1076 return E_NOTIMPL; 1077 } 1078 1079 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, 1080 LONGLONG *pEarliest, LONGLONG *pLatest) 1081 { 1082 AviMux *This = impl_from_IMediaSeeking(iface); 1083 FIXME("(%p)->(%p %p)\n", This, pEarliest, pLatest); 1084 return E_NOTIMPL; 1085 } 1086 1087 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate) 1088 { 1089 AviMux *This = impl_from_IMediaSeeking(iface); 1090 FIXME("(%p)->(%lf)\n", This, dRate); 1091 return E_NOTIMPL; 1092 } 1093 1094 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate) 1095 { 1096 AviMux *This = impl_from_IMediaSeeking(iface); 1097 FIXME("(%p)->(%p)\n", This, pdRate); 1098 return E_NOTIMPL; 1099 } 1100 1101 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll) 1102 { 1103 AviMux *This = impl_from_IMediaSeeking(iface); 1104 FIXME("(%p)->(%p)\n", This, pllPreroll); 1105 return E_NOTIMPL; 1106 } 1107 1108 static const IMediaSeekingVtbl MediaSeekingVtbl = { 1109 MediaSeeking_QueryInterface, 1110 MediaSeeking_AddRef, 1111 MediaSeeking_Release, 1112 MediaSeeking_GetCapabilities, 1113 MediaSeeking_CheckCapabilities, 1114 MediaSeeking_IsFormatSupported, 1115 MediaSeeking_QueryPreferredFormat, 1116 MediaSeeking_GetTimeFormat, 1117 MediaSeeking_IsUsingTimeFormat, 1118 MediaSeeking_SetTimeFormat, 1119 MediaSeeking_GetDuration, 1120 MediaSeeking_GetStopPosition, 1121 MediaSeeking_GetCurrentPosition, 1122 MediaSeeking_ConvertTimeFormat, 1123 MediaSeeking_SetPositions, 1124 MediaSeeking_GetPositions, 1125 MediaSeeking_GetAvailable, 1126 MediaSeeking_SetRate, 1127 MediaSeeking_GetRate, 1128 MediaSeeking_GetPreroll 1129 }; 1130 1131 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface) 1132 { 1133 return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface); 1134 } 1135 1136 static HRESULT WINAPI PersistMediaPropertyBag_QueryInterface( 1137 IPersistMediaPropertyBag *iface, REFIID riid, void **ppv) 1138 { 1139 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1140 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 1141 } 1142 1143 static ULONG WINAPI PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag *iface) 1144 { 1145 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1146 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 1147 } 1148 1149 static ULONG WINAPI PersistMediaPropertyBag_Release(IPersistMediaPropertyBag *iface) 1150 { 1151 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1152 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 1153 } 1154 1155 static HRESULT WINAPI PersistMediaPropertyBag_GetClassID( 1156 IPersistMediaPropertyBag *iface, CLSID *pClassID) 1157 { 1158 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1159 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID); 1160 } 1161 1162 static HRESULT WINAPI PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag *iface) 1163 { 1164 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1165 FIXME("(%p)->()\n", This); 1166 return E_NOTIMPL; 1167 } 1168 1169 static HRESULT WINAPI PersistMediaPropertyBag_Load(IPersistMediaPropertyBag *iface, 1170 IMediaPropertyBag *pPropBag, IErrorLog *pErrorLog) 1171 { 1172 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1173 FIXME("(%p)->()\n", This); 1174 return E_NOTIMPL; 1175 } 1176 1177 static HRESULT WINAPI PersistMediaPropertyBag_Save(IPersistMediaPropertyBag *iface, 1178 IMediaPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) 1179 { 1180 AviMux *This = impl_from_IPersistMediaPropertyBag(iface); 1181 FIXME("(%p)->()\n", This); 1182 return E_NOTIMPL; 1183 } 1184 1185 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl = { 1186 PersistMediaPropertyBag_QueryInterface, 1187 PersistMediaPropertyBag_AddRef, 1188 PersistMediaPropertyBag_Release, 1189 PersistMediaPropertyBag_GetClassID, 1190 PersistMediaPropertyBag_InitNew, 1191 PersistMediaPropertyBag_Load, 1192 PersistMediaPropertyBag_Save 1193 }; 1194 1195 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface) 1196 { 1197 return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface); 1198 } 1199 1200 static HRESULT WINAPI SpecifyPropertyPages_QueryInterface( 1201 ISpecifyPropertyPages *iface, REFIID riid, void **ppv) 1202 { 1203 AviMux *This = impl_from_ISpecifyPropertyPages(iface); 1204 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); 1205 } 1206 1207 static ULONG WINAPI SpecifyPropertyPages_AddRef(ISpecifyPropertyPages *iface) 1208 { 1209 AviMux *This = impl_from_ISpecifyPropertyPages(iface); 1210 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 1211 } 1212 1213 static ULONG WINAPI SpecifyPropertyPages_Release(ISpecifyPropertyPages *iface) 1214 { 1215 AviMux *This = impl_from_ISpecifyPropertyPages(iface); 1216 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 1217 } 1218 1219 static HRESULT WINAPI SpecifyPropertyPages_GetPages( 1220 ISpecifyPropertyPages *iface, CAUUID *pPages) 1221 { 1222 AviMux *This = impl_from_ISpecifyPropertyPages(iface); 1223 FIXME("(%p)->(%p)\n", This, pPages); 1224 return E_NOTIMPL; 1225 } 1226 1227 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = { 1228 SpecifyPropertyPages_QueryInterface, 1229 SpecifyPropertyPages_AddRef, 1230 SpecifyPropertyPages_Release, 1231 SpecifyPropertyPages_GetPages 1232 }; 1233 1234 static HRESULT WINAPI AviMuxOut_AttemptConnection(BasePin *base, 1235 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) 1236 { 1237 PIN_DIRECTION dir; 1238 HRESULT hr; 1239 1240 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", base, pReceivePin, pmt); 1241 dump_AM_MEDIA_TYPE(pmt); 1242 1243 hr = IPin_QueryDirection(pReceivePin, &dir); 1244 if(hr==S_OK && dir!=PINDIR_INPUT) 1245 return VFW_E_INVALID_DIRECTION; 1246 1247 return BaseOutputPinImpl_AttemptConnection(base, pReceivePin, pmt); 1248 } 1249 1250 static LONG WINAPI AviMuxOut_GetMediaTypeVersion(BasePin *base) 1251 { 1252 return 0; 1253 } 1254 1255 static HRESULT WINAPI AviMuxOut_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt) 1256 { 1257 TRACE("(%p)->(%d %p)\n", base, iPosition, amt); 1258 1259 if(iPosition < 0) 1260 return E_INVALIDARG; 1261 if(iPosition > 0) 1262 return VFW_S_NO_MORE_ITEMS; 1263 1264 amt->majortype = MEDIATYPE_Stream; 1265 amt->subtype = MEDIASUBTYPE_Avi; 1266 amt->bFixedSizeSamples = TRUE; 1267 amt->bTemporalCompression = FALSE; 1268 amt->lSampleSize = 1; 1269 amt->formattype = GUID_NULL; 1270 amt->pUnk = NULL; 1271 amt->cbFormat = 0; 1272 amt->pbFormat = NULL; 1273 return S_OK; 1274 } 1275 1276 static HRESULT WINAPI AviMuxOut_DecideAllocator(BaseOutputPin *base, 1277 IMemInputPin *pPin, IMemAllocator **pAlloc) 1278 { 1279 ALLOCATOR_PROPERTIES req, actual; 1280 HRESULT hr; 1281 1282 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc); 1283 1284 hr = BaseOutputPinImpl_InitAllocator(base, pAlloc); 1285 if(FAILED(hr)) 1286 return hr; 1287 1288 hr = IMemInputPin_GetAllocatorRequirements(pPin, &req); 1289 if(FAILED(hr)) 1290 req.cbAlign = 1; 1291 req.cBuffers = 32; 1292 req.cbBuffer = 0; 1293 req.cbPrefix = 0; 1294 1295 hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual); 1296 if(FAILED(hr)) 1297 return hr; 1298 1299 return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE); 1300 } 1301 1302 static HRESULT WINAPI AviMuxOut_BreakConnect(BaseOutputPin *base) 1303 { 1304 FIXME("(%p)\n", base); 1305 return E_NOTIMPL; 1306 } 1307 1308 static const BaseOutputPinFuncTable AviMuxOut_BaseOutputFuncTable = { 1309 { 1310 NULL, 1311 AviMuxOut_AttemptConnection, 1312 AviMuxOut_GetMediaTypeVersion, 1313 AviMuxOut_GetMediaType 1314 }, 1315 NULL, 1316 AviMuxOut_DecideAllocator, 1317 AviMuxOut_BreakConnect 1318 }; 1319 1320 static inline AviMux* impl_from_out_IPin(IPin *iface) 1321 { 1322 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface); 1323 IBaseFilter *bf = bp->pinInfo.pFilter; 1324 1325 return impl_from_IBaseFilter(bf); 1326 } 1327 1328 static HRESULT WINAPI AviMuxOut_QueryInterface(IPin *iface, REFIID riid, void **ppv) 1329 { 1330 AviMux *This = impl_from_out_IPin(iface); 1331 1332 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 1333 1334 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) 1335 *ppv = iface; 1336 else if(IsEqualIID(riid, &IID_IQualityControl)) 1337 *ppv = &This->out->IQualityControl_iface; 1338 else { 1339 FIXME("no interface for %s\n", debugstr_guid(riid)); 1340 *ppv = NULL; 1341 return E_NOINTERFACE; 1342 } 1343 1344 IUnknown_AddRef((IUnknown*)*ppv); 1345 return S_OK; 1346 } 1347 1348 static ULONG WINAPI AviMuxOut_AddRef(IPin *iface) 1349 { 1350 AviMux *This = impl_from_out_IPin(iface); 1351 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 1352 } 1353 1354 static ULONG WINAPI AviMuxOut_Release(IPin *iface) 1355 { 1356 AviMux *This = impl_from_out_IPin(iface); 1357 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 1358 } 1359 1360 static HRESULT WINAPI AviMuxOut_Connect(IPin *iface, 1361 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) 1362 { 1363 AviMux *This = impl_from_out_IPin(iface); 1364 HRESULT hr; 1365 int i; 1366 1367 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", This, pReceivePin, pmt); 1368 dump_AM_MEDIA_TYPE(pmt); 1369 1370 hr = BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); 1371 if(FAILED(hr)) 1372 return hr; 1373 1374 for(i=0; i<This->input_pin_no; i++) { 1375 if(!This->in[i]->pin.pin.pConnectedTo) 1376 continue; 1377 1378 hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, &This->in[i]->pin.pin.IPin_iface); 1379 if(FAILED(hr)) { 1380 BaseOutputPinImpl_Disconnect(iface); 1381 break; 1382 } 1383 } 1384 1385 if(hr == S_OK) 1386 IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 1387 return hr; 1388 } 1389 1390 static HRESULT WINAPI AviMuxOut_ReceiveConnection(IPin *iface, 1391 IPin *pConnector, const AM_MEDIA_TYPE *pmt) 1392 { 1393 AviMux *This = impl_from_out_IPin(iface); 1394 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p)\n", This, pConnector, pmt); 1395 dump_AM_MEDIA_TYPE(pmt); 1396 return BaseOutputPinImpl_ReceiveConnection(iface, pConnector, pmt); 1397 } 1398 1399 static HRESULT WINAPI AviMuxOut_Disconnect(IPin *iface) 1400 { 1401 AviMux *This = impl_from_out_IPin(iface); 1402 HRESULT hr; 1403 1404 TRACE("(%p)\n", This); 1405 1406 hr = BaseOutputPinImpl_Disconnect(iface); 1407 if(hr == S_OK) 1408 IBaseFilter_Release(&This->filter.IBaseFilter_iface); 1409 return hr; 1410 } 1411 1412 static HRESULT WINAPI AviMuxOut_ConnectedTo(IPin *iface, IPin **pPin) 1413 { 1414 AviMux *This = impl_from_out_IPin(iface); 1415 TRACE("(%p)->(%p)\n", This, pPin); 1416 return BasePinImpl_ConnectedTo(iface, pPin); 1417 } 1418 1419 static HRESULT WINAPI AviMuxOut_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt) 1420 { 1421 AviMux *This = impl_from_out_IPin(iface); 1422 TRACE("(%p)->(%p)\n", This, pmt); 1423 return BasePinImpl_ConnectionMediaType(iface, pmt); 1424 } 1425 1426 static HRESULT WINAPI AviMuxOut_QueryPinInfo(IPin *iface, PIN_INFO *pInfo) 1427 { 1428 AviMux *This = impl_from_out_IPin(iface); 1429 TRACE("(%p)->(%p)\n", This, pInfo); 1430 return BasePinImpl_QueryPinInfo(iface, pInfo); 1431 } 1432 1433 static HRESULT WINAPI AviMuxOut_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir) 1434 { 1435 AviMux *This = impl_from_out_IPin(iface); 1436 TRACE("(%p)->(%p)\n", This, pPinDir); 1437 return BasePinImpl_QueryDirection(iface, pPinDir); 1438 } 1439 1440 static HRESULT WINAPI AviMuxOut_QueryId(IPin *iface, LPWSTR *Id) 1441 { 1442 AviMux *This = impl_from_out_IPin(iface); 1443 TRACE("(%p)->(%p)\n", This, Id); 1444 return BasePinImpl_QueryId(iface, Id); 1445 } 1446 1447 static HRESULT WINAPI AviMuxOut_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) 1448 { 1449 AviMux *This = impl_from_out_IPin(iface); 1450 TRACE("(%p)->(AM_MEDIA_TYPE(%p))\n", This, pmt); 1451 dump_AM_MEDIA_TYPE(pmt); 1452 return BasePinImpl_QueryAccept(iface, pmt); 1453 } 1454 1455 static HRESULT WINAPI AviMuxOut_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) 1456 { 1457 AviMux *This = impl_from_out_IPin(iface); 1458 TRACE("(%p)->(%p)\n", This, ppEnum); 1459 return BasePinImpl_EnumMediaTypes(iface, ppEnum); 1460 } 1461 1462 static HRESULT WINAPI AviMuxOut_QueryInternalConnections( 1463 IPin *iface, IPin **apPin, ULONG *nPin) 1464 { 1465 AviMux *This = impl_from_out_IPin(iface); 1466 FIXME("(%p)->(%p %p)\n", This, apPin, nPin); 1467 return E_NOTIMPL; 1468 } 1469 1470 static HRESULT WINAPI AviMuxOut_EndOfStream(IPin *iface) 1471 { 1472 AviMux *This = impl_from_out_IPin(iface); 1473 TRACE("(%p)\n", This); 1474 return BaseOutputPinImpl_EndOfStream(iface); 1475 } 1476 1477 static HRESULT WINAPI AviMuxOut_BeginFlush(IPin *iface) 1478 { 1479 AviMux *This = impl_from_out_IPin(iface); 1480 TRACE("(%p)\n", This); 1481 return BaseOutputPinImpl_BeginFlush(iface); 1482 } 1483 1484 static HRESULT WINAPI AviMuxOut_EndFlush(IPin *iface) 1485 { 1486 AviMux *This = impl_from_out_IPin(iface); 1487 TRACE("(%p)\n", This); 1488 return BaseOutputPinImpl_EndFlush(iface); 1489 } 1490 1491 static HRESULT WINAPI AviMuxOut_NewSegment(IPin *iface, REFERENCE_TIME tStart, 1492 REFERENCE_TIME tStop, double dRate) 1493 { 1494 AviMux *This = impl_from_out_IPin(iface); 1495 TRACE("(%p)->(%s %s %f)\n", This, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); 1496 return BasePinImpl_NewSegment(iface, tStart, tStop, dRate); 1497 } 1498 1499 static const IPinVtbl AviMuxOut_PinVtbl = { 1500 AviMuxOut_QueryInterface, 1501 AviMuxOut_AddRef, 1502 AviMuxOut_Release, 1503 AviMuxOut_Connect, 1504 AviMuxOut_ReceiveConnection, 1505 AviMuxOut_Disconnect, 1506 AviMuxOut_ConnectedTo, 1507 AviMuxOut_ConnectionMediaType, 1508 AviMuxOut_QueryPinInfo, 1509 AviMuxOut_QueryDirection, 1510 AviMuxOut_QueryId, 1511 AviMuxOut_QueryAccept, 1512 AviMuxOut_EnumMediaTypes, 1513 AviMuxOut_QueryInternalConnections, 1514 AviMuxOut_EndOfStream, 1515 AviMuxOut_BeginFlush, 1516 AviMuxOut_EndFlush, 1517 AviMuxOut_NewSegment 1518 }; 1519 1520 static inline AviMux* impl_from_out_IQualityControl(IQualityControl *iface) 1521 { 1522 AviMuxOut *amo = CONTAINING_RECORD(iface, AviMuxOut, IQualityControl_iface); 1523 return impl_from_IBaseFilter(amo->pin.pin.pinInfo.pFilter); 1524 } 1525 1526 static HRESULT WINAPI AviMuxOut_QualityControl_QueryInterface( 1527 IQualityControl *iface, REFIID riid, void **ppv) 1528 { 1529 AviMux *This = impl_from_out_IQualityControl(iface); 1530 return IPin_QueryInterface(&This->out->pin.pin.IPin_iface, riid, ppv); 1531 } 1532 1533 static ULONG WINAPI AviMuxOut_QualityControl_AddRef(IQualityControl *iface) 1534 { 1535 AviMux *This = impl_from_out_IQualityControl(iface); 1536 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 1537 } 1538 1539 static ULONG WINAPI AviMuxOut_QualityControl_Release(IQualityControl *iface) 1540 { 1541 AviMux *This = impl_from_out_IQualityControl(iface); 1542 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 1543 } 1544 1545 static HRESULT WINAPI AviMuxOut_QualityControl_Notify(IQualityControl *iface, 1546 IBaseFilter *pSelf, Quality q) 1547 { 1548 AviMux *This = impl_from_out_IQualityControl(iface); 1549 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This, pSelf, 1550 q.Type, q.Proportion, 1551 wine_dbgstr_longlong(q.Late), 1552 wine_dbgstr_longlong(q.TimeStamp)); 1553 return E_NOTIMPL; 1554 } 1555 1556 static HRESULT WINAPI AviMuxOut_QualityControl_SetSink( 1557 IQualityControl *iface, IQualityControl *piqc) 1558 { 1559 AviMux *This = impl_from_out_IQualityControl(iface); 1560 FIXME("(%p)->(%p)\n", This, piqc); 1561 return E_NOTIMPL; 1562 } 1563 1564 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl = { 1565 AviMuxOut_QualityControl_QueryInterface, 1566 AviMuxOut_QualityControl_AddRef, 1567 AviMuxOut_QualityControl_Release, 1568 AviMuxOut_QualityControl_Notify, 1569 AviMuxOut_QualityControl_SetSink 1570 }; 1571 1572 static HRESULT WINAPI AviMuxIn_CheckMediaType(BasePin *base, const AM_MEDIA_TYPE *pmt) 1573 { 1574 TRACE("(%p:%s)->(AM_MEDIA_TYPE(%p))\n", base, debugstr_w(base->pinInfo.achName), pmt); 1575 dump_AM_MEDIA_TYPE(pmt); 1576 1577 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) && 1578 IsEqualIID(&pmt->formattype, &FORMAT_WaveFormatEx)) 1579 return S_OK; 1580 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Interleaved) && 1581 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo)) 1582 return S_OK; 1583 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) && 1584 (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo) || 1585 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo))) 1586 return S_OK; 1587 return S_FALSE; 1588 } 1589 1590 static LONG WINAPI AviMuxIn_GetMediaTypeVersion(BasePin *base) 1591 { 1592 return 0; 1593 } 1594 1595 static HRESULT WINAPI AviMuxIn_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt) 1596 { 1597 return S_FALSE; 1598 } 1599 1600 static HRESULT WINAPI AviMuxIn_Receive(BaseInputPin *base, IMediaSample *pSample) 1601 { 1602 AviMuxIn *avimuxin = CONTAINING_RECORD(base, AviMuxIn, pin); 1603 AviMux *avimux = impl_from_IBaseFilter(base->pin.pinInfo.pFilter); 1604 REFERENCE_TIME start, stop; 1605 IMediaSample *sample; 1606 int frames_no; 1607 IMediaSample2 *ms2; 1608 BYTE *frame, *buf; 1609 DWORD max_size, size; 1610 DWORD flags; 1611 HRESULT hr; 1612 1613 TRACE("(%p:%s)->(%p)\n", base, debugstr_w(base->pin.pinInfo.achName), pSample); 1614 1615 hr = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&ms2); 1616 if(SUCCEEDED(hr)) { 1617 AM_SAMPLE2_PROPERTIES props; 1618 1619 memset(&props, 0, sizeof(props)); 1620 hr = IMediaSample2_GetProperties(ms2, sizeof(props), (BYTE*)&props); 1621 IMediaSample2_Release(ms2); 1622 if(FAILED(hr)) 1623 return hr; 1624 1625 flags = props.dwSampleFlags; 1626 frame = props.pbBuffer; 1627 size = props.lActual; 1628 }else { 1629 flags = IMediaSample_IsSyncPoint(pSample) == S_OK ? AM_SAMPLE_SPLICEPOINT : 0; 1630 hr = IMediaSample_GetPointer(pSample, &frame); 1631 if(FAILED(hr)) 1632 return hr; 1633 size = IMediaSample_GetActualDataLength(pSample); 1634 } 1635 1636 if(!avimuxin->pin.pin.mtCurrent.bTemporalCompression) 1637 flags |= AM_SAMPLE_SPLICEPOINT; 1638 1639 hr = IMediaSample_GetTime(pSample, &start, &stop); 1640 if(FAILED(hr)) 1641 return hr; 1642 1643 if(avimuxin->stop>stop) 1644 return VFW_E_START_TIME_AFTER_END; 1645 1646 if(avimux->start == -1) 1647 avimux->start = start; 1648 if(avimux->stop < stop) 1649 avimux->stop = stop; 1650 1651 if(avimux->avih.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK)) 1652 avimux->avih.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK); 1653 if(avimuxin->strh.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK)) 1654 avimuxin->strh.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK); 1655 1656 frames_no = 1; 1657 if(avimuxin->stop!=-1 && start > avimuxin->stop) { 1658 frames_no += (double)(start - avimuxin->stop) / 10000000 1659 * avimuxin->strh.dwRate / avimuxin->strh.dwScale + 0.5; 1660 } 1661 avimuxin->stop = stop; 1662 1663 while(--frames_no) { 1664 /* TODO: store all control frames in one buffer */ 1665 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0); 1666 if(FAILED(hr)) 1667 return hr; 1668 hr = IMediaSample_SetActualDataLength(sample, 0); 1669 if(SUCCEEDED(hr)) 1670 hr = IMediaSample_SetDiscontinuity(sample, TRUE); 1671 if(SUCCEEDED(hr)) 1672 hr = IMediaSample_SetSyncPoint(sample, FALSE); 1673 if(SUCCEEDED(hr)) 1674 hr = queue_sample(avimux, avimuxin, sample); 1675 IMediaSample_Release(sample); 1676 if(FAILED(hr)) 1677 return hr; 1678 } 1679 1680 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0); 1681 if(FAILED(hr)) 1682 return hr; 1683 max_size = IMediaSample_GetSize(sample); 1684 if(size > max_size) 1685 size = max_size; 1686 hr = IMediaSample_SetActualDataLength(sample, size); 1687 if(SUCCEEDED(hr)) 1688 hr = IMediaSample_SetDiscontinuity(sample, FALSE); 1689 if(SUCCEEDED(hr)) 1690 hr = IMediaSample_SetSyncPoint(sample, flags & AM_SAMPLE_SPLICEPOINT); 1691 /* TODO: avoid unnecessary copying */ 1692 if(SUCCEEDED(hr)) 1693 hr = IMediaSample_GetPointer(sample, &buf); 1694 if(SUCCEEDED(hr)) { 1695 memcpy(buf, frame, size); 1696 hr = queue_sample(avimux, avimuxin, sample); 1697 } 1698 IMediaSample_Release(sample); 1699 1700 return hr; 1701 } 1702 1703 static const BaseInputPinFuncTable AviMuxIn_BaseInputFuncTable = { 1704 { 1705 AviMuxIn_CheckMediaType, 1706 NULL, 1707 AviMuxIn_GetMediaTypeVersion, 1708 AviMuxIn_GetMediaType 1709 }, 1710 AviMuxIn_Receive 1711 }; 1712 1713 static inline AviMux* impl_from_in_IPin(IPin *iface) 1714 { 1715 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface); 1716 IBaseFilter *bf = bp->pinInfo.pFilter; 1717 1718 return impl_from_IBaseFilter(bf); 1719 } 1720 1721 static inline AviMuxIn* AviMuxIn_from_IPin(IPin *iface) 1722 { 1723 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface); 1724 BaseInputPin *bip = CONTAINING_RECORD(bp, BaseInputPin, pin); 1725 return CONTAINING_RECORD(bip, AviMuxIn, pin); 1726 } 1727 1728 static HRESULT WINAPI AviMuxIn_QueryInterface(IPin *iface, REFIID riid, void **ppv) 1729 { 1730 AviMux *This = impl_from_in_IPin(iface); 1731 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1732 1733 TRACE("(%p:%s)->(%s %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 1734 debugstr_guid(riid), ppv); 1735 1736 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) 1737 *ppv = &avimuxin->pin.pin.IPin_iface; 1738 else if(IsEqualIID(riid, &IID_IAMStreamControl)) 1739 *ppv = &avimuxin->IAMStreamControl_iface; 1740 else if(IsEqualIID(riid, &IID_IMemInputPin)) 1741 *ppv = &avimuxin->pin.IMemInputPin_iface; 1742 else if(IsEqualIID(riid, &IID_IPropertyBag)) 1743 *ppv = &avimuxin->IPropertyBag_iface; 1744 else if(IsEqualIID(riid, &IID_IQualityControl)) 1745 *ppv = &avimuxin->IQualityControl_iface; 1746 else { 1747 FIXME("no interface for %s\n", debugstr_guid(riid)); 1748 *ppv = NULL; 1749 return E_NOINTERFACE; 1750 } 1751 1752 IUnknown_AddRef((IUnknown*)*ppv); 1753 return S_OK; 1754 } 1755 1756 static ULONG WINAPI AviMuxIn_AddRef(IPin *iface) 1757 { 1758 AviMux *This = impl_from_in_IPin(iface); 1759 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 1760 } 1761 1762 static ULONG WINAPI AviMuxIn_Release(IPin *iface) 1763 { 1764 AviMux *This = impl_from_in_IPin(iface); 1765 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 1766 } 1767 1768 static HRESULT WINAPI AviMuxIn_Connect(IPin *iface, 1769 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) 1770 { 1771 AviMux *This = impl_from_in_IPin(iface); 1772 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1773 TRACE("(%p:%s)->(%p AM_MEDIA_TYPE(%p))\n", This, 1774 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pReceivePin, pmt); 1775 dump_AM_MEDIA_TYPE(pmt); 1776 return BaseInputPinImpl_Connect(iface, pReceivePin, pmt); 1777 } 1778 1779 static HRESULT WINAPI AviMuxIn_ReceiveConnection(IPin *iface, 1780 IPin *pConnector, const AM_MEDIA_TYPE *pmt) 1781 { 1782 AviMux *This = impl_from_in_IPin(iface); 1783 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1784 HRESULT hr; 1785 1786 TRACE("(%p:%s)->(%p AM_MEDIA_TYPE(%p))\n", This, 1787 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pConnector, pmt); 1788 dump_AM_MEDIA_TYPE(pmt); 1789 1790 if(!pmt) 1791 return E_POINTER; 1792 1793 hr = BaseInputPinImpl_ReceiveConnection(iface, pConnector, pmt); 1794 if(FAILED(hr)) 1795 return hr; 1796 1797 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) && 1798 IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) { 1799 ALLOCATOR_PROPERTIES req, act; 1800 VIDEOINFOHEADER *vih; 1801 int size; 1802 1803 vih = (VIDEOINFOHEADER*)pmt->pbFormat; 1804 avimuxin->strh.fcc = ckidSTREAMHEADER; 1805 avimuxin->strh.cb = sizeof(AVISTREAMHEADER) - FIELD_OFFSET(AVISTREAMHEADER, fccType); 1806 avimuxin->strh.fccType = streamtypeVIDEO; 1807 /* FIXME: fccHandler should be set differently */ 1808 avimuxin->strh.fccHandler = vih->bmiHeader.biCompression ? 1809 vih->bmiHeader.biCompression : FCC('D','I','B',' '); 1810 avimuxin->avg_time_per_frame = vih->AvgTimePerFrame; 1811 avimuxin->stop = -1; 1812 1813 req.cBuffers = 32; 1814 req.cbBuffer = vih->bmiHeader.biSizeImage; 1815 req.cbAlign = 1; 1816 req.cbPrefix = sizeof(void*); 1817 hr = IMemAllocator_SetProperties(avimuxin->samples_allocator, &req, &act); 1818 if(SUCCEEDED(hr)) 1819 hr = IMemAllocator_Commit(avimuxin->samples_allocator); 1820 if(FAILED(hr)) { 1821 BasePinImpl_Disconnect(iface); 1822 return hr; 1823 } 1824 1825 size = pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader); 1826 avimuxin->strf = CoTaskMemAlloc(sizeof(RIFFCHUNK) + ALIGN(FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]))); 1827 avimuxin->strf->fcc = ckidSTREAMFORMAT; 1828 avimuxin->strf->cb = FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]); 1829 if(size > avimuxin->strf->cb) 1830 size = avimuxin->strf->cb; 1831 memcpy(avimuxin->strf->data, &vih->bmiHeader, size); 1832 }else { 1833 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt->majortype), 1834 debugstr_guid(&pmt->formattype)); 1835 return E_NOTIMPL; 1836 } 1837 1838 return create_input_pin(This); 1839 } 1840 1841 static HRESULT WINAPI AviMuxIn_Disconnect(IPin *iface) 1842 { 1843 AviMux *This = impl_from_in_IPin(iface); 1844 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1845 IMediaSample **prev, *cur; 1846 HRESULT hr; 1847 1848 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName)); 1849 1850 hr = BasePinImpl_Disconnect(iface); 1851 if(FAILED(hr)) 1852 return hr; 1853 1854 IMemAllocator_Decommit(avimuxin->samples_allocator); 1855 while(avimuxin->samples_head) { 1856 cur = avimuxin->samples_head; 1857 hr = IMediaSample_GetPointer(cur, (BYTE**)&prev); 1858 if(FAILED(hr)) 1859 break; 1860 prev--; 1861 1862 cur = avimuxin->samples_head; 1863 avimuxin->samples_head = *prev; 1864 IMediaSample_Release(cur); 1865 1866 if(cur == avimuxin->samples_head) 1867 avimuxin->samples_head = NULL; 1868 } 1869 CoTaskMemFree(avimuxin->strf); 1870 avimuxin->strf = NULL; 1871 return hr; 1872 } 1873 1874 static HRESULT WINAPI AviMuxIn_ConnectedTo(IPin *iface, IPin **pPin) 1875 { 1876 AviMux *This = impl_from_in_IPin(iface); 1877 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1878 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pPin); 1879 return BasePinImpl_ConnectedTo(iface, pPin); 1880 } 1881 1882 static HRESULT WINAPI AviMuxIn_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt) 1883 { 1884 AviMux *This = impl_from_in_IPin(iface); 1885 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1886 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pmt); 1887 return BasePinImpl_ConnectionMediaType(iface, pmt); 1888 } 1889 1890 static HRESULT WINAPI AviMuxIn_QueryPinInfo(IPin *iface, PIN_INFO *pInfo) 1891 { 1892 AviMux *This = impl_from_in_IPin(iface); 1893 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1894 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pInfo); 1895 return BasePinImpl_QueryPinInfo(iface, pInfo); 1896 } 1897 1898 static HRESULT WINAPI AviMuxIn_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir) 1899 { 1900 AviMux *This = impl_from_in_IPin(iface); 1901 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1902 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pPinDir); 1903 return BasePinImpl_QueryDirection(iface, pPinDir); 1904 } 1905 1906 static HRESULT WINAPI AviMuxIn_QueryId(IPin *iface, LPWSTR *Id) 1907 { 1908 AviMux *This = impl_from_in_IPin(iface); 1909 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1910 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), Id); 1911 return BasePinImpl_QueryId(iface, Id); 1912 } 1913 1914 static HRESULT WINAPI AviMuxIn_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) 1915 { 1916 AviMux *This = impl_from_in_IPin(iface); 1917 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1918 TRACE("(%p:%s)->(AM_MEDIA_TYPE(%p))\n", This, 1919 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pmt); 1920 dump_AM_MEDIA_TYPE(pmt); 1921 return BasePinImpl_QueryAccept(iface, pmt); 1922 } 1923 1924 static HRESULT WINAPI AviMuxIn_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) 1925 { 1926 AviMux *This = impl_from_in_IPin(iface); 1927 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1928 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), ppEnum); 1929 return BasePinImpl_EnumMediaTypes(iface, ppEnum); 1930 } 1931 1932 static HRESULT WINAPI AviMuxIn_QueryInternalConnections( 1933 IPin *iface, IPin **apPin, ULONG *nPin) 1934 { 1935 AviMux *This = impl_from_in_IPin(iface); 1936 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1937 TRACE("(%p:%s)->(%p %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), apPin, nPin); 1938 return BasePinImpl_QueryInternalConnections(iface, apPin, nPin); 1939 } 1940 1941 static HRESULT WINAPI AviMuxIn_EndOfStream(IPin *iface) 1942 { 1943 AviMux *This = impl_from_in_IPin(iface); 1944 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1945 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName)); 1946 return BaseInputPinImpl_EndOfStream(iface); 1947 } 1948 1949 static HRESULT WINAPI AviMuxIn_BeginFlush(IPin *iface) 1950 { 1951 AviMux *This = impl_from_in_IPin(iface); 1952 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1953 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName)); 1954 return BaseInputPinImpl_BeginFlush(iface); 1955 } 1956 1957 static HRESULT WINAPI AviMuxIn_EndFlush(IPin *iface) 1958 { 1959 AviMux *This = impl_from_in_IPin(iface); 1960 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1961 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName)); 1962 return BaseInputPinImpl_EndFlush(iface); 1963 } 1964 1965 static HRESULT WINAPI AviMuxIn_NewSegment(IPin *iface, REFERENCE_TIME tStart, 1966 REFERENCE_TIME tStop, double dRate) 1967 { 1968 AviMux *This = impl_from_in_IPin(iface); 1969 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface); 1970 TRACE("(%p:%s)->(%s %s %f)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 1971 wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); 1972 return BasePinImpl_NewSegment(iface, tStart, tStop, dRate); 1973 } 1974 1975 static const IPinVtbl AviMuxIn_PinVtbl = { 1976 AviMuxIn_QueryInterface, 1977 AviMuxIn_AddRef, 1978 AviMuxIn_Release, 1979 AviMuxIn_Connect, 1980 AviMuxIn_ReceiveConnection, 1981 AviMuxIn_Disconnect, 1982 AviMuxIn_ConnectedTo, 1983 AviMuxIn_ConnectionMediaType, 1984 AviMuxIn_QueryPinInfo, 1985 AviMuxIn_QueryDirection, 1986 AviMuxIn_QueryId, 1987 AviMuxIn_QueryAccept, 1988 AviMuxIn_EnumMediaTypes, 1989 AviMuxIn_QueryInternalConnections, 1990 AviMuxIn_EndOfStream, 1991 AviMuxIn_BeginFlush, 1992 AviMuxIn_EndFlush, 1993 AviMuxIn_NewSegment 1994 }; 1995 1996 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface) 1997 { 1998 return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface); 1999 } 2000 2001 static HRESULT WINAPI AviMuxIn_AMStreamControl_QueryInterface( 2002 IAMStreamControl *iface, REFIID riid, void **ppv) 2003 { 2004 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface); 2005 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv); 2006 } 2007 2008 static ULONG WINAPI AviMuxIn_AMStreamControl_AddRef(IAMStreamControl *iface) 2009 { 2010 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface); 2011 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2012 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 2013 } 2014 2015 static ULONG WINAPI AviMuxIn_AMStreamControl_Release(IAMStreamControl *iface) 2016 { 2017 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface); 2018 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2019 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 2020 } 2021 2022 static HRESULT WINAPI AviMuxIn_AMStreamControl_StartAt(IAMStreamControl *iface, 2023 const REFERENCE_TIME *ptStart, DWORD dwCookie) 2024 { 2025 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface); 2026 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2027 FIXME("(%p:%s)->(%p %x)\n", This, 2028 debugstr_w(avimuxin->pin.pin.pinInfo.achName), ptStart, dwCookie); 2029 return E_NOTIMPL; 2030 } 2031 2032 static HRESULT WINAPI AviMuxIn_AMStreamControl_StopAt(IAMStreamControl *iface, 2033 const REFERENCE_TIME *ptStop, BOOL bSendExtra, DWORD dwCookie) 2034 { 2035 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface); 2036 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2037 FIXME("(%p:%s)->(%p %x %x)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 2038 ptStop, bSendExtra, dwCookie); 2039 return E_NOTIMPL; 2040 } 2041 2042 static HRESULT WINAPI AviMuxIn_AMStreamControl_GetInfo( 2043 IAMStreamControl *iface, AM_STREAM_INFO *pInfo) 2044 { 2045 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface); 2046 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2047 FIXME("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pInfo); 2048 return E_NOTIMPL; 2049 } 2050 2051 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl = { 2052 AviMuxIn_AMStreamControl_QueryInterface, 2053 AviMuxIn_AMStreamControl_AddRef, 2054 AviMuxIn_AMStreamControl_Release, 2055 AviMuxIn_AMStreamControl_StartAt, 2056 AviMuxIn_AMStreamControl_StopAt, 2057 AviMuxIn_AMStreamControl_GetInfo 2058 }; 2059 2060 static inline AviMuxIn* AviMuxIn_from_IMemInputPin(IMemInputPin *iface) 2061 { 2062 BaseInputPin *bip = CONTAINING_RECORD(iface, BaseInputPin, IMemInputPin_iface); 2063 return CONTAINING_RECORD(bip, AviMuxIn, pin); 2064 } 2065 2066 static HRESULT WINAPI AviMuxIn_MemInputPin_QueryInterface( 2067 IMemInputPin *iface, REFIID riid, void **ppv) 2068 { 2069 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2070 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv); 2071 } 2072 2073 static ULONG WINAPI AviMuxIn_MemInputPin_AddRef(IMemInputPin *iface) 2074 { 2075 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2076 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2077 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 2078 } 2079 2080 static ULONG WINAPI AviMuxIn_MemInputPin_Release(IMemInputPin *iface) 2081 { 2082 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2083 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2084 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 2085 } 2086 2087 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocator( 2088 IMemInputPin *iface, IMemAllocator **ppAllocator) 2089 { 2090 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2091 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2092 2093 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), ppAllocator); 2094 2095 if(!ppAllocator) 2096 return E_POINTER; 2097 2098 IMemAllocator_AddRef(avimuxin->pin.pAllocator); 2099 *ppAllocator = avimuxin->pin.pAllocator; 2100 return S_OK; 2101 } 2102 2103 static HRESULT WINAPI AviMuxIn_MemInputPin_NotifyAllocator( 2104 IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly) 2105 { 2106 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2107 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2108 ALLOCATOR_PROPERTIES props; 2109 HRESULT hr; 2110 2111 TRACE("(%p:%s)->(%p %x)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 2112 pAllocator, bReadOnly); 2113 2114 if(!pAllocator) 2115 return E_POINTER; 2116 2117 memset(&props, 0, sizeof(props)); 2118 hr = IMemAllocator_GetProperties(pAllocator, &props); 2119 if(FAILED(hr)) 2120 return hr; 2121 2122 props.cbAlign = 1; 2123 props.cbPrefix = 8; 2124 return IMemAllocator_SetProperties(avimuxin->pin.pAllocator, &props, &props); 2125 } 2126 2127 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocatorRequirements( 2128 IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps) 2129 { 2130 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2131 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2132 2133 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pProps); 2134 2135 if(!pProps) 2136 return E_POINTER; 2137 2138 pProps->cbAlign = 1; 2139 pProps->cbPrefix = 8; 2140 return S_OK; 2141 } 2142 2143 static HRESULT WINAPI AviMuxIn_MemInputPin_Receive( 2144 IMemInputPin *iface, IMediaSample *pSample) 2145 { 2146 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2147 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2148 2149 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pSample); 2150 2151 return avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSample); 2152 } 2153 2154 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin *iface, 2155 IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed) 2156 { 2157 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2158 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2159 HRESULT hr = S_OK; 2160 2161 TRACE("(%p:%s)->(%p %d %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 2162 pSamples, nSamples, nSamplesProcessed); 2163 2164 for(*nSamplesProcessed=0; *nSamplesProcessed<nSamples; (*nSamplesProcessed)++) 2165 { 2166 hr = avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSamples[*nSamplesProcessed]); 2167 if(hr != S_OK) 2168 break; 2169 } 2170 2171 return hr; 2172 } 2173 2174 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin *iface) 2175 { 2176 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface); 2177 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2178 HRESULT hr; 2179 2180 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName)); 2181 2182 if(!This->out->pin.pMemInputPin) 2183 return S_FALSE; 2184 2185 hr = IMemInputPin_ReceiveCanBlock(This->out->pin.pMemInputPin); 2186 return hr != S_FALSE ? S_OK : S_FALSE; 2187 } 2188 2189 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl = { 2190 AviMuxIn_MemInputPin_QueryInterface, 2191 AviMuxIn_MemInputPin_AddRef, 2192 AviMuxIn_MemInputPin_Release, 2193 AviMuxIn_MemInputPin_GetAllocator, 2194 AviMuxIn_MemInputPin_NotifyAllocator, 2195 AviMuxIn_MemInputPin_GetAllocatorRequirements, 2196 AviMuxIn_MemInputPin_Receive, 2197 AviMuxIn_MemInputPin_ReceiveMultiple, 2198 AviMuxIn_MemInputPin_ReceiveCanBlock 2199 }; 2200 2201 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface) 2202 { 2203 return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface); 2204 } 2205 2206 static HRESULT WINAPI AviMuxIn_PropertyBag_QueryInterface( 2207 IPropertyBag *iface, REFIID riid, void **ppv) 2208 { 2209 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface); 2210 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv); 2211 } 2212 2213 static ULONG WINAPI AviMuxIn_PropertyBag_AddRef(IPropertyBag *iface) 2214 { 2215 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface); 2216 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2217 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 2218 } 2219 2220 static ULONG WINAPI AviMuxIn_PropertyBag_Release(IPropertyBag *iface) 2221 { 2222 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface); 2223 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2224 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 2225 } 2226 2227 static HRESULT WINAPI AviMuxIn_PropertyBag_Read(IPropertyBag *iface, 2228 LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) 2229 { 2230 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface); 2231 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2232 FIXME("(%p:%s)->(%s %p %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 2233 debugstr_w(pszPropName), pVar, pErrorLog); 2234 return E_NOTIMPL; 2235 } 2236 2237 static HRESULT WINAPI AviMuxIn_PropertyBag_Write(IPropertyBag *iface, 2238 LPCOLESTR pszPropName, VARIANT *pVar) 2239 { 2240 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface); 2241 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2242 FIXME("(%p:%s)->(%s %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), 2243 debugstr_w(pszPropName), pVar); 2244 return E_NOTIMPL; 2245 } 2246 2247 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl = { 2248 AviMuxIn_PropertyBag_QueryInterface, 2249 AviMuxIn_PropertyBag_AddRef, 2250 AviMuxIn_PropertyBag_Release, 2251 AviMuxIn_PropertyBag_Read, 2252 AviMuxIn_PropertyBag_Write 2253 }; 2254 2255 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface) 2256 { 2257 return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface); 2258 } 2259 2260 static HRESULT WINAPI AviMuxIn_QualityControl_QueryInterface( 2261 IQualityControl *iface, REFIID riid, void **ppv) 2262 { 2263 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface); 2264 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv); 2265 } 2266 2267 static ULONG WINAPI AviMuxIn_QualityControl_AddRef(IQualityControl *iface) 2268 { 2269 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface); 2270 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2271 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); 2272 } 2273 2274 static ULONG WINAPI AviMuxIn_QualityControl_Release(IQualityControl *iface) 2275 { 2276 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface); 2277 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2278 return IBaseFilter_Release(&This->filter.IBaseFilter_iface); 2279 } 2280 2281 static HRESULT WINAPI AviMuxIn_QualityControl_Notify(IQualityControl *iface, 2282 IBaseFilter *pSelf, Quality q) 2283 { 2284 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface); 2285 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2286 FIXME("(%p:%s)->(%p { 0x%x %u %s %s })\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pSelf, 2287 q.Type, q.Proportion, 2288 wine_dbgstr_longlong(q.Late), 2289 wine_dbgstr_longlong(q.TimeStamp)); 2290 return E_NOTIMPL; 2291 } 2292 2293 static HRESULT WINAPI AviMuxIn_QualityControl_SetSink( 2294 IQualityControl *iface, IQualityControl *piqc) 2295 { 2296 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface); 2297 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface); 2298 FIXME("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), piqc); 2299 return E_NOTIMPL; 2300 } 2301 2302 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl = { 2303 AviMuxIn_QualityControl_QueryInterface, 2304 AviMuxIn_QualityControl_AddRef, 2305 AviMuxIn_QualityControl_Release, 2306 AviMuxIn_QualityControl_Notify, 2307 AviMuxIn_QualityControl_SetSink 2308 }; 2309 2310 static HRESULT create_input_pin(AviMux *avimux) 2311 { 2312 static const WCHAR name[] = {'I','n','p','u','t',' ','0','0',0}; 2313 PIN_INFO info; 2314 HRESULT hr; 2315 2316 if(avimux->input_pin_no >= MAX_PIN_NO-1) 2317 return E_FAIL; 2318 2319 info.dir = PINDIR_INPUT; 2320 info.pFilter = &avimux->filter.IBaseFilter_iface; 2321 memcpy(info.achName, name, sizeof(name)); 2322 info.achName[7] = '0' + (avimux->input_pin_no+1) % 10; 2323 info.achName[6] = '0' + (avimux->input_pin_no+1) / 10; 2324 2325 hr = BaseInputPin_Construct(&AviMuxIn_PinVtbl, sizeof(AviMuxIn), &info, 2326 &AviMuxIn_BaseInputFuncTable, &avimux->filter.csFilter, NULL, (IPin**)&avimux->in[avimux->input_pin_no]); 2327 if(FAILED(hr)) 2328 return hr; 2329 avimux->in[avimux->input_pin_no]->pin.IMemInputPin_iface.lpVtbl = &AviMuxIn_MemInputPinVtbl; 2330 avimux->in[avimux->input_pin_no]->IAMStreamControl_iface.lpVtbl = &AviMuxIn_AMStreamControlVtbl; 2331 avimux->in[avimux->input_pin_no]->IPropertyBag_iface.lpVtbl = &AviMuxIn_PropertyBagVtbl; 2332 avimux->in[avimux->input_pin_no]->IQualityControl_iface.lpVtbl = &AviMuxIn_QualityControlVtbl; 2333 2334 avimux->in[avimux->input_pin_no]->samples_head = NULL; 2335 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, 2336 &IID_IMemAllocator, (void**)&avimux->in[avimux->input_pin_no]->samples_allocator); 2337 if(FAILED(hr)) { 2338 BaseInputPinImpl_Release(&avimux->in[avimux->input_pin_no]->pin.pin.IPin_iface); 2339 return hr; 2340 } 2341 2342 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, 2343 &IID_IMemAllocator, (void**)&avimux->in[avimux->input_pin_no]->pin.pAllocator); 2344 if(FAILED(hr)) { 2345 IMemAllocator_Release(avimux->in[avimux->input_pin_no]->samples_allocator); 2346 BaseInputPinImpl_Release(&avimux->in[avimux->input_pin_no]->pin.pin.IPin_iface); 2347 return hr; 2348 } 2349 2350 avimux->in[avimux->input_pin_no]->stream_time = 0; 2351 memset(&avimux->in[avimux->input_pin_no]->strh, 0, sizeof(avimux->in[avimux->input_pin_no]->strh)); 2352 avimux->in[avimux->input_pin_no]->strf = NULL; 2353 memset(&avimux->in[avimux->input_pin_no]->indx_data, 0, sizeof(avimux->in[avimux->input_pin_no]->indx_data)); 2354 memset(&avimux->in[avimux->input_pin_no]->ix_data, 0, sizeof(avimux->in[avimux->input_pin_no]->ix_data)); 2355 avimux->in[avimux->input_pin_no]->indx = (AVISUPERINDEX*)&avimux->in[avimux->input_pin_no]->indx_data; 2356 avimux->in[avimux->input_pin_no]->ix = (AVISTDINDEX*)avimux->in[avimux->input_pin_no]->ix_data; 2357 2358 avimux->input_pin_no++; 2359 return S_OK; 2360 } 2361 2362 IUnknown* WINAPI QCAP_createAVIMux(IUnknown *pUnkOuter, HRESULT *phr) 2363 { 2364 static const WCHAR output_name[] = {'A','V','I',' ','O','u','t',0}; 2365 2366 AviMux *avimux; 2367 PIN_INFO info; 2368 HRESULT hr; 2369 2370 TRACE("(%p)\n", pUnkOuter); 2371 2372 if(pUnkOuter) { 2373 *phr = CLASS_E_NOAGGREGATION; 2374 return NULL; 2375 } 2376 2377 avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux)); 2378 if(!avimux) { 2379 *phr = E_OUTOFMEMORY; 2380 return NULL; 2381 } 2382 2383 BaseFilter_Init(&avimux->filter, &AviMuxVtbl, &CLSID_AviDest, 2384 (DWORD_PTR)(__FILE__ ": AviMux.csFilter"), &filter_func_table); 2385 avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl; 2386 avimux->IConfigInterleaving_iface.lpVtbl = &ConfigInterleavingVtbl; 2387 avimux->IMediaSeeking_iface.lpVtbl = &MediaSeekingVtbl; 2388 avimux->IPersistMediaPropertyBag_iface.lpVtbl = &PersistMediaPropertyBagVtbl; 2389 avimux->ISpecifyPropertyPages_iface.lpVtbl = &SpecifyPropertyPagesVtbl; 2390 2391 info.dir = PINDIR_OUTPUT; 2392 info.pFilter = &avimux->filter.IBaseFilter_iface; 2393 lstrcpyW(info.achName, output_name); 2394 hr = BaseOutputPin_Construct(&AviMuxOut_PinVtbl, sizeof(AviMuxOut), &info, 2395 &AviMuxOut_BaseOutputFuncTable, &avimux->filter.csFilter, (IPin**)&avimux->out); 2396 if(FAILED(hr)) { 2397 BaseFilterImpl_Release(&avimux->filter.IBaseFilter_iface); 2398 HeapFree(GetProcessHeap(), 0, avimux); 2399 *phr = hr; 2400 return NULL; 2401 } 2402 avimux->out->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl; 2403 avimux->out->cur_stream = 0; 2404 avimux->out->cur_time = 0; 2405 avimux->out->stream = NULL; 2406 2407 hr = create_input_pin(avimux); 2408 if(FAILED(hr)) { 2409 BaseOutputPinImpl_Release(&avimux->out->pin.pin.IPin_iface); 2410 BaseFilterImpl_Release(&avimux->filter.IBaseFilter_iface); 2411 HeapFree(GetProcessHeap(), 0, avimux); 2412 *phr = hr; 2413 return NULL; 2414 } 2415 2416 avimux->interleave = 10000000; 2417 2418 ObjectRefCount(TRUE); 2419 *phr = S_OK; 2420 return (IUnknown*)&avimux->filter.IBaseFilter_iface; 2421 } 2422