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