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