wined3d: Don't bother with glGetError() if we have ARB_DEBUG_OUTPUT.
[wine.git] / dlls / qcap / avimux.c
blob533db133055c7bcd380790dd3374a48143d44fc9
1 /*
2 * Copyright (C) 2013 Piotr Caban for CodeWeavers
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.
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.
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
19 #include <stdarg.h>
20 #include <stdio.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wtypes.h"
27 #include "dshow.h"
28 #include "vfw.h"
29 #include "aviriff.h"
31 #include "qcap_main.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
37 #define MAX_PIN_NO 128
38 #define AVISUPERINDEX_ENTRIES 2000
39 #define AVISTDINDEX_ENTRIES 4000
40 #define ALIGN(x) ((x+1)/2*2)
42 typedef struct {
43 BaseOutputPin pin;
44 IQualityControl IQualityControl_iface;
46 int cur_stream;
47 LONGLONG cur_time;
49 int buf_pos;
50 BYTE buf[65536];
52 int movi_off;
53 int out_pos;
54 int size;
55 IStream *stream;
56 } AviMuxOut;
58 typedef struct {
59 BaseInputPin pin;
60 IAMStreamControl IAMStreamControl_iface;
61 IPropertyBag IPropertyBag_iface;
62 IQualityControl IQualityControl_iface;
64 REFERENCE_TIME avg_time_per_frame;
65 REFERENCE_TIME stop;
66 int stream_id;
67 LONGLONG stream_time;
69 /* strl chunk */
70 AVISTREAMHEADER strh;
71 struct {
72 FOURCC fcc;
73 DWORD cb;
74 BYTE data[1];
75 } *strf;
76 AVISUPERINDEX *indx;
77 BYTE indx_data[FIELD_OFFSET(AVISUPERINDEX, aIndex[AVISUPERINDEX_ENTRIES])];
79 /* movi chunk */
80 int ix_off;
81 AVISTDINDEX *ix;
82 BYTE ix_data[FIELD_OFFSET(AVISTDINDEX, aIndex[AVISTDINDEX_ENTRIES])];
84 IMediaSample *samples_head;
85 IMemAllocator *samples_allocator;
86 } AviMuxIn;
88 typedef struct {
89 BaseFilter filter;
90 IConfigAviMux IConfigAviMux_iface;
91 IConfigInterleaving IConfigInterleaving_iface;
92 IMediaSeeking IMediaSeeking_iface;
93 IPersistMediaPropertyBag IPersistMediaPropertyBag_iface;
94 ISpecifyPropertyPages ISpecifyPropertyPages_iface;
96 InterleavingMode mode;
97 REFERENCE_TIME interleave;
98 REFERENCE_TIME preroll;
100 AviMuxOut *out;
101 int input_pin_no;
102 AviMuxIn *in[MAX_PIN_NO-1];
104 REFERENCE_TIME start, stop;
105 AVIMAINHEADER avih;
107 int idx1_entries;
108 int idx1_size;
109 AVIINDEXENTRY *idx1;
110 } AviMux;
112 static HRESULT create_input_pin(AviMux*);
114 static inline AviMux* impl_from_BaseFilter(BaseFilter *filter)
116 return CONTAINING_RECORD(filter, AviMux, filter);
119 static IPin* WINAPI AviMux_GetPin(BaseFilter *iface, int pos)
121 AviMux *This = impl_from_BaseFilter(iface);
123 TRACE("(%p)->(%d)\n", This, pos);
125 if(pos == 0) {
126 IPin_AddRef(&This->out->pin.pin.IPin_iface);
127 return &This->out->pin.pin.IPin_iface;
128 }else if(pos>0 && pos<=This->input_pin_no) {
129 IPin_AddRef(&This->in[pos-1]->pin.pin.IPin_iface);
130 return &This->in[pos-1]->pin.pin.IPin_iface;
133 return NULL;
136 static LONG WINAPI AviMux_GetPinCount(BaseFilter *iface)
138 AviMux *This = impl_from_BaseFilter(iface);
139 TRACE("(%p)\n", This);
140 return This->input_pin_no+1;
143 static const BaseFilterFuncTable filter_func_table = {
144 AviMux_GetPin,
145 AviMux_GetPinCount
148 static inline AviMux* impl_from_IBaseFilter(IBaseFilter *iface)
150 BaseFilter *filter = CONTAINING_RECORD(iface, BaseFilter, IBaseFilter_iface);
151 return impl_from_BaseFilter(filter);
154 static HRESULT WINAPI AviMux_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
156 AviMux *This = impl_from_IBaseFilter(iface);
158 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
160 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPersist) ||
161 IsEqualIID(riid, &IID_IMediaFilter) || IsEqualIID(riid, &IID_IBaseFilter))
162 *ppv = &This->filter.IBaseFilter_iface;
163 else if(IsEqualIID(riid, &IID_IConfigAviMux))
164 *ppv = &This->IConfigAviMux_iface;
165 else if(IsEqualIID(riid, &IID_IConfigInterleaving))
166 *ppv = &This->IConfigInterleaving_iface;
167 else if(IsEqualIID(riid, &IID_IMediaSeeking))
168 *ppv = &This->IMediaSeeking_iface;
169 else if(IsEqualIID(riid, &IID_IPersistMediaPropertyBag))
170 *ppv = &This->IPersistMediaPropertyBag_iface;
171 else if(IsEqualIID(riid, &IID_ISpecifyPropertyPages))
172 *ppv = &This->ISpecifyPropertyPages_iface;
173 else {
174 FIXME("no interface for %s\n", debugstr_guid(riid));
175 *ppv = NULL;
176 return E_NOINTERFACE;
179 IUnknown_AddRef((IUnknown*)*ppv);
180 return S_OK;
183 static ULONG WINAPI AviMux_Release(IBaseFilter *iface)
185 AviMux *This = impl_from_IBaseFilter(iface);
186 ULONG ref = BaseFilterImpl_Release(iface);
188 TRACE("(%p) new refcount: %u\n", This, ref);
190 if(!ref) {
191 int i;
193 BaseOutputPinImpl_Release(&This->out->pin.pin.IPin_iface);
195 for(i=0; i<This->input_pin_no; i++) {
196 IPin_Disconnect(&This->in[i]->pin.pin.IPin_iface);
197 IMemAllocator_Release(This->in[i]->samples_allocator);
198 This->in[i]->samples_allocator = NULL;
199 BaseInputPinImpl_Release(&This->in[i]->pin.pin.IPin_iface);
202 HeapFree(GetProcessHeap(), 0, This->idx1);
203 HeapFree(GetProcessHeap(), 0, This);
204 ObjectRefCount(FALSE);
206 return ref;
209 static HRESULT out_flush(AviMux *This)
211 ULONG written;
212 HRESULT hr;
214 if(!This->out->buf_pos)
215 return S_OK;
217 hr = IStream_Write(This->out->stream, This->out->buf, This->out->buf_pos, &written);
218 if(FAILED(hr))
219 return hr;
220 if(written != This->out->buf_pos)
221 return E_FAIL;
223 This->out->buf_pos = 0;
224 return S_OK;
227 static HRESULT out_seek(AviMux *This, int pos)
229 LARGE_INTEGER li;
230 HRESULT hr;
232 hr = out_flush(This);
233 if(FAILED(hr))
234 return hr;
236 li.QuadPart = pos;
237 hr = IStream_Seek(This->out->stream, li, STREAM_SEEK_SET, NULL);
238 if(FAILED(hr))
239 return hr;
241 This->out->out_pos = pos;
242 if(This->out->out_pos > This->out->size)
243 This->out->size = This->out->out_pos;
244 return hr;
247 static HRESULT out_write(AviMux *This, const void *data, int size)
249 int chunk_size;
250 HRESULT hr;
252 while(1) {
253 if(size > sizeof(This->out->buf)-This->out->buf_pos)
254 chunk_size = sizeof(This->out->buf)-This->out->buf_pos;
255 else
256 chunk_size = size;
258 memcpy(This->out->buf + This->out->buf_pos, data, chunk_size);
259 size -= chunk_size;
260 data = (const BYTE*)data + chunk_size;
261 This->out->buf_pos += chunk_size;
262 This->out->out_pos += chunk_size;
263 if(This->out->out_pos > This->out->size)
264 This->out->size = This->out->out_pos;
266 if(!size)
267 break;
268 hr = out_flush(This);
269 if(FAILED(hr))
270 return hr;
273 return S_OK;
276 static inline HRESULT idx1_add_entry(AviMux *avimux, DWORD ckid, DWORD flags, DWORD off, DWORD len)
278 if(avimux->idx1_entries == avimux->idx1_size) {
279 AVIINDEXENTRY *new_idx = HeapReAlloc(GetProcessHeap(), 0, avimux->idx1,
280 sizeof(*avimux->idx1)*2*avimux->idx1_size);
281 if(!new_idx)
282 return E_OUTOFMEMORY;
284 avimux->idx1_size *= 2;
285 avimux->idx1 = new_idx;
288 avimux->idx1[avimux->idx1_entries].ckid = ckid;
289 avimux->idx1[avimux->idx1_entries].dwFlags = flags;
290 avimux->idx1[avimux->idx1_entries].dwChunkOffset = off;
291 avimux->idx1[avimux->idx1_entries].dwChunkLength = len;
292 avimux->idx1_entries++;
293 return S_OK;
296 static HRESULT flush_queue(AviMux *avimux, AviMuxIn *avimuxin, BOOL closing)
298 IMediaSample *sample, **prev, **head_prev;
299 BYTE *data;
300 RIFFCHUNK rf;
301 DWORD size;
302 DWORD flags;
303 HRESULT hr;
305 if(avimux->out->cur_stream != avimuxin->stream_id)
306 return S_OK;
308 while(avimuxin->samples_head) {
309 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
310 if(FAILED(hr))
311 return hr;
312 head_prev--;
314 hr = IMediaSample_GetPointer(*head_prev, (BYTE**)&prev);
315 if(FAILED(hr))
316 return hr;
317 prev--;
319 sample = *head_prev;
320 size = IMediaSample_GetActualDataLength(sample);
321 hr = IMediaSample_GetPointer(sample, &data);
322 if(FAILED(hr))
323 return hr;
324 flags = IMediaSample_IsDiscontinuity(sample)==S_OK ? AM_SAMPLE_TIMEDISCONTINUITY : 0;
325 if(IMediaSample_IsSyncPoint(sample) == S_OK)
326 flags |= AM_SAMPLE_SPLICEPOINT;
328 if(avimuxin->stream_time + (closing ? 0 : avimuxin->strh.dwScale) > avimux->out->cur_time &&
329 !(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
330 if(closing)
331 break;
333 avimux->out->cur_stream++;
334 if(avimux->out->cur_stream >= avimux->input_pin_no-1) {
335 avimux->out->cur_time += avimux->interleave;
336 avimux->out->cur_stream = 0;
338 avimuxin = avimux->in[avimux->out->cur_stream];
339 continue;
342 if(avimuxin->ix->nEntriesInUse == AVISTDINDEX_ENTRIES) {
343 /* TODO: use output pins Deliver/Receive method */
344 hr = out_seek(avimux, avimuxin->ix_off);
345 if(FAILED(hr))
346 return hr;
347 hr = out_write(avimux, avimuxin->ix, sizeof(avimuxin->ix_data));
348 if(FAILED(hr))
349 return hr;
351 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].qwOffset = avimuxin->ix_off;
352 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwSize = sizeof(avimuxin->ix_data);
353 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwDuration = AVISTDINDEX_ENTRIES;
354 avimuxin->indx->nEntriesInUse++;
356 memset(avimuxin->ix->aIndex, 0, sizeof(avimuxin->ix->aIndex)*avimuxin->ix->nEntriesInUse);
357 avimuxin->ix->nEntriesInUse = 0;
358 avimuxin->ix->qwBaseOffset = 0;
360 avimuxin->ix_off = avimux->out->size;
361 avimux->out->size += sizeof(avimuxin->ix_data);
364 if(*head_prev == avimuxin->samples_head)
365 avimuxin->samples_head = NULL;
366 else
367 *head_prev = *prev;
369 avimuxin->stream_time += avimuxin->strh.dwScale;
370 avimuxin->strh.dwLength++;
371 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
372 if(!avimuxin->ix->qwBaseOffset)
373 avimuxin->ix->qwBaseOffset = avimux->out->size;
374 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwOffset = avimux->out->size
375 + sizeof(RIFFCHUNK) - avimuxin->ix->qwBaseOffset;
377 hr = out_seek(avimux, avimux->out->size);
378 if(FAILED(hr)) {
379 IMediaSample_Release(sample);
380 return hr;
383 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwSize = size |
384 (flags & AM_SAMPLE_SPLICEPOINT ? 0 : AVISTDINDEX_DELTAFRAME);
385 avimuxin->ix->nEntriesInUse++;
387 rf.fcc = FCC('0'+avimuxin->stream_id/10, '0'+avimuxin->stream_id%10,
388 'd', flags & AM_SAMPLE_SPLICEPOINT ? 'b' : 'c');
389 rf.cb = size;
390 hr = idx1_add_entry(avimux, rf.fcc, flags & AM_SAMPLE_SPLICEPOINT ? AVIIF_KEYFRAME : 0,
391 flags & AM_SAMPLE_TIMEDISCONTINUITY ?
392 avimux->idx1[avimux->idx1_entries-1].dwChunkOffset : avimux->out->size, size);
393 if(FAILED(hr)) {
394 IMediaSample_Release(sample);
395 return hr;
398 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
399 hr = out_write(avimux, &rf, sizeof(rf));
400 if(FAILED(hr)) {
401 IMediaSample_Release(sample);
402 return hr;
404 hr = out_write(avimux, data, size);
405 if(FAILED(hr)) {
406 IMediaSample_Release(sample);
407 return hr;
409 flags = 0;
410 hr = out_write(avimux, &flags, ALIGN(rf.cb)-rf.cb);
411 if(FAILED(hr)) {
412 IMediaSample_Release(sample);
413 return hr;
416 IMediaSample_Release(sample);
418 return S_OK;
421 static HRESULT queue_sample(AviMux *avimux, AviMuxIn *avimuxin, IMediaSample *sample)
423 IMediaSample **prev, **head_prev;
424 HRESULT hr;
426 hr = IMediaSample_GetPointer(sample, (BYTE**)&prev);
427 if(FAILED(hr))
428 return hr;
429 prev--;
431 if(avimuxin->samples_head) {
432 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
433 if(FAILED(hr))
434 return hr;
435 head_prev--;
437 *prev = *head_prev;
438 *head_prev = sample;
439 }else {
440 *prev = sample;
442 avimuxin->samples_head = sample;
443 IMediaSample_AddRef(sample);
445 return flush_queue(avimux, avimuxin, FALSE);
448 static HRESULT WINAPI AviMux_Stop(IBaseFilter *iface)
450 AviMux *This = impl_from_IBaseFilter(iface);
451 HRESULT hr;
452 int i;
454 TRACE("(%p)\n", This);
456 if(This->filter.state == State_Stopped)
457 return S_OK;
459 if(This->out->stream) {
460 AVIEXTHEADER dmlh;
461 RIFFCHUNK rc;
462 RIFFLIST rl;
463 int idx1_off, empty_stream;
465 empty_stream = This->out->cur_stream;
466 for(i=empty_stream+1; ; i++) {
467 if(i >= This->input_pin_no-1)
468 i = 0;
469 if(i == empty_stream)
470 break;
472 This->out->cur_stream = i;
473 hr = flush_queue(This, This->in[This->out->cur_stream], TRUE);
474 if(FAILED(hr))
475 return hr;
478 idx1_off = This->out->size;
479 rc.fcc = ckidAVIOLDINDEX;
480 rc.cb = This->idx1_entries * sizeof(*This->idx1);
481 hr = out_write(This, &rc, sizeof(rc));
482 if(FAILED(hr))
483 return hr;
484 hr = out_write(This, This->idx1, This->idx1_entries * sizeof(*This->idx1));
485 if(FAILED(hr))
486 return hr;
487 /* native writes 8 '\0' characters after the end of RIFF data */
488 i = 0;
489 hr = out_write(This, &i, sizeof(i));
490 if(FAILED(hr))
491 return hr;
492 hr = out_write(This, &i, sizeof(i));
493 if(FAILED(hr))
494 return hr;
496 for(i=0; i<This->input_pin_no; i++) {
497 if(!This->in[i]->pin.pin.pConnectedTo)
498 continue;
500 hr = out_seek(This, This->in[i]->ix_off);
501 if(FAILED(hr))
502 return hr;
504 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].qwOffset = This->in[i]->ix_off;
505 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwSize = sizeof(This->in[i]->ix_data);
506 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration = This->in[i]->strh.dwLength;
507 if(This->in[i]->indx->nEntriesInUse) {
508 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration -=
509 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse-1].dwDuration;
511 This->in[i]->indx->nEntriesInUse++;
512 hr = out_write(This, This->in[i]->ix, sizeof(This->in[i]->ix_data));
513 if(FAILED(hr))
514 return hr;
517 hr = out_seek(This, 0);
518 if(FAILED(hr))
519 return hr;
521 rl.fcc = FCC('R','I','F','F');
522 rl.cb = This->out->size-sizeof(RIFFCHUNK)-2*sizeof(int);
523 rl.fccListType = FCC('A','V','I',' ');
524 hr = out_write(This, &rl, sizeof(rl));
525 if(FAILED(hr))
526 return hr;
528 rl.fcc = FCC('L','I','S','T');
529 rl.cb = This->out->movi_off - sizeof(RIFFLIST) - sizeof(RIFFCHUNK);
530 rl.fccListType = FCC('h','d','r','l');
531 hr = out_write(This, &rl, sizeof(rl));
532 if(FAILED(hr))
533 return hr;
535 /* FIXME: set This->avih.dwMaxBytesPerSec value */
536 This->avih.dwTotalFrames = (This->stop-This->start) / 10 / This->avih.dwMicroSecPerFrame;
537 hr = out_write(This, &This->avih, sizeof(This->avih));
538 if(FAILED(hr))
539 return hr;
541 for(i=0; i<This->input_pin_no; i++) {
542 if(!This->in[i]->pin.pin.pConnectedTo)
543 continue;
545 rl.cb = sizeof(FOURCC) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK) +
546 This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
547 rl.fccListType = ckidSTREAMLIST;
548 hr = out_write(This, &rl, sizeof(rl));
549 if(FAILED(hr))
550 return hr;
552 hr = out_write(This, &This->in[i]->strh, sizeof(AVISTREAMHEADER));
553 if(FAILED(hr))
554 return hr;
556 hr = out_write(This, This->in[i]->strf, sizeof(RIFFCHUNK) + This->in[i]->strf->cb);
557 if(FAILED(hr))
558 return hr;
560 hr = out_write(This, This->in[i]->indx, sizeof(This->in[i]->indx_data));
561 if(FAILED(hr))
562 return hr;
565 rl.cb = sizeof(dmlh) + sizeof(FOURCC);
566 rl.fccListType = ckidODML;
567 hr = out_write(This, &rl, sizeof(rl));
568 if(FAILED(hr))
569 return hr;
571 memset(&dmlh, 0, sizeof(dmlh));
572 dmlh.fcc = ckidAVIEXTHEADER;
573 dmlh.cb = sizeof(dmlh) - sizeof(RIFFCHUNK);
574 dmlh.dwGrandFrames = This->in[0]->strh.dwLength;
575 hr = out_write(This, &dmlh, sizeof(dmlh));
577 rl.cb = idx1_off - This->out->movi_off - sizeof(RIFFCHUNK);
578 rl.fccListType = FCC('m','o','v','i');
579 out_write(This, &rl, sizeof(rl));
580 out_flush(This);
582 IStream_Release(This->out->stream);
583 This->out->stream = NULL;
586 This->filter.state = State_Stopped;
587 return S_OK;
590 static HRESULT WINAPI AviMux_Pause(IBaseFilter *iface)
592 AviMux *This = impl_from_IBaseFilter(iface);
593 FIXME("(%p)\n", This);
594 return E_NOTIMPL;
597 static HRESULT WINAPI AviMux_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
599 AviMux *This = impl_from_IBaseFilter(iface);
600 HRESULT hr;
601 int i, stream_id;
603 TRACE("(%p)->(0x%x%08x)\n", This, (ULONG)(tStart >> 32), (ULONG)tStart);
605 if(This->filter.state == State_Running)
606 return S_OK;
608 if(This->mode != INTERLEAVE_FULL) {
609 FIXME("mode not supported (%d)\n", This->mode);
610 return E_NOTIMPL;
613 if(tStart)
614 FIXME("tStart parameter ignored\n");
616 for(i=0; i<This->input_pin_no; i++) {
617 IMediaSeeking *ms;
618 LONGLONG cur, stop;
620 if(!This->in[i]->pin.pin.pConnectedTo)
621 continue;
623 hr = IPin_QueryInterface(This->in[i]->pin.pin.pConnectedTo,
624 &IID_IMediaSeeking, (void**)&ms);
625 if(FAILED(hr))
626 continue;
628 hr = IMediaSeeking_GetPositions(ms, &cur, &stop);
629 if(FAILED(hr)) {
630 IMediaSeeking_Release(ms);
631 continue;
634 FIXME("Use IMediaSeeking to fill stream header\n");
635 IMediaSeeking_Release(ms);
638 if(This->out->pin.pMemInputPin) {
639 hr = IMemInputPin_QueryInterface(This->out->pin.pMemInputPin,
640 &IID_IStream, (void**)&This->out->stream);
641 if(FAILED(hr))
642 return hr;
645 This->idx1_entries = 0;
646 if(!This->idx1_size) {
647 This->idx1_size = 1024;
648 This->idx1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->idx1)*This->idx1_size);
649 if(!This->idx1)
650 return E_OUTOFMEMORY;
653 This->out->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER);
654 This->start = -1;
655 This->stop = -1;
656 memset(&This->avih, 0, sizeof(This->avih));
657 for(i=0; i<This->input_pin_no; i++) {
658 if(!This->in[i]->pin.pin.pConnectedTo)
659 continue;
661 This->avih.dwStreams++;
662 This->out->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK)
663 + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
665 This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000);
666 This->in[i]->strh.dwRate = This->interleave;
668 hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator);
669 if(FAILED(hr)) {
670 if(This->out->stream) {
671 IStream_Release(This->out->stream);
672 This->out->stream = NULL;
674 return hr;
678 This->out->movi_off = This->out->size;
679 This->out->size += sizeof(RIFFLIST);
681 idx1_add_entry(This, FCC('7','F','x','x'), 0, This->out->movi_off+sizeof(RIFFLIST), 0);
683 stream_id = 0;
684 for(i=0; i<This->input_pin_no; i++) {
685 if(!This->in[i]->pin.pin.pConnectedTo)
686 continue;
688 This->in[i]->ix_off = This->out->size;
689 This->out->size += sizeof(This->in[i]->ix_data);
690 This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10);
691 This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK);
692 This->in[i]->ix->wLongsPerEntry = 2;
693 This->in[i]->ix->bIndexSubType = 0;
694 This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS;
695 This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b');
696 This->in[i]->ix->qwBaseOffset = 0;
698 This->in[i]->indx->fcc = ckidAVISUPERINDEX;
699 This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK);
700 This->in[i]->indx->wLongsPerEntry = 4;
701 This->in[i]->indx->bIndexSubType = 0;
702 This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES;
703 This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId;
704 This->in[i]->stream_id = stream_id++;
707 This->out->buf_pos = 0;
708 This->out->out_pos = 0;
710 This->avih.fcc = ckidMAINAVIHEADER;
711 This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK);
712 /* TODO: Use first video stream */
713 This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10;
714 This->avih.dwPaddingGranularity = 1;
715 This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX;
716 This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth;
717 This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight;
719 This->filter.state = State_Running;
720 return S_OK;
723 static HRESULT WINAPI AviMux_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
725 AviMux *This = impl_from_IBaseFilter(iface);
726 TRACE("(%p)->(%p)\n", This, ppEnum);
727 return BaseFilterImpl_EnumPins(iface, ppEnum);
730 static HRESULT WINAPI AviMux_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
732 AviMux *This = impl_from_IBaseFilter(iface);
733 int i;
735 TRACE("(%p)->(%s %p)\n", This, debugstr_w(Id), ppPin);
737 if(!Id || !ppPin)
738 return E_POINTER;
740 if(!lstrcmpiW(Id, This->out->pin.pin.pinInfo.achName)) {
741 IPin_AddRef(&This->out->pin.pin.IPin_iface);
742 *ppPin = &This->out->pin.pin.IPin_iface;
743 return S_OK;
746 for(i=0; i<This->input_pin_no; i++) {
747 if(lstrcmpiW(Id, This->in[i]->pin.pin.pinInfo.achName))
748 continue;
750 IPin_AddRef(&This->in[i]->pin.pin.IPin_iface);
751 *ppPin = &This->in[i]->pin.pin.IPin_iface;
752 return S_OK;
755 return VFW_E_NOT_FOUND;
758 static HRESULT WINAPI AviMux_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo)
760 AviMux *This = impl_from_IBaseFilter(iface);
761 FIXME("(%p)->(%p)\n", This, pInfo);
762 return E_NOTIMPL;
765 static HRESULT WINAPI AviMux_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo)
767 AviMux *This = impl_from_IBaseFilter(iface);
768 FIXME("(%p)->(%p)\n", This, pVendorInfo);
769 return E_NOTIMPL;
772 static const IBaseFilterVtbl AviMuxVtbl = {
773 AviMux_QueryInterface,
774 BaseFilterImpl_AddRef,
775 AviMux_Release,
776 BaseFilterImpl_GetClassID,
777 AviMux_Stop,
778 AviMux_Pause,
779 AviMux_Run,
780 BaseFilterImpl_GetState,
781 BaseFilterImpl_SetSyncSource,
782 BaseFilterImpl_GetSyncSource,
783 AviMux_EnumPins,
784 AviMux_FindPin,
785 AviMux_QueryFilterInfo,
786 BaseFilterImpl_JoinFilterGraph,
787 AviMux_QueryVendorInfo
790 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface)
792 return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface);
795 static HRESULT WINAPI ConfigAviMux_QueryInterface(
796 IConfigAviMux *iface, REFIID riid, void **ppv)
798 AviMux *This = impl_from_IConfigAviMux(iface);
799 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
802 static ULONG WINAPI ConfigAviMux_AddRef(IConfigAviMux *iface)
804 AviMux *This = impl_from_IConfigAviMux(iface);
805 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
808 static ULONG WINAPI ConfigAviMux_Release(IConfigAviMux *iface)
810 AviMux *This = impl_from_IConfigAviMux(iface);
811 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
814 static HRESULT WINAPI ConfigAviMux_SetMasterStream(IConfigAviMux *iface, LONG iStream)
816 AviMux *This = impl_from_IConfigAviMux(iface);
817 FIXME("(%p)->(%d)\n", This, iStream);
818 return E_NOTIMPL;
821 static HRESULT WINAPI ConfigAviMux_GetMasterStream(IConfigAviMux *iface, LONG *pStream)
823 AviMux *This = impl_from_IConfigAviMux(iface);
824 FIXME("(%p)->(%p)\n", This, pStream);
825 return E_NOTIMPL;
828 static HRESULT WINAPI ConfigAviMux_SetOutputCompatibilityIndex(
829 IConfigAviMux *iface, BOOL fOldIndex)
831 AviMux *This = impl_from_IConfigAviMux(iface);
832 FIXME("(%p)->(%x)\n", This, fOldIndex);
833 return E_NOTIMPL;
836 static HRESULT WINAPI ConfigAviMux_GetOutputCompatibilityIndex(
837 IConfigAviMux *iface, BOOL *pfOldIndex)
839 AviMux *This = impl_from_IConfigAviMux(iface);
840 FIXME("(%p)->(%p)\n", This, pfOldIndex);
841 return E_NOTIMPL;
844 static const IConfigAviMuxVtbl ConfigAviMuxVtbl = {
845 ConfigAviMux_QueryInterface,
846 ConfigAviMux_AddRef,
847 ConfigAviMux_Release,
848 ConfigAviMux_SetMasterStream,
849 ConfigAviMux_GetMasterStream,
850 ConfigAviMux_SetOutputCompatibilityIndex,
851 ConfigAviMux_GetOutputCompatibilityIndex
854 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface)
856 return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface);
859 static HRESULT WINAPI ConfigInterleaving_QueryInterface(
860 IConfigInterleaving *iface, REFIID riid, void **ppv)
862 AviMux *This = impl_from_IConfigInterleaving(iface);
863 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
866 static ULONG WINAPI ConfigInterleaving_AddRef(IConfigInterleaving *iface)
868 AviMux *This = impl_from_IConfigInterleaving(iface);
869 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
872 static ULONG WINAPI ConfigInterleaving_Release(IConfigInterleaving *iface)
874 AviMux *This = impl_from_IConfigInterleaving(iface);
875 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
878 static HRESULT WINAPI ConfigInterleaving_put_Mode(
879 IConfigInterleaving *iface, InterleavingMode mode)
881 AviMux *This = impl_from_IConfigInterleaving(iface);
883 TRACE("(%p)->(%d)\n", This, mode);
885 if(mode>INTERLEAVE_NONE_BUFFERED)
886 return E_INVALIDARG;
888 if(This->mode != mode) {
889 if(This->out->pin.pin.pConnectedTo) {
890 HRESULT hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph,
891 &This->out->pin.pin.IPin_iface);
892 if(FAILED(hr))
893 return hr;
896 This->mode = mode;
899 return S_OK;
902 static HRESULT WINAPI ConfigInterleaving_get_Mode(
903 IConfigInterleaving *iface, InterleavingMode *pMode)
905 AviMux *This = impl_from_IConfigInterleaving(iface);
906 FIXME("(%p)->(%p)\n", This, pMode);
907 return E_NOTIMPL;
910 static HRESULT WINAPI ConfigInterleaving_put_Interleaving(IConfigInterleaving *iface,
911 const REFERENCE_TIME *prtInterleave, const REFERENCE_TIME *prtPreroll)
913 AviMux *This = impl_from_IConfigInterleaving(iface);
915 TRACE("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
917 if(prtInterleave)
918 This->interleave = *prtInterleave;
919 if(prtPreroll)
920 This->preroll = *prtPreroll;
921 return S_OK;
924 static HRESULT WINAPI ConfigInterleaving_get_Interleaving(IConfigInterleaving *iface,
925 REFERENCE_TIME *prtInterleave, REFERENCE_TIME *prtPreroll)
927 AviMux *This = impl_from_IConfigInterleaving(iface);
928 FIXME("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
929 return E_NOTIMPL;
932 static const IConfigInterleavingVtbl ConfigInterleavingVtbl = {
933 ConfigInterleaving_QueryInterface,
934 ConfigInterleaving_AddRef,
935 ConfigInterleaving_Release,
936 ConfigInterleaving_put_Mode,
937 ConfigInterleaving_get_Mode,
938 ConfigInterleaving_put_Interleaving,
939 ConfigInterleaving_get_Interleaving
942 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface)
944 return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface);
947 static HRESULT WINAPI MediaSeeking_QueryInterface(
948 IMediaSeeking *iface, REFIID riid, void **ppv)
950 AviMux *This = impl_from_IMediaSeeking(iface);
951 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
954 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
956 AviMux *This = impl_from_IMediaSeeking(iface);
957 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
960 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
962 AviMux *This = impl_from_IMediaSeeking(iface);
963 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
966 static HRESULT WINAPI MediaSeeking_GetCapabilities(
967 IMediaSeeking *iface, DWORD *pCapabilities)
969 AviMux *This = impl_from_IMediaSeeking(iface);
970 FIXME("(%p)->(%p)\n", This, pCapabilities);
971 return E_NOTIMPL;
974 static HRESULT WINAPI MediaSeeking_CheckCapabilities(
975 IMediaSeeking *iface, DWORD *pCapabilities)
977 AviMux *This = impl_from_IMediaSeeking(iface);
978 FIXME("(%p)->(%p)\n", This, pCapabilities);
979 return E_NOTIMPL;
982 static HRESULT WINAPI MediaSeeking_IsFormatSupported(
983 IMediaSeeking *iface, const GUID *pFormat)
985 AviMux *This = impl_from_IMediaSeeking(iface);
986 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
987 return E_NOTIMPL;
990 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(
991 IMediaSeeking *iface, GUID *pFormat)
993 AviMux *This = impl_from_IMediaSeeking(iface);
994 FIXME("(%p)->(%p)\n", This, pFormat);
995 return E_NOTIMPL;
998 static HRESULT WINAPI MediaSeeking_GetTimeFormat(
999 IMediaSeeking *iface, GUID *pFormat)
1001 AviMux *This = impl_from_IMediaSeeking(iface);
1002 FIXME("(%p)->(%p)\n", This, pFormat);
1003 return E_NOTIMPL;
1006 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(
1007 IMediaSeeking *iface, const GUID *pFormat)
1009 AviMux *This = impl_from_IMediaSeeking(iface);
1010 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
1011 return E_NOTIMPL;
1014 static HRESULT WINAPI MediaSeeking_SetTimeFormat(
1015 IMediaSeeking *iface, const GUID *pFormat)
1017 AviMux *This = impl_from_IMediaSeeking(iface);
1018 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
1019 return E_NOTIMPL;
1022 static HRESULT WINAPI MediaSeeking_GetDuration(
1023 IMediaSeeking *iface, LONGLONG *pDuration)
1025 AviMux *This = impl_from_IMediaSeeking(iface);
1026 FIXME("(%p)->(%p)\n", This, pDuration);
1027 return E_NOTIMPL;
1030 static HRESULT WINAPI MediaSeeking_GetStopPosition(
1031 IMediaSeeking *iface, LONGLONG *pStop)
1033 AviMux *This = impl_from_IMediaSeeking(iface);
1034 FIXME("(%p)->(%p)\n", This, pStop);
1035 return E_NOTIMPL;
1038 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(
1039 IMediaSeeking *iface, LONGLONG *pCurrent)
1041 AviMux *This = impl_from_IMediaSeeking(iface);
1042 FIXME("(%p)->(%p)\n", This, pCurrent);
1043 return E_NOTIMPL;
1046 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
1047 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
1049 AviMux *This = impl_from_IMediaSeeking(iface);
1050 FIXME("(%p)->(%p %s %s %s)\n", This, pTarget, debugstr_guid(pTargetFormat),
1051 wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
1052 return E_NOTIMPL;
1055 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
1056 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
1058 AviMux *This = impl_from_IMediaSeeking(iface);
1059 FIXME("(%p)->(%p %x %p %x)\n", This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
1060 return E_NOTIMPL;
1063 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
1064 LONGLONG *pCurrent, LONGLONG *pStop)
1066 AviMux *This = impl_from_IMediaSeeking(iface);
1067 FIXME("(%p)->(%p %p)\n", This, pCurrent, pStop);
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
1072 LONGLONG *pEarliest, LONGLONG *pLatest)
1074 AviMux *This = impl_from_IMediaSeeking(iface);
1075 FIXME("(%p)->(%p %p)\n", This, pEarliest, pLatest);
1076 return E_NOTIMPL;
1079 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
1081 AviMux *This = impl_from_IMediaSeeking(iface);
1082 FIXME("(%p)->(%lf)\n", This, dRate);
1083 return E_NOTIMPL;
1086 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
1088 AviMux *This = impl_from_IMediaSeeking(iface);
1089 FIXME("(%p)->(%p)\n", This, pdRate);
1090 return E_NOTIMPL;
1093 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
1095 AviMux *This = impl_from_IMediaSeeking(iface);
1096 FIXME("(%p)->(%p)\n", This, pllPreroll);
1097 return E_NOTIMPL;
1100 static const IMediaSeekingVtbl MediaSeekingVtbl = {
1101 MediaSeeking_QueryInterface,
1102 MediaSeeking_AddRef,
1103 MediaSeeking_Release,
1104 MediaSeeking_GetCapabilities,
1105 MediaSeeking_CheckCapabilities,
1106 MediaSeeking_IsFormatSupported,
1107 MediaSeeking_QueryPreferredFormat,
1108 MediaSeeking_GetTimeFormat,
1109 MediaSeeking_IsUsingTimeFormat,
1110 MediaSeeking_SetTimeFormat,
1111 MediaSeeking_GetDuration,
1112 MediaSeeking_GetStopPosition,
1113 MediaSeeking_GetCurrentPosition,
1114 MediaSeeking_ConvertTimeFormat,
1115 MediaSeeking_SetPositions,
1116 MediaSeeking_GetPositions,
1117 MediaSeeking_GetAvailable,
1118 MediaSeeking_SetRate,
1119 MediaSeeking_GetRate,
1120 MediaSeeking_GetPreroll
1123 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface)
1125 return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface);
1128 static HRESULT WINAPI PersistMediaPropertyBag_QueryInterface(
1129 IPersistMediaPropertyBag *iface, REFIID riid, void **ppv)
1131 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1132 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1135 static ULONG WINAPI PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag *iface)
1137 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1138 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1141 static ULONG WINAPI PersistMediaPropertyBag_Release(IPersistMediaPropertyBag *iface)
1143 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1144 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1147 static HRESULT WINAPI PersistMediaPropertyBag_GetClassID(
1148 IPersistMediaPropertyBag *iface, CLSID *pClassID)
1150 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1151 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID);
1154 static HRESULT WINAPI PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag *iface)
1156 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1157 FIXME("(%p)->()\n", This);
1158 return E_NOTIMPL;
1161 static HRESULT WINAPI PersistMediaPropertyBag_Load(IPersistMediaPropertyBag *iface,
1162 IMediaPropertyBag *pPropBag, IErrorLog *pErrorLog)
1164 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1165 FIXME("(%p)->()\n", This);
1166 return E_NOTIMPL;
1169 static HRESULT WINAPI PersistMediaPropertyBag_Save(IPersistMediaPropertyBag *iface,
1170 IMediaPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
1172 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1173 FIXME("(%p)->()\n", This);
1174 return E_NOTIMPL;
1177 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl = {
1178 PersistMediaPropertyBag_QueryInterface,
1179 PersistMediaPropertyBag_AddRef,
1180 PersistMediaPropertyBag_Release,
1181 PersistMediaPropertyBag_GetClassID,
1182 PersistMediaPropertyBag_InitNew,
1183 PersistMediaPropertyBag_Load,
1184 PersistMediaPropertyBag_Save
1187 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface)
1189 return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface);
1192 static HRESULT WINAPI SpecifyPropertyPages_QueryInterface(
1193 ISpecifyPropertyPages *iface, REFIID riid, void **ppv)
1195 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1196 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1199 static ULONG WINAPI SpecifyPropertyPages_AddRef(ISpecifyPropertyPages *iface)
1201 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1202 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1205 static ULONG WINAPI SpecifyPropertyPages_Release(ISpecifyPropertyPages *iface)
1207 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1208 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1211 static HRESULT WINAPI SpecifyPropertyPages_GetPages(
1212 ISpecifyPropertyPages *iface, CAUUID *pPages)
1214 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1215 FIXME("(%p)->(%p)\n", This, pPages);
1216 return E_NOTIMPL;
1219 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = {
1220 SpecifyPropertyPages_QueryInterface,
1221 SpecifyPropertyPages_AddRef,
1222 SpecifyPropertyPages_Release,
1223 SpecifyPropertyPages_GetPages
1226 static HRESULT WINAPI AviMuxOut_AttemptConnection(BasePin *base,
1227 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1229 PIN_DIRECTION dir;
1230 HRESULT hr;
1232 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", base, pReceivePin, pmt);
1233 dump_AM_MEDIA_TYPE(pmt);
1235 hr = IPin_QueryDirection(pReceivePin, &dir);
1236 if(hr==S_OK && dir!=PINDIR_INPUT)
1237 return VFW_E_INVALID_DIRECTION;
1239 return BaseOutputPinImpl_AttemptConnection(base, pReceivePin, pmt);
1242 static LONG WINAPI AviMuxOut_GetMediaTypeVersion(BasePin *base)
1244 return 0;
1247 static HRESULT WINAPI AviMuxOut_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
1249 TRACE("(%p)->(%d %p)\n", base, iPosition, amt);
1251 if(iPosition < 0)
1252 return E_INVALIDARG;
1253 if(iPosition > 0)
1254 return VFW_S_NO_MORE_ITEMS;
1256 amt->majortype = MEDIATYPE_Stream;
1257 amt->subtype = MEDIASUBTYPE_Avi;
1258 amt->bFixedSizeSamples = TRUE;
1259 amt->bTemporalCompression = FALSE;
1260 amt->lSampleSize = 1;
1261 amt->formattype = GUID_NULL;
1262 amt->pUnk = NULL;
1263 amt->cbFormat = 0;
1264 amt->pbFormat = NULL;
1265 return S_OK;
1268 static HRESULT WINAPI AviMuxOut_DecideAllocator(BaseOutputPin *base,
1269 IMemInputPin *pPin, IMemAllocator **pAlloc)
1271 ALLOCATOR_PROPERTIES req, actual;
1272 HRESULT hr;
1274 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc);
1276 hr = BaseOutputPinImpl_InitAllocator(base, pAlloc);
1277 if(FAILED(hr))
1278 return hr;
1280 hr = IMemInputPin_GetAllocatorRequirements(pPin, &req);
1281 if(FAILED(hr))
1282 req.cbAlign = 1;
1283 req.cBuffers = 32;
1284 req.cbBuffer = 0;
1285 req.cbPrefix = 0;
1287 hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual);
1288 if(FAILED(hr))
1289 return hr;
1291 return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE);
1294 static HRESULT WINAPI AviMuxOut_BreakConnect(BaseOutputPin *base)
1296 FIXME("(%p)\n", base);
1297 return E_NOTIMPL;
1300 static const BaseOutputPinFuncTable AviMuxOut_BaseOutputFuncTable = {
1302 NULL,
1303 AviMuxOut_AttemptConnection,
1304 AviMuxOut_GetMediaTypeVersion,
1305 AviMuxOut_GetMediaType
1307 NULL,
1308 AviMuxOut_DecideAllocator,
1309 AviMuxOut_BreakConnect
1312 static inline AviMux* impl_from_out_IPin(IPin *iface)
1314 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface);
1315 IBaseFilter *bf = bp->pinInfo.pFilter;
1317 return impl_from_IBaseFilter(bf);
1320 static HRESULT WINAPI AviMuxOut_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1322 AviMux *This = impl_from_out_IPin(iface);
1324 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1326 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1327 *ppv = iface;
1328 else if(IsEqualIID(riid, &IID_IQualityControl))
1329 *ppv = &This->out->IQualityControl_iface;
1330 else {
1331 FIXME("no interface for %s\n", debugstr_guid(riid));
1332 *ppv = NULL;
1333 return E_NOINTERFACE;
1336 IUnknown_AddRef((IUnknown*)*ppv);
1337 return S_OK;
1340 static ULONG WINAPI AviMuxOut_AddRef(IPin *iface)
1342 AviMux *This = impl_from_out_IPin(iface);
1343 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1346 static ULONG WINAPI AviMuxOut_Release(IPin *iface)
1348 AviMux *This = impl_from_out_IPin(iface);
1349 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1352 static HRESULT WINAPI AviMuxOut_Connect(IPin *iface,
1353 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1355 AviMux *This = impl_from_out_IPin(iface);
1356 HRESULT hr;
1357 int i;
1359 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", This, pReceivePin, pmt);
1360 dump_AM_MEDIA_TYPE(pmt);
1362 hr = BaseOutputPinImpl_Connect(iface, pReceivePin, pmt);
1363 if(FAILED(hr))
1364 return hr;
1366 for(i=0; i<This->input_pin_no; i++) {
1367 if(!This->in[i]->pin.pin.pConnectedTo)
1368 continue;
1370 hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, &This->in[i]->pin.pin.IPin_iface);
1371 if(FAILED(hr)) {
1372 BaseOutputPinImpl_Disconnect(iface);
1373 break;
1377 if(hr == S_OK)
1378 IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1379 return hr;
1382 static HRESULT WINAPI AviMuxOut_ReceiveConnection(IPin *iface,
1383 IPin *pConnector, const AM_MEDIA_TYPE *pmt)
1385 AviMux *This = impl_from_out_IPin(iface);
1386 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p)\n", This, pConnector, pmt);
1387 dump_AM_MEDIA_TYPE(pmt);
1388 return BaseOutputPinImpl_ReceiveConnection(iface, pConnector, pmt);
1391 static HRESULT WINAPI AviMuxOut_Disconnect(IPin *iface)
1393 AviMux *This = impl_from_out_IPin(iface);
1394 HRESULT hr;
1396 TRACE("(%p)\n", This);
1398 hr = BaseOutputPinImpl_Disconnect(iface);
1399 if(hr == S_OK)
1400 IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1401 return hr;
1404 static HRESULT WINAPI AviMuxOut_ConnectedTo(IPin *iface, IPin **pPin)
1406 AviMux *This = impl_from_out_IPin(iface);
1407 TRACE("(%p)->(%p)\n", This, pPin);
1408 return BasePinImpl_ConnectedTo(iface, pPin);
1411 static HRESULT WINAPI AviMuxOut_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
1413 AviMux *This = impl_from_out_IPin(iface);
1414 TRACE("(%p)->(%p)\n", This, pmt);
1415 return BasePinImpl_ConnectionMediaType(iface, pmt);
1418 static HRESULT WINAPI AviMuxOut_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
1420 AviMux *This = impl_from_out_IPin(iface);
1421 TRACE("(%p)->(%p)\n", This, pInfo);
1422 return BasePinImpl_QueryPinInfo(iface, pInfo);
1425 static HRESULT WINAPI AviMuxOut_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
1427 AviMux *This = impl_from_out_IPin(iface);
1428 TRACE("(%p)->(%p)\n", This, pPinDir);
1429 return BasePinImpl_QueryDirection(iface, pPinDir);
1432 static HRESULT WINAPI AviMuxOut_QueryId(IPin *iface, LPWSTR *Id)
1434 AviMux *This = impl_from_out_IPin(iface);
1435 TRACE("(%p)->(%p)\n", This, Id);
1436 return BasePinImpl_QueryId(iface, Id);
1439 static HRESULT WINAPI AviMuxOut_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
1441 AviMux *This = impl_from_out_IPin(iface);
1442 TRACE("(%p)->(AM_MEDIA_TYPE(%p))\n", This, pmt);
1443 dump_AM_MEDIA_TYPE(pmt);
1444 return BasePinImpl_QueryAccept(iface, pmt);
1447 static HRESULT WINAPI AviMuxOut_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1449 AviMux *This = impl_from_out_IPin(iface);
1450 TRACE("(%p)->(%p)\n", This, ppEnum);
1451 return BasePinImpl_EnumMediaTypes(iface, ppEnum);
1454 static HRESULT WINAPI AviMuxOut_QueryInternalConnections(
1455 IPin *iface, IPin **apPin, ULONG *nPin)
1457 AviMux *This = impl_from_out_IPin(iface);
1458 FIXME("(%p)->(%p %p)\n", This, apPin, nPin);
1459 return E_NOTIMPL;
1462 static HRESULT WINAPI AviMuxOut_EndOfStream(IPin *iface)
1464 AviMux *This = impl_from_out_IPin(iface);
1465 TRACE("(%p)\n", This);
1466 return BaseOutputPinImpl_EndOfStream(iface);
1469 static HRESULT WINAPI AviMuxOut_BeginFlush(IPin *iface)
1471 AviMux *This = impl_from_out_IPin(iface);
1472 TRACE("(%p)\n", This);
1473 return BaseOutputPinImpl_BeginFlush(iface);
1476 static HRESULT WINAPI AviMuxOut_EndFlush(IPin *iface)
1478 AviMux *This = impl_from_out_IPin(iface);
1479 TRACE("(%p)\n", This);
1480 return BaseOutputPinImpl_EndFlush(iface);
1483 static HRESULT WINAPI AviMuxOut_NewSegment(IPin *iface, REFERENCE_TIME tStart,
1484 REFERENCE_TIME tStop, double dRate)
1486 AviMux *This = impl_from_out_IPin(iface);
1487 TRACE("(%p)->(0x%x%08x 0x%x%08x %lf)\n", This, (ULONG)(tStart >> 32),
1488 (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
1489 return BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1492 static const IPinVtbl AviMuxOut_PinVtbl = {
1493 AviMuxOut_QueryInterface,
1494 AviMuxOut_AddRef,
1495 AviMuxOut_Release,
1496 AviMuxOut_Connect,
1497 AviMuxOut_ReceiveConnection,
1498 AviMuxOut_Disconnect,
1499 AviMuxOut_ConnectedTo,
1500 AviMuxOut_ConnectionMediaType,
1501 AviMuxOut_QueryPinInfo,
1502 AviMuxOut_QueryDirection,
1503 AviMuxOut_QueryId,
1504 AviMuxOut_QueryAccept,
1505 AviMuxOut_EnumMediaTypes,
1506 AviMuxOut_QueryInternalConnections,
1507 AviMuxOut_EndOfStream,
1508 AviMuxOut_BeginFlush,
1509 AviMuxOut_EndFlush,
1510 AviMuxOut_NewSegment
1513 static inline AviMux* impl_from_out_IQualityControl(IQualityControl *iface)
1515 AviMuxOut *amo = CONTAINING_RECORD(iface, AviMuxOut, IQualityControl_iface);
1516 return impl_from_IBaseFilter(amo->pin.pin.pinInfo.pFilter);
1519 static HRESULT WINAPI AviMuxOut_QualityControl_QueryInterface(
1520 IQualityControl *iface, REFIID riid, void **ppv)
1522 AviMux *This = impl_from_out_IQualityControl(iface);
1523 return IPin_QueryInterface(&This->out->pin.pin.IPin_iface, riid, ppv);
1526 static ULONG WINAPI AviMuxOut_QualityControl_AddRef(IQualityControl *iface)
1528 AviMux *This = impl_from_out_IQualityControl(iface);
1529 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1532 static ULONG WINAPI AviMuxOut_QualityControl_Release(IQualityControl *iface)
1534 AviMux *This = impl_from_out_IQualityControl(iface);
1535 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1538 static HRESULT WINAPI AviMuxOut_QualityControl_Notify(IQualityControl *iface,
1539 IBaseFilter *pSelf, Quality q)
1541 AviMux *This = impl_from_out_IQualityControl(iface);
1542 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This, pSelf,
1543 q.Type, q.Proportion,
1544 wine_dbgstr_longlong(q.Late),
1545 wine_dbgstr_longlong(q.TimeStamp));
1546 return E_NOTIMPL;
1549 static HRESULT WINAPI AviMuxOut_QualityControl_SetSink(
1550 IQualityControl *iface, IQualityControl *piqc)
1552 AviMux *This = impl_from_out_IQualityControl(iface);
1553 FIXME("(%p)->(%p)\n", This, piqc);
1554 return E_NOTIMPL;
1557 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl = {
1558 AviMuxOut_QualityControl_QueryInterface,
1559 AviMuxOut_QualityControl_AddRef,
1560 AviMuxOut_QualityControl_Release,
1561 AviMuxOut_QualityControl_Notify,
1562 AviMuxOut_QualityControl_SetSink
1565 static HRESULT WINAPI AviMuxIn_CheckMediaType(BasePin *base, const AM_MEDIA_TYPE *pmt)
1567 TRACE("(%p:%s)->(AM_MEDIA_TYPE(%p))\n", base, debugstr_w(base->pinInfo.achName), pmt);
1568 dump_AM_MEDIA_TYPE(pmt);
1570 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) &&
1571 IsEqualIID(&pmt->formattype, &FORMAT_WaveFormatEx))
1572 return S_OK;
1573 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Interleaved) &&
1574 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo))
1575 return S_OK;
1576 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1577 (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo) ||
1578 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo)))
1579 return S_OK;
1580 return S_FALSE;
1583 static LONG WINAPI AviMuxIn_GetMediaTypeVersion(BasePin *base)
1585 return 0;
1588 static HRESULT WINAPI AviMuxIn_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
1590 return S_FALSE;
1593 static HRESULT WINAPI AviMuxIn_Receive(BaseInputPin *base, IMediaSample *pSample)
1595 AviMuxIn *avimuxin = CONTAINING_RECORD(base, AviMuxIn, pin);
1596 AviMux *avimux = impl_from_IBaseFilter(base->pin.pinInfo.pFilter);
1597 REFERENCE_TIME start, stop;
1598 IMediaSample *sample;
1599 int frames_no;
1600 IMediaSample2 *ms2;
1601 BYTE *frame, *buf;
1602 DWORD max_size, size;
1603 DWORD flags;
1604 HRESULT hr;
1606 TRACE("(%p:%s)->(%p)\n", base, debugstr_w(base->pin.pinInfo.achName), pSample);
1608 hr = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&ms2);
1609 if(SUCCEEDED(hr)) {
1610 AM_SAMPLE2_PROPERTIES props;
1612 memset(&props, 0, sizeof(props));
1613 hr = IMediaSample2_GetProperties(ms2, sizeof(props), (BYTE*)&props);
1614 IMediaSample2_Release(ms2);
1615 if(FAILED(hr))
1616 return hr;
1618 flags = props.dwSampleFlags;
1619 frame = props.pbBuffer;
1620 size = props.lActual;
1621 }else {
1622 flags = IMediaSample_IsSyncPoint(pSample) == S_OK ? AM_SAMPLE_SPLICEPOINT : 0;
1623 hr = IMediaSample_GetPointer(pSample, &frame);
1624 if(FAILED(hr))
1625 return hr;
1626 size = IMediaSample_GetActualDataLength(pSample);
1629 if(!avimuxin->pin.pin.mtCurrent.bTemporalCompression)
1630 flags |= AM_SAMPLE_SPLICEPOINT;
1632 hr = IMediaSample_GetTime(pSample, &start, &stop);
1633 if(FAILED(hr))
1634 return hr;
1636 if(avimuxin->stop>stop)
1637 return VFW_E_START_TIME_AFTER_END;
1639 if(avimux->start == -1)
1640 avimux->start = start;
1641 if(avimux->stop < stop)
1642 avimux->stop = stop;
1644 if(avimux->avih.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1645 avimux->avih.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1646 if(avimuxin->strh.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1647 avimuxin->strh.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1649 frames_no = 1;
1650 if(avimuxin->stop!=-1 && start > avimuxin->stop) {
1651 frames_no += (double)(start - avimuxin->stop) / 10000000
1652 * avimuxin->strh.dwRate / avimuxin->strh.dwScale + 0.5;
1654 avimuxin->stop = stop;
1656 while(--frames_no) {
1657 /* TODO: store all control frames in one buffer */
1658 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1659 if(FAILED(hr))
1660 return hr;
1661 hr = IMediaSample_SetActualDataLength(sample, 0);
1662 if(SUCCEEDED(hr))
1663 hr = IMediaSample_SetDiscontinuity(sample, TRUE);
1664 if(SUCCEEDED(hr))
1665 hr = IMediaSample_SetSyncPoint(sample, FALSE);
1666 if(SUCCEEDED(hr))
1667 hr = queue_sample(avimux, avimuxin, sample);
1668 IMediaSample_Release(sample);
1669 if(FAILED(hr))
1670 return hr;
1673 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1674 if(FAILED(hr))
1675 return hr;
1676 max_size = IMediaSample_GetSize(sample);
1677 if(size > max_size)
1678 size = max_size;
1679 hr = IMediaSample_SetActualDataLength(sample, size);
1680 if(SUCCEEDED(hr))
1681 hr = IMediaSample_SetDiscontinuity(sample, FALSE);
1682 if(SUCCEEDED(hr))
1683 hr = IMediaSample_SetSyncPoint(sample, flags & AM_SAMPLE_SPLICEPOINT);
1684 /* TODO: avoid unnecessary copying */
1685 if(SUCCEEDED(hr))
1686 hr = IMediaSample_GetPointer(sample, &buf);
1687 if(SUCCEEDED(hr)) {
1688 memcpy(buf, frame, size);
1689 hr = queue_sample(avimux, avimuxin, sample);
1691 IMediaSample_Release(sample);
1693 return hr;
1696 static const BaseInputPinFuncTable AviMuxIn_BaseInputFuncTable = {
1698 AviMuxIn_CheckMediaType,
1699 NULL,
1700 AviMuxIn_GetMediaTypeVersion,
1701 AviMuxIn_GetMediaType
1703 AviMuxIn_Receive
1706 static inline AviMux* impl_from_in_IPin(IPin *iface)
1708 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface);
1709 IBaseFilter *bf = bp->pinInfo.pFilter;
1711 return impl_from_IBaseFilter(bf);
1714 static inline AviMuxIn* AviMuxIn_from_IPin(IPin *iface)
1716 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface);
1717 BaseInputPin *bip = CONTAINING_RECORD(bp, BaseInputPin, pin);
1718 return CONTAINING_RECORD(bip, AviMuxIn, pin);
1721 static HRESULT WINAPI AviMuxIn_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1723 AviMux *This = impl_from_in_IPin(iface);
1724 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1726 TRACE("(%p:%s)->(%s %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
1727 debugstr_guid(riid), ppv);
1729 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1730 *ppv = &avimuxin->pin.pin.IPin_iface;
1731 else if(IsEqualIID(riid, &IID_IAMStreamControl))
1732 *ppv = &avimuxin->IAMStreamControl_iface;
1733 else if(IsEqualIID(riid, &IID_IMemInputPin))
1734 *ppv = &avimuxin->pin.IMemInputPin_iface;
1735 else if(IsEqualIID(riid, &IID_IPropertyBag))
1736 *ppv = &avimuxin->IPropertyBag_iface;
1737 else if(IsEqualIID(riid, &IID_IQualityControl))
1738 *ppv = &avimuxin->IQualityControl_iface;
1739 else {
1740 FIXME("no interface for %s\n", debugstr_guid(riid));
1741 *ppv = NULL;
1742 return E_NOINTERFACE;
1745 IUnknown_AddRef((IUnknown*)*ppv);
1746 return S_OK;
1749 static ULONG WINAPI AviMuxIn_AddRef(IPin *iface)
1751 AviMux *This = impl_from_in_IPin(iface);
1752 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1755 static ULONG WINAPI AviMuxIn_Release(IPin *iface)
1757 AviMux *This = impl_from_in_IPin(iface);
1758 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1761 static HRESULT WINAPI AviMuxIn_Connect(IPin *iface,
1762 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1764 AviMux *This = impl_from_in_IPin(iface);
1765 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1766 TRACE("(%p:%s)->(%p AM_MEDIA_TYPE(%p))\n", This,
1767 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pReceivePin, pmt);
1768 dump_AM_MEDIA_TYPE(pmt);
1769 return BaseInputPinImpl_Connect(iface, pReceivePin, pmt);
1772 static HRESULT WINAPI AviMuxIn_ReceiveConnection(IPin *iface,
1773 IPin *pConnector, const AM_MEDIA_TYPE *pmt)
1775 AviMux *This = impl_from_in_IPin(iface);
1776 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1777 HRESULT hr;
1779 TRACE("(%p:%s)->(%p AM_MEDIA_TYPE(%p))\n", This,
1780 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pConnector, pmt);
1781 dump_AM_MEDIA_TYPE(pmt);
1783 if(!pmt)
1784 return E_POINTER;
1786 hr = BaseInputPinImpl_ReceiveConnection(iface, pConnector, pmt);
1787 if(FAILED(hr))
1788 return hr;
1790 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1791 IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
1792 ALLOCATOR_PROPERTIES req, act;
1793 VIDEOINFOHEADER *vih;
1794 int size;
1796 vih = (VIDEOINFOHEADER*)pmt->pbFormat;
1797 avimuxin->strh.fcc = ckidSTREAMHEADER;
1798 avimuxin->strh.cb = sizeof(AVISTREAMHEADER) - FIELD_OFFSET(AVISTREAMHEADER, fccType);
1799 avimuxin->strh.fccType = streamtypeVIDEO;
1800 /* FIXME: fccHandler should be set differently */
1801 avimuxin->strh.fccHandler = vih->bmiHeader.biCompression ?
1802 vih->bmiHeader.biCompression : FCC('D','I','B',' ');
1803 avimuxin->avg_time_per_frame = vih->AvgTimePerFrame;
1804 avimuxin->stop = -1;
1806 req.cBuffers = 32;
1807 req.cbBuffer = vih->bmiHeader.biSizeImage;
1808 req.cbAlign = 1;
1809 req.cbPrefix = sizeof(void*);
1810 hr = IMemAllocator_SetProperties(avimuxin->samples_allocator, &req, &act);
1811 if(SUCCEEDED(hr))
1812 hr = IMemAllocator_Commit(avimuxin->samples_allocator);
1813 if(FAILED(hr)) {
1814 BasePinImpl_Disconnect(iface);
1815 return hr;
1818 size = pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
1819 avimuxin->strf = CoTaskMemAlloc(sizeof(RIFFCHUNK) + ALIGN(FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed])));
1820 avimuxin->strf->fcc = ckidSTREAMFORMAT;
1821 avimuxin->strf->cb = FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]);
1822 if(size > avimuxin->strf->cb)
1823 size = avimuxin->strf->cb;
1824 memcpy(avimuxin->strf->data, &vih->bmiHeader, size);
1825 }else {
1826 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt->majortype),
1827 debugstr_guid(&pmt->formattype));
1828 return E_NOTIMPL;
1831 return create_input_pin(This);
1834 static HRESULT WINAPI AviMuxIn_Disconnect(IPin *iface)
1836 AviMux *This = impl_from_in_IPin(iface);
1837 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1838 IMediaSample **prev, *cur;
1839 HRESULT hr;
1841 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
1843 hr = BasePinImpl_Disconnect(iface);
1844 if(FAILED(hr))
1845 return hr;
1847 IMemAllocator_Decommit(avimuxin->samples_allocator);
1848 while(avimuxin->samples_head) {
1849 cur = avimuxin->samples_head;
1850 hr = IMediaSample_GetPointer(cur, (BYTE**)&prev);
1851 if(FAILED(hr))
1852 break;
1853 prev--;
1855 cur = avimuxin->samples_head;
1856 avimuxin->samples_head = *prev;
1857 IMediaSample_Release(cur);
1859 if(cur == avimuxin->samples_head)
1860 avimuxin->samples_head = NULL;
1862 CoTaskMemFree(avimuxin->strf);
1863 avimuxin->strf = NULL;
1864 return hr;
1867 static HRESULT WINAPI AviMuxIn_ConnectedTo(IPin *iface, IPin **pPin)
1869 AviMux *This = impl_from_in_IPin(iface);
1870 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1871 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pPin);
1872 return BasePinImpl_ConnectedTo(iface, pPin);
1875 static HRESULT WINAPI AviMuxIn_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
1877 AviMux *This = impl_from_in_IPin(iface);
1878 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1879 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pmt);
1880 return BasePinImpl_ConnectionMediaType(iface, pmt);
1883 static HRESULT WINAPI AviMuxIn_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
1885 AviMux *This = impl_from_in_IPin(iface);
1886 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1887 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pInfo);
1888 return BasePinImpl_QueryPinInfo(iface, pInfo);
1891 static HRESULT WINAPI AviMuxIn_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
1893 AviMux *This = impl_from_in_IPin(iface);
1894 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1895 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pPinDir);
1896 return BasePinImpl_QueryDirection(iface, pPinDir);
1899 static HRESULT WINAPI AviMuxIn_QueryId(IPin *iface, LPWSTR *Id)
1901 AviMux *This = impl_from_in_IPin(iface);
1902 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1903 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), Id);
1904 return BasePinImpl_QueryId(iface, Id);
1907 static HRESULT WINAPI AviMuxIn_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
1909 AviMux *This = impl_from_in_IPin(iface);
1910 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1911 TRACE("(%p:%s)->(AM_MEDIA_TYPE(%p))\n", This,
1912 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pmt);
1913 dump_AM_MEDIA_TYPE(pmt);
1914 return BasePinImpl_QueryAccept(iface, pmt);
1917 static HRESULT WINAPI AviMuxIn_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1919 AviMux *This = impl_from_in_IPin(iface);
1920 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1921 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), ppEnum);
1922 return BasePinImpl_EnumMediaTypes(iface, ppEnum);
1925 static HRESULT WINAPI AviMuxIn_QueryInternalConnections(
1926 IPin *iface, IPin **apPin, ULONG *nPin)
1928 AviMux *This = impl_from_in_IPin(iface);
1929 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1930 TRACE("(%p:%s)->(%p %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), apPin, nPin);
1931 return BasePinImpl_QueryInternalConnections(iface, apPin, nPin);
1934 static HRESULT WINAPI AviMuxIn_EndOfStream(IPin *iface)
1936 AviMux *This = impl_from_in_IPin(iface);
1937 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1938 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
1939 return BaseInputPinImpl_EndOfStream(iface);
1942 static HRESULT WINAPI AviMuxIn_BeginFlush(IPin *iface)
1944 AviMux *This = impl_from_in_IPin(iface);
1945 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1946 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
1947 return BaseInputPinImpl_BeginFlush(iface);
1950 static HRESULT WINAPI AviMuxIn_EndFlush(IPin *iface)
1952 AviMux *This = impl_from_in_IPin(iface);
1953 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1954 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
1955 return BaseInputPinImpl_EndFlush(iface);
1958 static HRESULT WINAPI AviMuxIn_NewSegment(IPin *iface, REFERENCE_TIME tStart,
1959 REFERENCE_TIME tStop, double dRate)
1961 AviMux *This = impl_from_in_IPin(iface);
1962 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1963 TRACE("(%p:%s)->(0x%x%08x 0x%x%08x %lf)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
1964 (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
1965 return BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1968 static const IPinVtbl AviMuxIn_PinVtbl = {
1969 AviMuxIn_QueryInterface,
1970 AviMuxIn_AddRef,
1971 AviMuxIn_Release,
1972 AviMuxIn_Connect,
1973 AviMuxIn_ReceiveConnection,
1974 AviMuxIn_Disconnect,
1975 AviMuxIn_ConnectedTo,
1976 AviMuxIn_ConnectionMediaType,
1977 AviMuxIn_QueryPinInfo,
1978 AviMuxIn_QueryDirection,
1979 AviMuxIn_QueryId,
1980 AviMuxIn_QueryAccept,
1981 AviMuxIn_EnumMediaTypes,
1982 AviMuxIn_QueryInternalConnections,
1983 AviMuxIn_EndOfStream,
1984 AviMuxIn_BeginFlush,
1985 AviMuxIn_EndFlush,
1986 AviMuxIn_NewSegment
1989 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface)
1991 return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface);
1994 static HRESULT WINAPI AviMuxIn_AMStreamControl_QueryInterface(
1995 IAMStreamControl *iface, REFIID riid, void **ppv)
1997 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1998 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2001 static ULONG WINAPI AviMuxIn_AMStreamControl_AddRef(IAMStreamControl *iface)
2003 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2004 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2005 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2008 static ULONG WINAPI AviMuxIn_AMStreamControl_Release(IAMStreamControl *iface)
2010 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2011 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2012 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2015 static HRESULT WINAPI AviMuxIn_AMStreamControl_StartAt(IAMStreamControl *iface,
2016 const REFERENCE_TIME *ptStart, DWORD dwCookie)
2018 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2019 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2020 FIXME("(%p:%s)->(%p %x)\n", This,
2021 debugstr_w(avimuxin->pin.pin.pinInfo.achName), ptStart, dwCookie);
2022 return E_NOTIMPL;
2025 static HRESULT WINAPI AviMuxIn_AMStreamControl_StopAt(IAMStreamControl *iface,
2026 const REFERENCE_TIME *ptStop, BOOL bSendExtra, DWORD dwCookie)
2028 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2029 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2030 FIXME("(%p:%s)->(%p %x %x)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2031 ptStop, bSendExtra, dwCookie);
2032 return E_NOTIMPL;
2035 static HRESULT WINAPI AviMuxIn_AMStreamControl_GetInfo(
2036 IAMStreamControl *iface, AM_STREAM_INFO *pInfo)
2038 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2039 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2040 FIXME("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pInfo);
2041 return E_NOTIMPL;
2044 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl = {
2045 AviMuxIn_AMStreamControl_QueryInterface,
2046 AviMuxIn_AMStreamControl_AddRef,
2047 AviMuxIn_AMStreamControl_Release,
2048 AviMuxIn_AMStreamControl_StartAt,
2049 AviMuxIn_AMStreamControl_StopAt,
2050 AviMuxIn_AMStreamControl_GetInfo
2053 static inline AviMuxIn* AviMuxIn_from_IMemInputPin(IMemInputPin *iface)
2055 BaseInputPin *bip = CONTAINING_RECORD(iface, BaseInputPin, IMemInputPin_iface);
2056 return CONTAINING_RECORD(bip, AviMuxIn, pin);
2059 static HRESULT WINAPI AviMuxIn_MemInputPin_QueryInterface(
2060 IMemInputPin *iface, REFIID riid, void **ppv)
2062 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2063 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2066 static ULONG WINAPI AviMuxIn_MemInputPin_AddRef(IMemInputPin *iface)
2068 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2069 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2070 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2073 static ULONG WINAPI AviMuxIn_MemInputPin_Release(IMemInputPin *iface)
2075 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2076 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2077 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2080 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocator(
2081 IMemInputPin *iface, IMemAllocator **ppAllocator)
2083 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2084 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2086 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), ppAllocator);
2088 if(!ppAllocator)
2089 return E_POINTER;
2091 IMemAllocator_AddRef(avimuxin->pin.pAllocator);
2092 *ppAllocator = avimuxin->pin.pAllocator;
2093 return S_OK;
2096 static HRESULT WINAPI AviMuxIn_MemInputPin_NotifyAllocator(
2097 IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly)
2099 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2100 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2101 ALLOCATOR_PROPERTIES props;
2102 HRESULT hr;
2104 TRACE("(%p:%s)->(%p %x)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2105 pAllocator, bReadOnly);
2107 if(!pAllocator)
2108 return E_POINTER;
2110 memset(&props, 0, sizeof(props));
2111 hr = IMemAllocator_GetProperties(pAllocator, &props);
2112 if(FAILED(hr))
2113 return hr;
2115 props.cbAlign = 1;
2116 props.cbPrefix = 8;
2117 return IMemAllocator_SetProperties(avimuxin->pin.pAllocator, &props, &props);
2120 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocatorRequirements(
2121 IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps)
2123 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2124 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2126 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pProps);
2128 if(!pProps)
2129 return E_POINTER;
2131 pProps->cbAlign = 1;
2132 pProps->cbPrefix = 8;
2133 return S_OK;
2136 static HRESULT WINAPI AviMuxIn_MemInputPin_Receive(
2137 IMemInputPin *iface, IMediaSample *pSample)
2139 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2140 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2142 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pSample);
2144 return avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSample);
2147 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin *iface,
2148 IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed)
2150 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2151 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2152 HRESULT hr = S_OK;
2154 TRACE("(%p:%s)->(%p %d %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2155 pSamples, nSamples, nSamplesProcessed);
2157 for(*nSamplesProcessed=0; *nSamplesProcessed<nSamples; (*nSamplesProcessed)++)
2159 hr = avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSamples[*nSamplesProcessed]);
2160 if(hr != S_OK)
2161 break;
2164 return hr;
2167 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin *iface)
2169 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2170 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2171 HRESULT hr;
2173 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
2175 if(!This->out->pin.pMemInputPin)
2176 return S_FALSE;
2178 hr = IMemInputPin_ReceiveCanBlock(This->out->pin.pMemInputPin);
2179 return hr != S_FALSE ? S_OK : S_FALSE;
2182 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl = {
2183 AviMuxIn_MemInputPin_QueryInterface,
2184 AviMuxIn_MemInputPin_AddRef,
2185 AviMuxIn_MemInputPin_Release,
2186 AviMuxIn_MemInputPin_GetAllocator,
2187 AviMuxIn_MemInputPin_NotifyAllocator,
2188 AviMuxIn_MemInputPin_GetAllocatorRequirements,
2189 AviMuxIn_MemInputPin_Receive,
2190 AviMuxIn_MemInputPin_ReceiveMultiple,
2191 AviMuxIn_MemInputPin_ReceiveCanBlock
2194 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface)
2196 return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface);
2199 static HRESULT WINAPI AviMuxIn_PropertyBag_QueryInterface(
2200 IPropertyBag *iface, REFIID riid, void **ppv)
2202 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2203 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2206 static ULONG WINAPI AviMuxIn_PropertyBag_AddRef(IPropertyBag *iface)
2208 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2209 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2210 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2213 static ULONG WINAPI AviMuxIn_PropertyBag_Release(IPropertyBag *iface)
2215 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2216 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2217 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2220 static HRESULT WINAPI AviMuxIn_PropertyBag_Read(IPropertyBag *iface,
2221 LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
2223 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2224 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2225 FIXME("(%p:%s)->(%s %p %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2226 debugstr_w(pszPropName), pVar, pErrorLog);
2227 return E_NOTIMPL;
2230 static HRESULT WINAPI AviMuxIn_PropertyBag_Write(IPropertyBag *iface,
2231 LPCOLESTR pszPropName, VARIANT *pVar)
2233 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2234 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2235 FIXME("(%p:%s)->(%s %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2236 debugstr_w(pszPropName), pVar);
2237 return E_NOTIMPL;
2240 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl = {
2241 AviMuxIn_PropertyBag_QueryInterface,
2242 AviMuxIn_PropertyBag_AddRef,
2243 AviMuxIn_PropertyBag_Release,
2244 AviMuxIn_PropertyBag_Read,
2245 AviMuxIn_PropertyBag_Write
2248 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface)
2250 return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface);
2253 static HRESULT WINAPI AviMuxIn_QualityControl_QueryInterface(
2254 IQualityControl *iface, REFIID riid, void **ppv)
2256 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2257 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2260 static ULONG WINAPI AviMuxIn_QualityControl_AddRef(IQualityControl *iface)
2262 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2263 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2264 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2267 static ULONG WINAPI AviMuxIn_QualityControl_Release(IQualityControl *iface)
2269 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2270 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2271 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2274 static HRESULT WINAPI AviMuxIn_QualityControl_Notify(IQualityControl *iface,
2275 IBaseFilter *pSelf, Quality q)
2277 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2278 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2279 FIXME("(%p:%s)->(%p { 0x%x %u %s %s })\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pSelf,
2280 q.Type, q.Proportion,
2281 wine_dbgstr_longlong(q.Late),
2282 wine_dbgstr_longlong(q.TimeStamp));
2283 return E_NOTIMPL;
2286 static HRESULT WINAPI AviMuxIn_QualityControl_SetSink(
2287 IQualityControl *iface, IQualityControl *piqc)
2289 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2290 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2291 FIXME("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), piqc);
2292 return E_NOTIMPL;
2295 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl = {
2296 AviMuxIn_QualityControl_QueryInterface,
2297 AviMuxIn_QualityControl_AddRef,
2298 AviMuxIn_QualityControl_Release,
2299 AviMuxIn_QualityControl_Notify,
2300 AviMuxIn_QualityControl_SetSink
2303 static HRESULT create_input_pin(AviMux *avimux)
2305 static const WCHAR name[] = {'I','n','p','u','t',' ','0','0',0};
2306 PIN_INFO info;
2307 HRESULT hr;
2309 if(avimux->input_pin_no >= MAX_PIN_NO-1)
2310 return E_FAIL;
2312 info.dir = PINDIR_INPUT;
2313 info.pFilter = &avimux->filter.IBaseFilter_iface;
2314 memcpy(info.achName, name, sizeof(name));
2315 info.achName[7] = '0' + (avimux->input_pin_no+1) % 10;
2316 info.achName[6] = '0' + (avimux->input_pin_no+1) / 10;
2318 hr = BaseInputPin_Construct(&AviMuxIn_PinVtbl, sizeof(AviMuxIn), &info,
2319 &AviMuxIn_BaseInputFuncTable, &avimux->filter.csFilter, NULL, (IPin**)&avimux->in[avimux->input_pin_no]);
2320 if(FAILED(hr))
2321 return hr;
2322 avimux->in[avimux->input_pin_no]->pin.IMemInputPin_iface.lpVtbl = &AviMuxIn_MemInputPinVtbl;
2323 avimux->in[avimux->input_pin_no]->IAMStreamControl_iface.lpVtbl = &AviMuxIn_AMStreamControlVtbl;
2324 avimux->in[avimux->input_pin_no]->IPropertyBag_iface.lpVtbl = &AviMuxIn_PropertyBagVtbl;
2325 avimux->in[avimux->input_pin_no]->IQualityControl_iface.lpVtbl = &AviMuxIn_QualityControlVtbl;
2327 avimux->in[avimux->input_pin_no]->samples_head = NULL;
2328 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
2329 &IID_IMemAllocator, (void**)&avimux->in[avimux->input_pin_no]->samples_allocator);
2330 if(FAILED(hr)) {
2331 BaseInputPinImpl_Release(&avimux->in[avimux->input_pin_no]->pin.pin.IPin_iface);
2332 return hr;
2335 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
2336 &IID_IMemAllocator, (void**)&avimux->in[avimux->input_pin_no]->pin.pAllocator);
2337 if(FAILED(hr)) {
2338 IMemAllocator_Release(avimux->in[avimux->input_pin_no]->samples_allocator);
2339 BaseInputPinImpl_Release(&avimux->in[avimux->input_pin_no]->pin.pin.IPin_iface);
2340 return hr;
2343 avimux->in[avimux->input_pin_no]->stream_time = 0;
2344 memset(&avimux->in[avimux->input_pin_no]->strh, 0, sizeof(avimux->in[avimux->input_pin_no]->strh));
2345 avimux->in[avimux->input_pin_no]->strf = NULL;
2346 memset(&avimux->in[avimux->input_pin_no]->indx_data, 0, sizeof(avimux->in[avimux->input_pin_no]->indx_data));
2347 memset(&avimux->in[avimux->input_pin_no]->ix_data, 0, sizeof(avimux->in[avimux->input_pin_no]->ix_data));
2348 avimux->in[avimux->input_pin_no]->indx = (AVISUPERINDEX*)&avimux->in[avimux->input_pin_no]->indx_data;
2349 avimux->in[avimux->input_pin_no]->ix = (AVISTDINDEX*)avimux->in[avimux->input_pin_no]->ix_data;
2351 avimux->input_pin_no++;
2352 return S_OK;
2355 IUnknown* WINAPI QCAP_createAVIMux(IUnknown *pUnkOuter, HRESULT *phr)
2357 static const WCHAR output_name[] = {'A','V','I',' ','O','u','t',0};
2359 AviMux *avimux;
2360 PIN_INFO info;
2361 HRESULT hr;
2363 TRACE("(%p)\n", pUnkOuter);
2365 if(pUnkOuter) {
2366 *phr = CLASS_E_NOAGGREGATION;
2367 return NULL;
2370 avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux));
2371 if(!avimux) {
2372 *phr = E_OUTOFMEMORY;
2373 return NULL;
2376 BaseFilter_Init(&avimux->filter, &AviMuxVtbl, &CLSID_AviDest,
2377 (DWORD_PTR)(__FILE__ ": AviMux.csFilter"), &filter_func_table);
2378 avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl;
2379 avimux->IConfigInterleaving_iface.lpVtbl = &ConfigInterleavingVtbl;
2380 avimux->IMediaSeeking_iface.lpVtbl = &MediaSeekingVtbl;
2381 avimux->IPersistMediaPropertyBag_iface.lpVtbl = &PersistMediaPropertyBagVtbl;
2382 avimux->ISpecifyPropertyPages_iface.lpVtbl = &SpecifyPropertyPagesVtbl;
2384 info.dir = PINDIR_OUTPUT;
2385 info.pFilter = &avimux->filter.IBaseFilter_iface;
2386 lstrcpyW(info.achName, output_name);
2387 hr = BaseOutputPin_Construct(&AviMuxOut_PinVtbl, sizeof(AviMuxOut), &info,
2388 &AviMuxOut_BaseOutputFuncTable, &avimux->filter.csFilter, (IPin**)&avimux->out);
2389 if(FAILED(hr)) {
2390 BaseFilterImpl_Release(&avimux->filter.IBaseFilter_iface);
2391 HeapFree(GetProcessHeap(), 0, avimux);
2392 *phr = hr;
2393 return NULL;
2395 avimux->out->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl;
2396 avimux->out->cur_stream = 0;
2397 avimux->out->cur_time = 0;
2398 avimux->out->stream = NULL;
2400 hr = create_input_pin(avimux);
2401 if(FAILED(hr)) {
2402 BaseOutputPinImpl_Release(&avimux->out->pin.pin.IPin_iface);
2403 BaseFilterImpl_Release(&avimux->filter.IBaseFilter_iface);
2404 HeapFree(GetProcessHeap(), 0, avimux);
2405 *phr = hr;
2406 return NULL;
2409 avimux->interleave = 10000000;
2411 ObjectRefCount(TRUE);
2412 *phr = S_OK;
2413 return (IUnknown*)&avimux->filter.IBaseFilter_iface;