xref: /reactos/dll/directx/wine/qcap/avimux.c (revision 56aa5137)
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 
impl_from_BaseFilter(BaseFilter * filter)122 static inline AviMux* impl_from_BaseFilter(BaseFilter *filter)
123 {
124     return CONTAINING_RECORD(filter, AviMux, filter);
125 }
126 
AviMux_GetPin(BaseFilter * iface,int pos)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 
AviMux_GetPinCount(BaseFilter * iface)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 
impl_from_IBaseFilter(IBaseFilter * iface)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 
AviMux_QueryInterface(IBaseFilter * iface,REFIID riid,void ** ppv)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 
AviMux_Release(IBaseFilter * iface)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 
out_flush(AviMux * This)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 
out_seek(AviMux * This,int pos)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 
out_write(AviMux * This,const void * data,int size)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 
idx1_add_entry(AviMux * avimux,DWORD ckid,DWORD flags,DWORD off,DWORD len)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 
flush_queue(AviMux * avimux,AviMuxIn * avimuxin,BOOL closing)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 
queue_sample(AviMux * avimux,AviMuxIn * avimuxin,IMediaSample * sample)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 
AviMux_Stop(IBaseFilter * iface)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 
AviMux_Pause(IBaseFilter * iface)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 
AviMux_Run(IBaseFilter * iface,REFERENCE_TIME tStart)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 
AviMux_EnumPins(IBaseFilter * iface,IEnumPins ** ppEnum)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 
AviMux_FindPin(IBaseFilter * iface,LPCWSTR Id,IPin ** ppPin)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 
AviMux_QueryFilterInfo(IBaseFilter * iface,FILTER_INFO * pInfo)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 
AviMux_QueryVendorInfo(IBaseFilter * iface,LPWSTR * pVendorInfo)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 
impl_from_IConfigAviMux(IConfigAviMux * iface)798 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface)
799 {
800     return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface);
801 }
802 
ConfigAviMux_QueryInterface(IConfigAviMux * iface,REFIID riid,void ** ppv)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 
ConfigAviMux_AddRef(IConfigAviMux * iface)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 
ConfigAviMux_Release(IConfigAviMux * iface)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 
ConfigAviMux_SetMasterStream(IConfigAviMux * iface,LONG iStream)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 
ConfigAviMux_GetMasterStream(IConfigAviMux * iface,LONG * pStream)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 
ConfigAviMux_SetOutputCompatibilityIndex(IConfigAviMux * iface,BOOL fOldIndex)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 
ConfigAviMux_GetOutputCompatibilityIndex(IConfigAviMux * iface,BOOL * pfOldIndex)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 
impl_from_IConfigInterleaving(IConfigInterleaving * iface)862 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface)
863 {
864     return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface);
865 }
866 
ConfigInterleaving_QueryInterface(IConfigInterleaving * iface,REFIID riid,void ** ppv)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 
ConfigInterleaving_AddRef(IConfigInterleaving * iface)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 
ConfigInterleaving_Release(IConfigInterleaving * iface)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 
ConfigInterleaving_put_Mode(IConfigInterleaving * iface,InterleavingMode mode)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 
ConfigInterleaving_get_Mode(IConfigInterleaving * iface,InterleavingMode * pMode)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 
ConfigInterleaving_put_Interleaving(IConfigInterleaving * iface,const REFERENCE_TIME * prtInterleave,const REFERENCE_TIME * prtPreroll)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 
ConfigInterleaving_get_Interleaving(IConfigInterleaving * iface,REFERENCE_TIME * prtInterleave,REFERENCE_TIME * prtPreroll)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 
impl_from_IMediaSeeking(IMediaSeeking * iface)950 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface)
951 {
952     return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface);
953 }
954 
MediaSeeking_QueryInterface(IMediaSeeking * iface,REFIID riid,void ** ppv)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 
MediaSeeking_AddRef(IMediaSeeking * iface)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 
MediaSeeking_Release(IMediaSeeking * iface)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 
MediaSeeking_GetCapabilities(IMediaSeeking * iface,DWORD * pCapabilities)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 
MediaSeeking_CheckCapabilities(IMediaSeeking * iface,DWORD * pCapabilities)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 
MediaSeeking_IsFormatSupported(IMediaSeeking * iface,const GUID * pFormat)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 
MediaSeeking_QueryPreferredFormat(IMediaSeeking * iface,GUID * pFormat)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 
MediaSeeking_GetTimeFormat(IMediaSeeking * iface,GUID * pFormat)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 
MediaSeeking_IsUsingTimeFormat(IMediaSeeking * iface,const GUID * pFormat)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 
MediaSeeking_SetTimeFormat(IMediaSeeking * iface,const GUID * pFormat)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 
MediaSeeking_GetDuration(IMediaSeeking * iface,LONGLONG * pDuration)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 
MediaSeeking_GetStopPosition(IMediaSeeking * iface,LONGLONG * pStop)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 
MediaSeeking_GetCurrentPosition(IMediaSeeking * iface,LONGLONG * pCurrent)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 
MediaSeeking_ConvertTimeFormat(IMediaSeeking * iface,LONGLONG * pTarget,const GUID * pTargetFormat,LONGLONG Source,const GUID * pSourceFormat)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 
MediaSeeking_SetPositions(IMediaSeeking * iface,LONGLONG * pCurrent,DWORD dwCurrentFlags,LONGLONG * pStop,DWORD dwStopFlags)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 
MediaSeeking_GetPositions(IMediaSeeking * iface,LONGLONG * pCurrent,LONGLONG * pStop)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 
MediaSeeking_GetAvailable(IMediaSeeking * iface,LONGLONG * pEarliest,LONGLONG * pLatest)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 
MediaSeeking_SetRate(IMediaSeeking * iface,double dRate)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 
MediaSeeking_GetRate(IMediaSeeking * iface,double * pdRate)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 
MediaSeeking_GetPreroll(IMediaSeeking * iface,LONGLONG * pllPreroll)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 
impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag * iface)1131 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface)
1132 {
1133     return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface);
1134 }
1135 
PersistMediaPropertyBag_QueryInterface(IPersistMediaPropertyBag * iface,REFIID riid,void ** ppv)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 
PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag * iface)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 
PersistMediaPropertyBag_Release(IPersistMediaPropertyBag * iface)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 
PersistMediaPropertyBag_GetClassID(IPersistMediaPropertyBag * iface,CLSID * pClassID)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 
PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag * iface)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 
PersistMediaPropertyBag_Load(IPersistMediaPropertyBag * iface,IMediaPropertyBag * pPropBag,IErrorLog * pErrorLog)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 
PersistMediaPropertyBag_Save(IPersistMediaPropertyBag * iface,IMediaPropertyBag * pPropBag,BOOL fClearDirty,BOOL fSaveAllProperties)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 
impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages * iface)1195 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface)
1196 {
1197     return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface);
1198 }
1199 
SpecifyPropertyPages_QueryInterface(ISpecifyPropertyPages * iface,REFIID riid,void ** ppv)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 
SpecifyPropertyPages_AddRef(ISpecifyPropertyPages * iface)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 
SpecifyPropertyPages_Release(ISpecifyPropertyPages * iface)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 
SpecifyPropertyPages_GetPages(ISpecifyPropertyPages * iface,CAUUID * pPages)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 
AviMuxOut_AttemptConnection(BasePin * base,IPin * pReceivePin,const AM_MEDIA_TYPE * pmt)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 
AviMuxOut_GetMediaTypeVersion(BasePin * base)1250 static LONG WINAPI AviMuxOut_GetMediaTypeVersion(BasePin *base)
1251 {
1252     return 0;
1253 }
1254 
AviMuxOut_GetMediaType(BasePin * base,int iPosition,AM_MEDIA_TYPE * amt)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 
AviMuxOut_DecideAllocator(BaseOutputPin * base,IMemInputPin * pPin,IMemAllocator ** pAlloc)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 
AviMuxOut_BreakConnect(BaseOutputPin * base)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 
impl_from_out_IPin(IPin * iface)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 
AviMuxOut_QueryInterface(IPin * iface,REFIID riid,void ** ppv)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 
AviMuxOut_AddRef(IPin * iface)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 
AviMuxOut_Release(IPin * iface)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 
AviMuxOut_Connect(IPin * iface,IPin * pReceivePin,const AM_MEDIA_TYPE * pmt)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 
AviMuxOut_ReceiveConnection(IPin * iface,IPin * pConnector,const AM_MEDIA_TYPE * pmt)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 
AviMuxOut_Disconnect(IPin * iface)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 
AviMuxOut_ConnectedTo(IPin * iface,IPin ** pPin)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 
AviMuxOut_ConnectionMediaType(IPin * iface,AM_MEDIA_TYPE * pmt)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 
AviMuxOut_QueryPinInfo(IPin * iface,PIN_INFO * pInfo)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 
AviMuxOut_QueryDirection(IPin * iface,PIN_DIRECTION * pPinDir)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 
AviMuxOut_QueryId(IPin * iface,LPWSTR * Id)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 
AviMuxOut_QueryAccept(IPin * iface,const AM_MEDIA_TYPE * pmt)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 
AviMuxOut_EnumMediaTypes(IPin * iface,IEnumMediaTypes ** ppEnum)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 
AviMuxOut_QueryInternalConnections(IPin * iface,IPin ** apPin,ULONG * nPin)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 
AviMuxOut_EndOfStream(IPin * iface)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 
AviMuxOut_BeginFlush(IPin * iface)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 
AviMuxOut_EndFlush(IPin * iface)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 
AviMuxOut_NewSegment(IPin * iface,REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate)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 
impl_from_out_IQualityControl(IQualityControl * iface)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 
AviMuxOut_QualityControl_QueryInterface(IQualityControl * iface,REFIID riid,void ** ppv)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 
AviMuxOut_QualityControl_AddRef(IQualityControl * iface)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 
AviMuxOut_QualityControl_Release(IQualityControl * iface)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 
AviMuxOut_QualityControl_Notify(IQualityControl * iface,IBaseFilter * pSelf,Quality q)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 
AviMuxOut_QualityControl_SetSink(IQualityControl * iface,IQualityControl * piqc)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 
AviMuxIn_CheckMediaType(BasePin * base,const AM_MEDIA_TYPE * pmt)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 
AviMuxIn_GetMediaTypeVersion(BasePin * base)1590 static LONG WINAPI AviMuxIn_GetMediaTypeVersion(BasePin *base)
1591 {
1592     return 0;
1593 }
1594 
AviMuxIn_GetMediaType(BasePin * base,int iPosition,AM_MEDIA_TYPE * amt)1595 static HRESULT WINAPI AviMuxIn_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
1596 {
1597     return S_FALSE;
1598 }
1599 
AviMuxIn_Receive(BaseInputPin * base,IMediaSample * pSample)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 
impl_from_in_IPin(IPin * iface)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 
AviMuxIn_from_IPin(IPin * iface)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 
AviMuxIn_QueryInterface(IPin * iface,REFIID riid,void ** ppv)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 
AviMuxIn_AddRef(IPin * iface)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 
AviMuxIn_Release(IPin * iface)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 
AviMuxIn_Connect(IPin * iface,IPin * pReceivePin,const AM_MEDIA_TYPE * pmt)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 
AviMuxIn_ReceiveConnection(IPin * iface,IPin * pConnector,const AM_MEDIA_TYPE * pmt)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 
AviMuxIn_Disconnect(IPin * iface)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 
AviMuxIn_ConnectedTo(IPin * iface,IPin ** pPin)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 
AviMuxIn_ConnectionMediaType(IPin * iface,AM_MEDIA_TYPE * pmt)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 
AviMuxIn_QueryPinInfo(IPin * iface,PIN_INFO * pInfo)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 
AviMuxIn_QueryDirection(IPin * iface,PIN_DIRECTION * pPinDir)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 
AviMuxIn_QueryId(IPin * iface,LPWSTR * Id)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 
AviMuxIn_QueryAccept(IPin * iface,const AM_MEDIA_TYPE * pmt)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 
AviMuxIn_EnumMediaTypes(IPin * iface,IEnumMediaTypes ** ppEnum)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 
AviMuxIn_QueryInternalConnections(IPin * iface,IPin ** apPin,ULONG * nPin)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 
AviMuxIn_EndOfStream(IPin * iface)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 
AviMuxIn_BeginFlush(IPin * iface)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 
AviMuxIn_EndFlush(IPin * iface)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 
AviMuxIn_NewSegment(IPin * iface,REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate)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 
AviMuxIn_from_IAMStreamControl(IAMStreamControl * iface)1996 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface)
1997 {
1998     return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface);
1999 }
2000 
AviMuxIn_AMStreamControl_QueryInterface(IAMStreamControl * iface,REFIID riid,void ** ppv)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 
AviMuxIn_AMStreamControl_AddRef(IAMStreamControl * iface)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 
AviMuxIn_AMStreamControl_Release(IAMStreamControl * iface)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 
AviMuxIn_AMStreamControl_StartAt(IAMStreamControl * iface,const REFERENCE_TIME * ptStart,DWORD dwCookie)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 
AviMuxIn_AMStreamControl_StopAt(IAMStreamControl * iface,const REFERENCE_TIME * ptStop,BOOL bSendExtra,DWORD dwCookie)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 
AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl * iface,AM_STREAM_INFO * pInfo)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 
AviMuxIn_from_IMemInputPin(IMemInputPin * iface)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 
AviMuxIn_MemInputPin_QueryInterface(IMemInputPin * iface,REFIID riid,void ** ppv)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 
AviMuxIn_MemInputPin_AddRef(IMemInputPin * iface)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 
AviMuxIn_MemInputPin_Release(IMemInputPin * iface)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 
AviMuxIn_MemInputPin_GetAllocator(IMemInputPin * iface,IMemAllocator ** ppAllocator)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 
AviMuxIn_MemInputPin_NotifyAllocator(IMemInputPin * iface,IMemAllocator * pAllocator,BOOL bReadOnly)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 
AviMuxIn_MemInputPin_GetAllocatorRequirements(IMemInputPin * iface,ALLOCATOR_PROPERTIES * pProps)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 
AviMuxIn_MemInputPin_Receive(IMemInputPin * iface,IMediaSample * pSample)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 
AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin * iface,IMediaSample ** pSamples,LONG nSamples,LONG * nSamplesProcessed)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 
AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin * iface)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 
AviMuxIn_from_IPropertyBag(IPropertyBag * iface)2201 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface)
2202 {
2203     return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface);
2204 }
2205 
AviMuxIn_PropertyBag_QueryInterface(IPropertyBag * iface,REFIID riid,void ** ppv)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 
AviMuxIn_PropertyBag_AddRef(IPropertyBag * iface)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 
AviMuxIn_PropertyBag_Release(IPropertyBag * iface)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 
AviMuxIn_PropertyBag_Read(IPropertyBag * iface,LPCOLESTR pszPropName,VARIANT * pVar,IErrorLog * pErrorLog)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 
AviMuxIn_PropertyBag_Write(IPropertyBag * iface,LPCOLESTR pszPropName,VARIANT * pVar)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 
AviMuxIn_from_IQualityControl(IQualityControl * iface)2255 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface)
2256 {
2257     return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface);
2258 }
2259 
AviMuxIn_QualityControl_QueryInterface(IQualityControl * iface,REFIID riid,void ** ppv)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 
AviMuxIn_QualityControl_AddRef(IQualityControl * iface)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 
AviMuxIn_QualityControl_Release(IQualityControl * iface)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 
AviMuxIn_QualityControl_Notify(IQualityControl * iface,IBaseFilter * pSelf,Quality q)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 
AviMuxIn_QualityControl_SetSink(IQualityControl * iface,IQualityControl * piqc)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 
create_input_pin(AviMux * avimux)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 
QCAP_createAVIMux(IUnknown * pUnkOuter,HRESULT * phr)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