opcservices: Implement IOpcPartEnumerator.
[wine.git] / dlls / qcap / avimux.c
blob427b019ec64e9fe7d2067fbda2deabbeb0f417b5
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)->(%s)\n", This, wine_dbgstr_longlong(tStart));
605 if(This->filter.state == State_Running)
606 return S_OK;
608 if(This->mode != INTERLEAVE_FULL) {
609 FIXME("mode not supported (%d)\n", This->mode);
610 return E_NOTIMPL;
613 if(tStart)
614 FIXME("tStart parameter ignored\n");
616 for(i=0; i<This->input_pin_no; i++) {
617 IMediaSeeking *ms;
618 LONGLONG cur, stop;
620 if(!This->in[i]->pin.pin.pConnectedTo)
621 continue;
623 hr = IPin_QueryInterface(This->in[i]->pin.pin.pConnectedTo,
624 &IID_IMediaSeeking, (void**)&ms);
625 if(FAILED(hr))
626 continue;
628 hr = IMediaSeeking_GetPositions(ms, &cur, &stop);
629 if(FAILED(hr)) {
630 IMediaSeeking_Release(ms);
631 continue;
634 FIXME("Use IMediaSeeking to fill stream header\n");
635 IMediaSeeking_Release(ms);
638 if(This->out->pin.pMemInputPin) {
639 hr = IMemInputPin_QueryInterface(This->out->pin.pMemInputPin,
640 &IID_IStream, (void**)&This->out->stream);
641 if(FAILED(hr))
642 return hr;
645 This->idx1_entries = 0;
646 if(!This->idx1_size) {
647 This->idx1_size = 1024;
648 This->idx1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->idx1)*This->idx1_size);
649 if(!This->idx1)
650 return E_OUTOFMEMORY;
653 This->out->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER);
654 This->start = -1;
655 This->stop = -1;
656 memset(&This->avih, 0, sizeof(This->avih));
657 for(i=0; i<This->input_pin_no; i++) {
658 if(!This->in[i]->pin.pin.pConnectedTo)
659 continue;
661 This->avih.dwStreams++;
662 This->out->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK)
663 + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
665 This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000);
666 This->in[i]->strh.dwRate = This->interleave;
668 hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator);
669 if(FAILED(hr)) {
670 if(This->out->stream) {
671 IStream_Release(This->out->stream);
672 This->out->stream = NULL;
674 return hr;
678 This->out->movi_off = This->out->size;
679 This->out->size += sizeof(RIFFLIST);
681 idx1_add_entry(This, FCC('7','F','x','x'), 0, This->out->movi_off+sizeof(RIFFLIST), 0);
683 stream_id = 0;
684 for(i=0; i<This->input_pin_no; i++) {
685 if(!This->in[i]->pin.pin.pConnectedTo)
686 continue;
688 This->in[i]->ix_off = This->out->size;
689 This->out->size += sizeof(This->in[i]->ix_data);
690 This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10);
691 This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK);
692 This->in[i]->ix->wLongsPerEntry = 2;
693 This->in[i]->ix->bIndexSubType = 0;
694 This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS;
695 This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b');
696 This->in[i]->ix->qwBaseOffset = 0;
698 This->in[i]->indx->fcc = ckidAVISUPERINDEX;
699 This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK);
700 This->in[i]->indx->wLongsPerEntry = 4;
701 This->in[i]->indx->bIndexSubType = 0;
702 This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES;
703 This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId;
704 This->in[i]->stream_id = stream_id++;
707 This->out->buf_pos = 0;
708 This->out->out_pos = 0;
710 This->avih.fcc = ckidMAINAVIHEADER;
711 This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK);
712 /* TODO: Use first video stream */
713 This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10;
714 This->avih.dwPaddingGranularity = 1;
715 This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX;
716 This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth;
717 This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight;
719 This->filter.state = State_Running;
720 return S_OK;
723 static HRESULT WINAPI AviMux_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
725 AviMux *This = impl_from_IBaseFilter(iface);
726 TRACE("(%p)->(%p)\n", This, ppEnum);
727 return BaseFilterImpl_EnumPins(iface, ppEnum);
730 static HRESULT WINAPI AviMux_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
732 AviMux *This = impl_from_IBaseFilter(iface);
733 int i;
735 TRACE("(%p)->(%s %p)\n", This, debugstr_w(Id), ppPin);
737 if(!Id || !ppPin)
738 return E_POINTER;
740 if(!lstrcmpiW(Id, This->out->pin.pin.pinInfo.achName)) {
741 IPin_AddRef(&This->out->pin.pin.IPin_iface);
742 *ppPin = &This->out->pin.pin.IPin_iface;
743 return S_OK;
746 for(i=0; i<This->input_pin_no; i++) {
747 if(lstrcmpiW(Id, This->in[i]->pin.pin.pinInfo.achName))
748 continue;
750 IPin_AddRef(&This->in[i]->pin.pin.IPin_iface);
751 *ppPin = &This->in[i]->pin.pin.IPin_iface;
752 return S_OK;
755 return VFW_E_NOT_FOUND;
758 static HRESULT WINAPI AviMux_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo)
760 AviMux *This = impl_from_IBaseFilter(iface);
761 FIXME("(%p)->(%p)\n", This, pInfo);
762 return E_NOTIMPL;
765 static HRESULT WINAPI AviMux_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo)
767 AviMux *This = impl_from_IBaseFilter(iface);
768 FIXME("(%p)->(%p)\n", This, pVendorInfo);
769 return E_NOTIMPL;
772 static const IBaseFilterVtbl AviMuxVtbl = {
773 AviMux_QueryInterface,
774 BaseFilterImpl_AddRef,
775 AviMux_Release,
776 BaseFilterImpl_GetClassID,
777 AviMux_Stop,
778 AviMux_Pause,
779 AviMux_Run,
780 BaseFilterImpl_GetState,
781 BaseFilterImpl_SetSyncSource,
782 BaseFilterImpl_GetSyncSource,
783 AviMux_EnumPins,
784 AviMux_FindPin,
785 AviMux_QueryFilterInfo,
786 BaseFilterImpl_JoinFilterGraph,
787 AviMux_QueryVendorInfo
790 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface)
792 return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface);
795 static HRESULT WINAPI ConfigAviMux_QueryInterface(
796 IConfigAviMux *iface, REFIID riid, void **ppv)
798 AviMux *This = impl_from_IConfigAviMux(iface);
799 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
802 static ULONG WINAPI ConfigAviMux_AddRef(IConfigAviMux *iface)
804 AviMux *This = impl_from_IConfigAviMux(iface);
805 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
808 static ULONG WINAPI ConfigAviMux_Release(IConfigAviMux *iface)
810 AviMux *This = impl_from_IConfigAviMux(iface);
811 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
814 static HRESULT WINAPI ConfigAviMux_SetMasterStream(IConfigAviMux *iface, LONG iStream)
816 AviMux *This = impl_from_IConfigAviMux(iface);
817 FIXME("(%p)->(%d)\n", This, iStream);
818 return E_NOTIMPL;
821 static HRESULT WINAPI ConfigAviMux_GetMasterStream(IConfigAviMux *iface, LONG *pStream)
823 AviMux *This = impl_from_IConfigAviMux(iface);
824 FIXME("(%p)->(%p)\n", This, pStream);
825 return E_NOTIMPL;
828 static HRESULT WINAPI ConfigAviMux_SetOutputCompatibilityIndex(
829 IConfigAviMux *iface, BOOL fOldIndex)
831 AviMux *This = impl_from_IConfigAviMux(iface);
832 FIXME("(%p)->(%x)\n", This, fOldIndex);
833 return E_NOTIMPL;
836 static HRESULT WINAPI ConfigAviMux_GetOutputCompatibilityIndex(
837 IConfigAviMux *iface, BOOL *pfOldIndex)
839 AviMux *This = impl_from_IConfigAviMux(iface);
840 FIXME("(%p)->(%p)\n", This, pfOldIndex);
841 return E_NOTIMPL;
844 static const IConfigAviMuxVtbl ConfigAviMuxVtbl = {
845 ConfigAviMux_QueryInterface,
846 ConfigAviMux_AddRef,
847 ConfigAviMux_Release,
848 ConfigAviMux_SetMasterStream,
849 ConfigAviMux_GetMasterStream,
850 ConfigAviMux_SetOutputCompatibilityIndex,
851 ConfigAviMux_GetOutputCompatibilityIndex
854 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface)
856 return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface);
859 static HRESULT WINAPI ConfigInterleaving_QueryInterface(
860 IConfigInterleaving *iface, REFIID riid, void **ppv)
862 AviMux *This = impl_from_IConfigInterleaving(iface);
863 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
866 static ULONG WINAPI ConfigInterleaving_AddRef(IConfigInterleaving *iface)
868 AviMux *This = impl_from_IConfigInterleaving(iface);
869 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
872 static ULONG WINAPI ConfigInterleaving_Release(IConfigInterleaving *iface)
874 AviMux *This = impl_from_IConfigInterleaving(iface);
875 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
878 static HRESULT WINAPI ConfigInterleaving_put_Mode(
879 IConfigInterleaving *iface, InterleavingMode mode)
881 AviMux *This = impl_from_IConfigInterleaving(iface);
883 TRACE("(%p)->(%d)\n", This, mode);
885 if(mode>INTERLEAVE_NONE_BUFFERED)
886 return E_INVALIDARG;
888 if(This->mode != mode) {
889 if(This->out->pin.pin.pConnectedTo) {
890 HRESULT hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph,
891 &This->out->pin.pin.IPin_iface);
892 if(FAILED(hr))
893 return hr;
896 This->mode = mode;
899 return S_OK;
902 static HRESULT WINAPI ConfigInterleaving_get_Mode(
903 IConfigInterleaving *iface, InterleavingMode *pMode)
905 AviMux *This = impl_from_IConfigInterleaving(iface);
906 FIXME("(%p)->(%p)\n", This, pMode);
907 return E_NOTIMPL;
910 static HRESULT WINAPI ConfigInterleaving_put_Interleaving(IConfigInterleaving *iface,
911 const REFERENCE_TIME *prtInterleave, const REFERENCE_TIME *prtPreroll)
913 AviMux *This = impl_from_IConfigInterleaving(iface);
915 TRACE("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
917 if(prtInterleave)
918 This->interleave = *prtInterleave;
919 if(prtPreroll)
920 This->preroll = *prtPreroll;
921 return S_OK;
924 static HRESULT WINAPI ConfigInterleaving_get_Interleaving(IConfigInterleaving *iface,
925 REFERENCE_TIME *prtInterleave, REFERENCE_TIME *prtPreroll)
927 AviMux *This = impl_from_IConfigInterleaving(iface);
928 FIXME("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
929 return E_NOTIMPL;
932 static const IConfigInterleavingVtbl ConfigInterleavingVtbl = {
933 ConfigInterleaving_QueryInterface,
934 ConfigInterleaving_AddRef,
935 ConfigInterleaving_Release,
936 ConfigInterleaving_put_Mode,
937 ConfigInterleaving_get_Mode,
938 ConfigInterleaving_put_Interleaving,
939 ConfigInterleaving_get_Interleaving
942 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface)
944 return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface);
947 static HRESULT WINAPI MediaSeeking_QueryInterface(
948 IMediaSeeking *iface, REFIID riid, void **ppv)
950 AviMux *This = impl_from_IMediaSeeking(iface);
951 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
954 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
956 AviMux *This = impl_from_IMediaSeeking(iface);
957 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
960 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
962 AviMux *This = impl_from_IMediaSeeking(iface);
963 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
966 static HRESULT WINAPI MediaSeeking_GetCapabilities(
967 IMediaSeeking *iface, DWORD *pCapabilities)
969 AviMux *This = impl_from_IMediaSeeking(iface);
970 FIXME("(%p)->(%p)\n", This, pCapabilities);
971 return E_NOTIMPL;
974 static HRESULT WINAPI MediaSeeking_CheckCapabilities(
975 IMediaSeeking *iface, DWORD *pCapabilities)
977 AviMux *This = impl_from_IMediaSeeking(iface);
978 FIXME("(%p)->(%p)\n", This, pCapabilities);
979 return E_NOTIMPL;
982 static HRESULT WINAPI MediaSeeking_IsFormatSupported(
983 IMediaSeeking *iface, const GUID *pFormat)
985 AviMux *This = impl_from_IMediaSeeking(iface);
986 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
987 return E_NOTIMPL;
990 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(
991 IMediaSeeking *iface, GUID *pFormat)
993 AviMux *This = impl_from_IMediaSeeking(iface);
994 FIXME("(%p)->(%p)\n", This, pFormat);
995 return E_NOTIMPL;
998 static HRESULT WINAPI MediaSeeking_GetTimeFormat(
999 IMediaSeeking *iface, GUID *pFormat)
1001 AviMux *This = impl_from_IMediaSeeking(iface);
1002 FIXME("(%p)->(%p)\n", This, pFormat);
1003 return E_NOTIMPL;
1006 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(
1007 IMediaSeeking *iface, const GUID *pFormat)
1009 AviMux *This = impl_from_IMediaSeeking(iface);
1010 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
1011 return E_NOTIMPL;
1014 static HRESULT WINAPI MediaSeeking_SetTimeFormat(
1015 IMediaSeeking *iface, const GUID *pFormat)
1017 AviMux *This = impl_from_IMediaSeeking(iface);
1018 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
1019 return E_NOTIMPL;
1022 static HRESULT WINAPI MediaSeeking_GetDuration(
1023 IMediaSeeking *iface, LONGLONG *pDuration)
1025 AviMux *This = impl_from_IMediaSeeking(iface);
1026 FIXME("(%p)->(%p)\n", This, pDuration);
1027 return E_NOTIMPL;
1030 static HRESULT WINAPI MediaSeeking_GetStopPosition(
1031 IMediaSeeking *iface, LONGLONG *pStop)
1033 AviMux *This = impl_from_IMediaSeeking(iface);
1034 FIXME("(%p)->(%p)\n", This, pStop);
1035 return E_NOTIMPL;
1038 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(
1039 IMediaSeeking *iface, LONGLONG *pCurrent)
1041 AviMux *This = impl_from_IMediaSeeking(iface);
1042 FIXME("(%p)->(%p)\n", This, pCurrent);
1043 return E_NOTIMPL;
1046 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
1047 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
1049 AviMux *This = impl_from_IMediaSeeking(iface);
1050 FIXME("(%p)->(%p %s %s %s)\n", This, pTarget, debugstr_guid(pTargetFormat),
1051 wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
1052 return E_NOTIMPL;
1055 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
1056 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
1058 AviMux *This = impl_from_IMediaSeeking(iface);
1059 FIXME("(%p)->(%p %x %p %x)\n", This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
1060 return E_NOTIMPL;
1063 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
1064 LONGLONG *pCurrent, LONGLONG *pStop)
1066 AviMux *This = impl_from_IMediaSeeking(iface);
1067 FIXME("(%p)->(%p %p)\n", This, pCurrent, pStop);
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
1072 LONGLONG *pEarliest, LONGLONG *pLatest)
1074 AviMux *This = impl_from_IMediaSeeking(iface);
1075 FIXME("(%p)->(%p %p)\n", This, pEarliest, pLatest);
1076 return E_NOTIMPL;
1079 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
1081 AviMux *This = impl_from_IMediaSeeking(iface);
1082 FIXME("(%p)->(%lf)\n", This, dRate);
1083 return E_NOTIMPL;
1086 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
1088 AviMux *This = impl_from_IMediaSeeking(iface);
1089 FIXME("(%p)->(%p)\n", This, pdRate);
1090 return E_NOTIMPL;
1093 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
1095 AviMux *This = impl_from_IMediaSeeking(iface);
1096 FIXME("(%p)->(%p)\n", This, pllPreroll);
1097 return E_NOTIMPL;
1100 static const IMediaSeekingVtbl MediaSeekingVtbl = {
1101 MediaSeeking_QueryInterface,
1102 MediaSeeking_AddRef,
1103 MediaSeeking_Release,
1104 MediaSeeking_GetCapabilities,
1105 MediaSeeking_CheckCapabilities,
1106 MediaSeeking_IsFormatSupported,
1107 MediaSeeking_QueryPreferredFormat,
1108 MediaSeeking_GetTimeFormat,
1109 MediaSeeking_IsUsingTimeFormat,
1110 MediaSeeking_SetTimeFormat,
1111 MediaSeeking_GetDuration,
1112 MediaSeeking_GetStopPosition,
1113 MediaSeeking_GetCurrentPosition,
1114 MediaSeeking_ConvertTimeFormat,
1115 MediaSeeking_SetPositions,
1116 MediaSeeking_GetPositions,
1117 MediaSeeking_GetAvailable,
1118 MediaSeeking_SetRate,
1119 MediaSeeking_GetRate,
1120 MediaSeeking_GetPreroll
1123 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface)
1125 return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface);
1128 static HRESULT WINAPI PersistMediaPropertyBag_QueryInterface(
1129 IPersistMediaPropertyBag *iface, REFIID riid, void **ppv)
1131 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1132 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1135 static ULONG WINAPI PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag *iface)
1137 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1138 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1141 static ULONG WINAPI PersistMediaPropertyBag_Release(IPersistMediaPropertyBag *iface)
1143 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1144 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1147 static HRESULT WINAPI PersistMediaPropertyBag_GetClassID(
1148 IPersistMediaPropertyBag *iface, CLSID *pClassID)
1150 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1151 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID);
1154 static HRESULT WINAPI PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag *iface)
1156 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1157 FIXME("(%p)->()\n", This);
1158 return E_NOTIMPL;
1161 static HRESULT WINAPI PersistMediaPropertyBag_Load(IPersistMediaPropertyBag *iface,
1162 IMediaPropertyBag *pPropBag, IErrorLog *pErrorLog)
1164 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1165 FIXME("(%p)->()\n", This);
1166 return E_NOTIMPL;
1169 static HRESULT WINAPI PersistMediaPropertyBag_Save(IPersistMediaPropertyBag *iface,
1170 IMediaPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
1172 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1173 FIXME("(%p)->()\n", This);
1174 return E_NOTIMPL;
1177 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl = {
1178 PersistMediaPropertyBag_QueryInterface,
1179 PersistMediaPropertyBag_AddRef,
1180 PersistMediaPropertyBag_Release,
1181 PersistMediaPropertyBag_GetClassID,
1182 PersistMediaPropertyBag_InitNew,
1183 PersistMediaPropertyBag_Load,
1184 PersistMediaPropertyBag_Save
1187 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface)
1189 return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface);
1192 static HRESULT WINAPI SpecifyPropertyPages_QueryInterface(
1193 ISpecifyPropertyPages *iface, REFIID riid, void **ppv)
1195 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1196 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1199 static ULONG WINAPI SpecifyPropertyPages_AddRef(ISpecifyPropertyPages *iface)
1201 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1202 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1205 static ULONG WINAPI SpecifyPropertyPages_Release(ISpecifyPropertyPages *iface)
1207 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1208 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1211 static HRESULT WINAPI SpecifyPropertyPages_GetPages(
1212 ISpecifyPropertyPages *iface, CAUUID *pPages)
1214 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1215 FIXME("(%p)->(%p)\n", This, pPages);
1216 return E_NOTIMPL;
1219 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = {
1220 SpecifyPropertyPages_QueryInterface,
1221 SpecifyPropertyPages_AddRef,
1222 SpecifyPropertyPages_Release,
1223 SpecifyPropertyPages_GetPages
1226 static HRESULT WINAPI AviMuxOut_CheckMediaType(BasePin *base, const AM_MEDIA_TYPE *amt)
1228 FIXME("(%p) stub\n", base);
1229 return S_OK;
1232 static HRESULT WINAPI AviMuxOut_AttemptConnection(BasePin *base,
1233 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1235 PIN_DIRECTION dir;
1236 HRESULT hr;
1238 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", base, pReceivePin, pmt);
1239 dump_AM_MEDIA_TYPE(pmt);
1241 hr = IPin_QueryDirection(pReceivePin, &dir);
1242 if(hr==S_OK && dir!=PINDIR_INPUT)
1243 return VFW_E_INVALID_DIRECTION;
1245 return BaseOutputPinImpl_AttemptConnection(base, pReceivePin, pmt);
1248 static LONG WINAPI AviMuxOut_GetMediaTypeVersion(BasePin *base)
1250 return 0;
1253 static HRESULT WINAPI AviMuxOut_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
1255 TRACE("(%p)->(%d %p)\n", base, iPosition, amt);
1257 if(iPosition < 0)
1258 return E_INVALIDARG;
1259 if(iPosition > 0)
1260 return VFW_S_NO_MORE_ITEMS;
1262 amt->majortype = MEDIATYPE_Stream;
1263 amt->subtype = MEDIASUBTYPE_Avi;
1264 amt->bFixedSizeSamples = TRUE;
1265 amt->bTemporalCompression = FALSE;
1266 amt->lSampleSize = 1;
1267 amt->formattype = GUID_NULL;
1268 amt->pUnk = NULL;
1269 amt->cbFormat = 0;
1270 amt->pbFormat = NULL;
1271 return S_OK;
1274 static HRESULT WINAPI AviMuxOut_DecideAllocator(BaseOutputPin *base,
1275 IMemInputPin *pPin, IMemAllocator **pAlloc)
1277 ALLOCATOR_PROPERTIES req, actual;
1278 HRESULT hr;
1280 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc);
1282 hr = BaseOutputPinImpl_InitAllocator(base, pAlloc);
1283 if(FAILED(hr))
1284 return hr;
1286 hr = IMemInputPin_GetAllocatorRequirements(pPin, &req);
1287 if(FAILED(hr))
1288 req.cbAlign = 1;
1289 req.cBuffers = 32;
1290 req.cbBuffer = 0;
1291 req.cbPrefix = 0;
1293 hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual);
1294 if(FAILED(hr))
1295 return hr;
1297 return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE);
1300 static HRESULT WINAPI AviMuxOut_BreakConnect(BaseOutputPin *base)
1302 FIXME("(%p)\n", base);
1303 return E_NOTIMPL;
1306 static const BaseOutputPinFuncTable AviMuxOut_BaseOutputFuncTable = {
1308 AviMuxOut_CheckMediaType,
1309 AviMuxOut_AttemptConnection,
1310 AviMuxOut_GetMediaTypeVersion,
1311 AviMuxOut_GetMediaType
1313 NULL,
1314 AviMuxOut_DecideAllocator,
1315 AviMuxOut_BreakConnect
1318 static inline AviMux* impl_from_out_IPin(IPin *iface)
1320 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface);
1321 IBaseFilter *bf = bp->pinInfo.pFilter;
1323 return impl_from_IBaseFilter(bf);
1326 static HRESULT WINAPI AviMuxOut_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1328 AviMux *This = impl_from_out_IPin(iface);
1330 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1332 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1333 *ppv = iface;
1334 else if(IsEqualIID(riid, &IID_IQualityControl))
1335 *ppv = &This->out->IQualityControl_iface;
1336 else {
1337 FIXME("no interface for %s\n", debugstr_guid(riid));
1338 *ppv = NULL;
1339 return E_NOINTERFACE;
1342 IUnknown_AddRef((IUnknown*)*ppv);
1343 return S_OK;
1346 static ULONG WINAPI AviMuxOut_AddRef(IPin *iface)
1348 AviMux *This = impl_from_out_IPin(iface);
1349 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1352 static ULONG WINAPI AviMuxOut_Release(IPin *iface)
1354 AviMux *This = impl_from_out_IPin(iface);
1355 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1358 static HRESULT WINAPI AviMuxOut_Connect(IPin *iface,
1359 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1361 AviMux *This = impl_from_out_IPin(iface);
1362 HRESULT hr;
1363 int i;
1365 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", This, pReceivePin, pmt);
1366 dump_AM_MEDIA_TYPE(pmt);
1368 hr = BaseOutputPinImpl_Connect(iface, pReceivePin, pmt);
1369 if(FAILED(hr))
1370 return hr;
1372 for(i=0; i<This->input_pin_no; i++) {
1373 if(!This->in[i]->pin.pin.pConnectedTo)
1374 continue;
1376 hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, &This->in[i]->pin.pin.IPin_iface);
1377 if(FAILED(hr)) {
1378 BaseOutputPinImpl_Disconnect(iface);
1379 break;
1383 if(hr == S_OK)
1384 IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1385 return hr;
1388 static HRESULT WINAPI AviMuxOut_ReceiveConnection(IPin *iface,
1389 IPin *pConnector, const AM_MEDIA_TYPE *pmt)
1391 AviMux *This = impl_from_out_IPin(iface);
1392 TRACE("(%p)->(%p AM_MEDIA_TYPE(%p)\n", This, pConnector, pmt);
1393 dump_AM_MEDIA_TYPE(pmt);
1394 return BaseOutputPinImpl_ReceiveConnection(iface, pConnector, pmt);
1397 static HRESULT WINAPI AviMuxOut_Disconnect(IPin *iface)
1399 AviMux *This = impl_from_out_IPin(iface);
1400 HRESULT hr;
1402 TRACE("(%p)\n", This);
1404 hr = BaseOutputPinImpl_Disconnect(iface);
1405 if(hr == S_OK)
1406 IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1407 return hr;
1410 static HRESULT WINAPI AviMuxOut_ConnectedTo(IPin *iface, IPin **pPin)
1412 AviMux *This = impl_from_out_IPin(iface);
1413 TRACE("(%p)->(%p)\n", This, pPin);
1414 return BasePinImpl_ConnectedTo(iface, pPin);
1417 static HRESULT WINAPI AviMuxOut_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
1419 AviMux *This = impl_from_out_IPin(iface);
1420 TRACE("(%p)->(%p)\n", This, pmt);
1421 return BasePinImpl_ConnectionMediaType(iface, pmt);
1424 static HRESULT WINAPI AviMuxOut_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
1426 AviMux *This = impl_from_out_IPin(iface);
1427 TRACE("(%p)->(%p)\n", This, pInfo);
1428 return BasePinImpl_QueryPinInfo(iface, pInfo);
1431 static HRESULT WINAPI AviMuxOut_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
1433 AviMux *This = impl_from_out_IPin(iface);
1434 TRACE("(%p)->(%p)\n", This, pPinDir);
1435 return BasePinImpl_QueryDirection(iface, pPinDir);
1438 static HRESULT WINAPI AviMuxOut_QueryId(IPin *iface, LPWSTR *Id)
1440 AviMux *This = impl_from_out_IPin(iface);
1441 TRACE("(%p)->(%p)\n", This, Id);
1442 return BasePinImpl_QueryId(iface, Id);
1445 static HRESULT WINAPI AviMuxOut_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
1447 AviMux *This = impl_from_out_IPin(iface);
1448 TRACE("(%p)->(AM_MEDIA_TYPE(%p))\n", This, pmt);
1449 dump_AM_MEDIA_TYPE(pmt);
1450 return BasePinImpl_QueryAccept(iface, pmt);
1453 static HRESULT WINAPI AviMuxOut_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1455 AviMux *This = impl_from_out_IPin(iface);
1456 TRACE("(%p)->(%p)\n", This, ppEnum);
1457 return BasePinImpl_EnumMediaTypes(iface, ppEnum);
1460 static HRESULT WINAPI AviMuxOut_QueryInternalConnections(
1461 IPin *iface, IPin **apPin, ULONG *nPin)
1463 AviMux *This = impl_from_out_IPin(iface);
1464 FIXME("(%p)->(%p %p)\n", This, apPin, nPin);
1465 return E_NOTIMPL;
1468 static HRESULT WINAPI AviMuxOut_EndOfStream(IPin *iface)
1470 AviMux *This = impl_from_out_IPin(iface);
1471 TRACE("(%p)\n", This);
1472 return BaseOutputPinImpl_EndOfStream(iface);
1475 static HRESULT WINAPI AviMuxOut_BeginFlush(IPin *iface)
1477 AviMux *This = impl_from_out_IPin(iface);
1478 TRACE("(%p)\n", This);
1479 return BaseOutputPinImpl_BeginFlush(iface);
1482 static HRESULT WINAPI AviMuxOut_EndFlush(IPin *iface)
1484 AviMux *This = impl_from_out_IPin(iface);
1485 TRACE("(%p)\n", This);
1486 return BaseOutputPinImpl_EndFlush(iface);
1489 static HRESULT WINAPI AviMuxOut_NewSegment(IPin *iface, REFERENCE_TIME tStart,
1490 REFERENCE_TIME tStop, double dRate)
1492 AviMux *This = impl_from_out_IPin(iface);
1493 TRACE("(%p)->(%s %s %f)\n", This, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1494 return BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1497 static const IPinVtbl AviMuxOut_PinVtbl = {
1498 AviMuxOut_QueryInterface,
1499 AviMuxOut_AddRef,
1500 AviMuxOut_Release,
1501 AviMuxOut_Connect,
1502 AviMuxOut_ReceiveConnection,
1503 AviMuxOut_Disconnect,
1504 AviMuxOut_ConnectedTo,
1505 AviMuxOut_ConnectionMediaType,
1506 AviMuxOut_QueryPinInfo,
1507 AviMuxOut_QueryDirection,
1508 AviMuxOut_QueryId,
1509 AviMuxOut_QueryAccept,
1510 AviMuxOut_EnumMediaTypes,
1511 AviMuxOut_QueryInternalConnections,
1512 AviMuxOut_EndOfStream,
1513 AviMuxOut_BeginFlush,
1514 AviMuxOut_EndFlush,
1515 AviMuxOut_NewSegment
1518 static inline AviMux* impl_from_out_IQualityControl(IQualityControl *iface)
1520 AviMuxOut *amo = CONTAINING_RECORD(iface, AviMuxOut, IQualityControl_iface);
1521 return impl_from_IBaseFilter(amo->pin.pin.pinInfo.pFilter);
1524 static HRESULT WINAPI AviMuxOut_QualityControl_QueryInterface(
1525 IQualityControl *iface, REFIID riid, void **ppv)
1527 AviMux *This = impl_from_out_IQualityControl(iface);
1528 return IPin_QueryInterface(&This->out->pin.pin.IPin_iface, riid, ppv);
1531 static ULONG WINAPI AviMuxOut_QualityControl_AddRef(IQualityControl *iface)
1533 AviMux *This = impl_from_out_IQualityControl(iface);
1534 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1537 static ULONG WINAPI AviMuxOut_QualityControl_Release(IQualityControl *iface)
1539 AviMux *This = impl_from_out_IQualityControl(iface);
1540 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1543 static HRESULT WINAPI AviMuxOut_QualityControl_Notify(IQualityControl *iface,
1544 IBaseFilter *pSelf, Quality q)
1546 AviMux *This = impl_from_out_IQualityControl(iface);
1547 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This, pSelf,
1548 q.Type, q.Proportion,
1549 wine_dbgstr_longlong(q.Late),
1550 wine_dbgstr_longlong(q.TimeStamp));
1551 return E_NOTIMPL;
1554 static HRESULT WINAPI AviMuxOut_QualityControl_SetSink(
1555 IQualityControl *iface, IQualityControl *piqc)
1557 AviMux *This = impl_from_out_IQualityControl(iface);
1558 FIXME("(%p)->(%p)\n", This, piqc);
1559 return E_NOTIMPL;
1562 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl = {
1563 AviMuxOut_QualityControl_QueryInterface,
1564 AviMuxOut_QualityControl_AddRef,
1565 AviMuxOut_QualityControl_Release,
1566 AviMuxOut_QualityControl_Notify,
1567 AviMuxOut_QualityControl_SetSink
1570 static HRESULT WINAPI AviMuxIn_CheckMediaType(BasePin *base, const AM_MEDIA_TYPE *pmt)
1572 TRACE("(%p:%s)->(AM_MEDIA_TYPE(%p))\n", base, debugstr_w(base->pinInfo.achName), pmt);
1573 dump_AM_MEDIA_TYPE(pmt);
1575 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) &&
1576 IsEqualIID(&pmt->formattype, &FORMAT_WaveFormatEx))
1577 return S_OK;
1578 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Interleaved) &&
1579 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo))
1580 return S_OK;
1581 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1582 (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo) ||
1583 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo)))
1584 return S_OK;
1585 return S_FALSE;
1588 static LONG WINAPI AviMuxIn_GetMediaTypeVersion(BasePin *base)
1590 return 0;
1593 static HRESULT WINAPI AviMuxIn_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
1595 return S_FALSE;
1598 static HRESULT WINAPI AviMuxIn_Receive(BaseInputPin *base, IMediaSample *pSample)
1600 AviMuxIn *avimuxin = CONTAINING_RECORD(base, AviMuxIn, pin);
1601 AviMux *avimux = impl_from_IBaseFilter(base->pin.pinInfo.pFilter);
1602 REFERENCE_TIME start, stop;
1603 IMediaSample *sample;
1604 int frames_no;
1605 IMediaSample2 *ms2;
1606 BYTE *frame, *buf;
1607 DWORD max_size, size;
1608 DWORD flags;
1609 HRESULT hr;
1611 TRACE("(%p:%s)->(%p)\n", base, debugstr_w(base->pin.pinInfo.achName), pSample);
1613 hr = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&ms2);
1614 if(SUCCEEDED(hr)) {
1615 AM_SAMPLE2_PROPERTIES props;
1617 memset(&props, 0, sizeof(props));
1618 hr = IMediaSample2_GetProperties(ms2, sizeof(props), (BYTE*)&props);
1619 IMediaSample2_Release(ms2);
1620 if(FAILED(hr))
1621 return hr;
1623 flags = props.dwSampleFlags;
1624 frame = props.pbBuffer;
1625 size = props.lActual;
1626 }else {
1627 flags = IMediaSample_IsSyncPoint(pSample) == S_OK ? AM_SAMPLE_SPLICEPOINT : 0;
1628 hr = IMediaSample_GetPointer(pSample, &frame);
1629 if(FAILED(hr))
1630 return hr;
1631 size = IMediaSample_GetActualDataLength(pSample);
1634 if(!avimuxin->pin.pin.mtCurrent.bTemporalCompression)
1635 flags |= AM_SAMPLE_SPLICEPOINT;
1637 hr = IMediaSample_GetTime(pSample, &start, &stop);
1638 if(FAILED(hr))
1639 return hr;
1641 if(avimuxin->stop>stop)
1642 return VFW_E_START_TIME_AFTER_END;
1644 if(avimux->start == -1)
1645 avimux->start = start;
1646 if(avimux->stop < stop)
1647 avimux->stop = stop;
1649 if(avimux->avih.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1650 avimux->avih.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1651 if(avimuxin->strh.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1652 avimuxin->strh.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1654 frames_no = 1;
1655 if(avimuxin->stop!=-1 && start > avimuxin->stop) {
1656 frames_no += (double)(start - avimuxin->stop) / 10000000
1657 * avimuxin->strh.dwRate / avimuxin->strh.dwScale + 0.5;
1659 avimuxin->stop = stop;
1661 while(--frames_no) {
1662 /* TODO: store all control frames in one buffer */
1663 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1664 if(FAILED(hr))
1665 return hr;
1666 hr = IMediaSample_SetActualDataLength(sample, 0);
1667 if(SUCCEEDED(hr))
1668 hr = IMediaSample_SetDiscontinuity(sample, TRUE);
1669 if(SUCCEEDED(hr))
1670 hr = IMediaSample_SetSyncPoint(sample, FALSE);
1671 if(SUCCEEDED(hr))
1672 hr = queue_sample(avimux, avimuxin, sample);
1673 IMediaSample_Release(sample);
1674 if(FAILED(hr))
1675 return hr;
1678 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1679 if(FAILED(hr))
1680 return hr;
1681 max_size = IMediaSample_GetSize(sample);
1682 if(size > max_size)
1683 size = max_size;
1684 hr = IMediaSample_SetActualDataLength(sample, size);
1685 if(SUCCEEDED(hr))
1686 hr = IMediaSample_SetDiscontinuity(sample, FALSE);
1687 if(SUCCEEDED(hr))
1688 hr = IMediaSample_SetSyncPoint(sample, flags & AM_SAMPLE_SPLICEPOINT);
1689 /* TODO: avoid unnecessary copying */
1690 if(SUCCEEDED(hr))
1691 hr = IMediaSample_GetPointer(sample, &buf);
1692 if(SUCCEEDED(hr)) {
1693 memcpy(buf, frame, size);
1694 hr = queue_sample(avimux, avimuxin, sample);
1696 IMediaSample_Release(sample);
1698 return hr;
1701 static const BaseInputPinFuncTable AviMuxIn_BaseInputFuncTable = {
1703 AviMuxIn_CheckMediaType,
1704 NULL,
1705 AviMuxIn_GetMediaTypeVersion,
1706 AviMuxIn_GetMediaType
1708 AviMuxIn_Receive
1711 static inline AviMux* impl_from_in_IPin(IPin *iface)
1713 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface);
1714 IBaseFilter *bf = bp->pinInfo.pFilter;
1716 return impl_from_IBaseFilter(bf);
1719 static inline AviMuxIn* AviMuxIn_from_IPin(IPin *iface)
1721 BasePin *bp = CONTAINING_RECORD(iface, BasePin, IPin_iface);
1722 BaseInputPin *bip = CONTAINING_RECORD(bp, BaseInputPin, pin);
1723 return CONTAINING_RECORD(bip, AviMuxIn, pin);
1726 static HRESULT WINAPI AviMuxIn_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1728 AviMux *This = impl_from_in_IPin(iface);
1729 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1731 TRACE("(%p:%s)->(%s %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
1732 debugstr_guid(riid), ppv);
1734 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1735 *ppv = &avimuxin->pin.pin.IPin_iface;
1736 else if(IsEqualIID(riid, &IID_IAMStreamControl))
1737 *ppv = &avimuxin->IAMStreamControl_iface;
1738 else if(IsEqualIID(riid, &IID_IMemInputPin))
1739 *ppv = &avimuxin->pin.IMemInputPin_iface;
1740 else if(IsEqualIID(riid, &IID_IPropertyBag))
1741 *ppv = &avimuxin->IPropertyBag_iface;
1742 else if(IsEqualIID(riid, &IID_IQualityControl))
1743 *ppv = &avimuxin->IQualityControl_iface;
1744 else {
1745 FIXME("no interface for %s\n", debugstr_guid(riid));
1746 *ppv = NULL;
1747 return E_NOINTERFACE;
1750 IUnknown_AddRef((IUnknown*)*ppv);
1751 return S_OK;
1754 static ULONG WINAPI AviMuxIn_AddRef(IPin *iface)
1756 AviMux *This = impl_from_in_IPin(iface);
1757 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1760 static ULONG WINAPI AviMuxIn_Release(IPin *iface)
1762 AviMux *This = impl_from_in_IPin(iface);
1763 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1766 static HRESULT WINAPI AviMuxIn_Connect(IPin *iface,
1767 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1769 AviMux *This = impl_from_in_IPin(iface);
1770 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1771 TRACE("(%p:%s)->(%p AM_MEDIA_TYPE(%p))\n", This,
1772 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pReceivePin, pmt);
1773 dump_AM_MEDIA_TYPE(pmt);
1774 return BaseInputPinImpl_Connect(iface, pReceivePin, pmt);
1777 static HRESULT WINAPI AviMuxIn_ReceiveConnection(IPin *iface,
1778 IPin *pConnector, const AM_MEDIA_TYPE *pmt)
1780 AviMux *This = impl_from_in_IPin(iface);
1781 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1782 HRESULT hr;
1784 TRACE("(%p:%s)->(%p AM_MEDIA_TYPE(%p))\n", This,
1785 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pConnector, pmt);
1786 dump_AM_MEDIA_TYPE(pmt);
1788 if(!pmt)
1789 return E_POINTER;
1791 hr = BaseInputPinImpl_ReceiveConnection(iface, pConnector, pmt);
1792 if(FAILED(hr))
1793 return hr;
1795 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1796 IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
1797 ALLOCATOR_PROPERTIES req, act;
1798 VIDEOINFOHEADER *vih;
1799 int size;
1801 vih = (VIDEOINFOHEADER*)pmt->pbFormat;
1802 avimuxin->strh.fcc = ckidSTREAMHEADER;
1803 avimuxin->strh.cb = sizeof(AVISTREAMHEADER) - FIELD_OFFSET(AVISTREAMHEADER, fccType);
1804 avimuxin->strh.fccType = streamtypeVIDEO;
1805 /* FIXME: fccHandler should be set differently */
1806 avimuxin->strh.fccHandler = vih->bmiHeader.biCompression ?
1807 vih->bmiHeader.biCompression : FCC('D','I','B',' ');
1808 avimuxin->avg_time_per_frame = vih->AvgTimePerFrame;
1809 avimuxin->stop = -1;
1811 req.cBuffers = 32;
1812 req.cbBuffer = vih->bmiHeader.biSizeImage;
1813 req.cbAlign = 1;
1814 req.cbPrefix = sizeof(void*);
1815 hr = IMemAllocator_SetProperties(avimuxin->samples_allocator, &req, &act);
1816 if(SUCCEEDED(hr))
1817 hr = IMemAllocator_Commit(avimuxin->samples_allocator);
1818 if(FAILED(hr)) {
1819 BasePinImpl_Disconnect(iface);
1820 return hr;
1823 size = pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
1824 avimuxin->strf = CoTaskMemAlloc(sizeof(RIFFCHUNK) + ALIGN(FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed])));
1825 avimuxin->strf->fcc = ckidSTREAMFORMAT;
1826 avimuxin->strf->cb = FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]);
1827 if(size > avimuxin->strf->cb)
1828 size = avimuxin->strf->cb;
1829 memcpy(avimuxin->strf->data, &vih->bmiHeader, size);
1830 }else {
1831 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt->majortype),
1832 debugstr_guid(&pmt->formattype));
1833 return E_NOTIMPL;
1836 return create_input_pin(This);
1839 static HRESULT WINAPI AviMuxIn_Disconnect(IPin *iface)
1841 AviMux *This = impl_from_in_IPin(iface);
1842 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1843 IMediaSample **prev, *cur;
1844 HRESULT hr;
1846 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
1848 hr = BasePinImpl_Disconnect(iface);
1849 if(FAILED(hr))
1850 return hr;
1852 IMemAllocator_Decommit(avimuxin->samples_allocator);
1853 while(avimuxin->samples_head) {
1854 cur = avimuxin->samples_head;
1855 hr = IMediaSample_GetPointer(cur, (BYTE**)&prev);
1856 if(FAILED(hr))
1857 break;
1858 prev--;
1860 cur = avimuxin->samples_head;
1861 avimuxin->samples_head = *prev;
1862 IMediaSample_Release(cur);
1864 if(cur == avimuxin->samples_head)
1865 avimuxin->samples_head = NULL;
1867 CoTaskMemFree(avimuxin->strf);
1868 avimuxin->strf = NULL;
1869 return hr;
1872 static HRESULT WINAPI AviMuxIn_ConnectedTo(IPin *iface, IPin **pPin)
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), pPin);
1877 return BasePinImpl_ConnectedTo(iface, pPin);
1880 static HRESULT WINAPI AviMuxIn_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
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), pmt);
1885 return BasePinImpl_ConnectionMediaType(iface, pmt);
1888 static HRESULT WINAPI AviMuxIn_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
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), pInfo);
1893 return BasePinImpl_QueryPinInfo(iface, pInfo);
1896 static HRESULT WINAPI AviMuxIn_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
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), pPinDir);
1901 return BasePinImpl_QueryDirection(iface, pPinDir);
1904 static HRESULT WINAPI AviMuxIn_QueryId(IPin *iface, LPWSTR *Id)
1906 AviMux *This = impl_from_in_IPin(iface);
1907 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1908 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), Id);
1909 return BasePinImpl_QueryId(iface, Id);
1912 static HRESULT WINAPI AviMuxIn_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
1914 AviMux *This = impl_from_in_IPin(iface);
1915 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1916 TRACE("(%p:%s)->(AM_MEDIA_TYPE(%p))\n", This,
1917 debugstr_w(avimuxin->pin.pin.pinInfo.achName), pmt);
1918 dump_AM_MEDIA_TYPE(pmt);
1919 return BasePinImpl_QueryAccept(iface, pmt);
1922 static HRESULT WINAPI AviMuxIn_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1924 AviMux *This = impl_from_in_IPin(iface);
1925 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1926 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), ppEnum);
1927 return BasePinImpl_EnumMediaTypes(iface, ppEnum);
1930 static HRESULT WINAPI AviMuxIn_QueryInternalConnections(
1931 IPin *iface, IPin **apPin, ULONG *nPin)
1933 AviMux *This = impl_from_in_IPin(iface);
1934 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1935 TRACE("(%p:%s)->(%p %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), apPin, nPin);
1936 return BasePinImpl_QueryInternalConnections(iface, apPin, nPin);
1939 static HRESULT WINAPI AviMuxIn_EndOfStream(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_EndOfStream(iface);
1947 static HRESULT WINAPI AviMuxIn_BeginFlush(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_BeginFlush(iface);
1955 static HRESULT WINAPI AviMuxIn_EndFlush(IPin *iface)
1957 AviMux *This = impl_from_in_IPin(iface);
1958 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1959 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
1960 return BaseInputPinImpl_EndFlush(iface);
1963 static HRESULT WINAPI AviMuxIn_NewSegment(IPin *iface, REFERENCE_TIME tStart,
1964 REFERENCE_TIME tStop, double dRate)
1966 AviMux *This = impl_from_in_IPin(iface);
1967 AviMuxIn *avimuxin = AviMuxIn_from_IPin(iface);
1968 TRACE("(%p:%s)->(%s %s %f)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
1969 wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1970 return BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1973 static const IPinVtbl AviMuxIn_PinVtbl = {
1974 AviMuxIn_QueryInterface,
1975 AviMuxIn_AddRef,
1976 AviMuxIn_Release,
1977 AviMuxIn_Connect,
1978 AviMuxIn_ReceiveConnection,
1979 AviMuxIn_Disconnect,
1980 AviMuxIn_ConnectedTo,
1981 AviMuxIn_ConnectionMediaType,
1982 AviMuxIn_QueryPinInfo,
1983 AviMuxIn_QueryDirection,
1984 AviMuxIn_QueryId,
1985 AviMuxIn_QueryAccept,
1986 AviMuxIn_EnumMediaTypes,
1987 AviMuxIn_QueryInternalConnections,
1988 AviMuxIn_EndOfStream,
1989 AviMuxIn_BeginFlush,
1990 AviMuxIn_EndFlush,
1991 AviMuxIn_NewSegment
1994 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface)
1996 return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface);
1999 static HRESULT WINAPI AviMuxIn_AMStreamControl_QueryInterface(
2000 IAMStreamControl *iface, REFIID riid, void **ppv)
2002 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2003 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2006 static ULONG WINAPI AviMuxIn_AMStreamControl_AddRef(IAMStreamControl *iface)
2008 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2009 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2010 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2013 static ULONG WINAPI AviMuxIn_AMStreamControl_Release(IAMStreamControl *iface)
2015 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2016 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2017 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2020 static HRESULT WINAPI AviMuxIn_AMStreamControl_StartAt(IAMStreamControl *iface,
2021 const REFERENCE_TIME *ptStart, DWORD dwCookie)
2023 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2024 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2025 FIXME("(%p:%s)->(%p %x)\n", This,
2026 debugstr_w(avimuxin->pin.pin.pinInfo.achName), ptStart, dwCookie);
2027 return E_NOTIMPL;
2030 static HRESULT WINAPI AviMuxIn_AMStreamControl_StopAt(IAMStreamControl *iface,
2031 const REFERENCE_TIME *ptStop, BOOL bSendExtra, DWORD dwCookie)
2033 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2034 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2035 FIXME("(%p:%s)->(%p %x %x)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2036 ptStop, bSendExtra, dwCookie);
2037 return E_NOTIMPL;
2040 static HRESULT WINAPI AviMuxIn_AMStreamControl_GetInfo(
2041 IAMStreamControl *iface, AM_STREAM_INFO *pInfo)
2043 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
2044 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2045 FIXME("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pInfo);
2046 return E_NOTIMPL;
2049 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl = {
2050 AviMuxIn_AMStreamControl_QueryInterface,
2051 AviMuxIn_AMStreamControl_AddRef,
2052 AviMuxIn_AMStreamControl_Release,
2053 AviMuxIn_AMStreamControl_StartAt,
2054 AviMuxIn_AMStreamControl_StopAt,
2055 AviMuxIn_AMStreamControl_GetInfo
2058 static inline AviMuxIn* AviMuxIn_from_IMemInputPin(IMemInputPin *iface)
2060 BaseInputPin *bip = CONTAINING_RECORD(iface, BaseInputPin, IMemInputPin_iface);
2061 return CONTAINING_RECORD(bip, AviMuxIn, pin);
2064 static HRESULT WINAPI AviMuxIn_MemInputPin_QueryInterface(
2065 IMemInputPin *iface, REFIID riid, void **ppv)
2067 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2068 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2071 static ULONG WINAPI AviMuxIn_MemInputPin_AddRef(IMemInputPin *iface)
2073 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2074 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2075 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2078 static ULONG WINAPI AviMuxIn_MemInputPin_Release(IMemInputPin *iface)
2080 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2081 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2082 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2085 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocator(
2086 IMemInputPin *iface, IMemAllocator **ppAllocator)
2088 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2089 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2091 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), ppAllocator);
2093 if(!ppAllocator)
2094 return E_POINTER;
2096 IMemAllocator_AddRef(avimuxin->pin.pAllocator);
2097 *ppAllocator = avimuxin->pin.pAllocator;
2098 return S_OK;
2101 static HRESULT WINAPI AviMuxIn_MemInputPin_NotifyAllocator(
2102 IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly)
2104 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2105 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2106 ALLOCATOR_PROPERTIES props;
2107 HRESULT hr;
2109 TRACE("(%p:%s)->(%p %x)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2110 pAllocator, bReadOnly);
2112 if(!pAllocator)
2113 return E_POINTER;
2115 memset(&props, 0, sizeof(props));
2116 hr = IMemAllocator_GetProperties(pAllocator, &props);
2117 if(FAILED(hr))
2118 return hr;
2120 props.cbAlign = 1;
2121 props.cbPrefix = 8;
2122 return IMemAllocator_SetProperties(avimuxin->pin.pAllocator, &props, &props);
2125 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocatorRequirements(
2126 IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps)
2128 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2129 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2131 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pProps);
2133 if(!pProps)
2134 return E_POINTER;
2136 pProps->cbAlign = 1;
2137 pProps->cbPrefix = 8;
2138 return S_OK;
2141 static HRESULT WINAPI AviMuxIn_MemInputPin_Receive(
2142 IMemInputPin *iface, IMediaSample *pSample)
2144 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2145 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2147 TRACE("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pSample);
2149 return avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSample);
2152 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin *iface,
2153 IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed)
2155 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2156 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2157 HRESULT hr = S_OK;
2159 TRACE("(%p:%s)->(%p %d %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2160 pSamples, nSamples, nSamplesProcessed);
2162 for(*nSamplesProcessed=0; *nSamplesProcessed<nSamples; (*nSamplesProcessed)++)
2164 hr = avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSamples[*nSamplesProcessed]);
2165 if(hr != S_OK)
2166 break;
2169 return hr;
2172 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin *iface)
2174 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
2175 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2176 HRESULT hr;
2178 TRACE("(%p:%s)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName));
2180 if(!This->out->pin.pMemInputPin)
2181 return S_FALSE;
2183 hr = IMemInputPin_ReceiveCanBlock(This->out->pin.pMemInputPin);
2184 return hr != S_FALSE ? S_OK : S_FALSE;
2187 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl = {
2188 AviMuxIn_MemInputPin_QueryInterface,
2189 AviMuxIn_MemInputPin_AddRef,
2190 AviMuxIn_MemInputPin_Release,
2191 AviMuxIn_MemInputPin_GetAllocator,
2192 AviMuxIn_MemInputPin_NotifyAllocator,
2193 AviMuxIn_MemInputPin_GetAllocatorRequirements,
2194 AviMuxIn_MemInputPin_Receive,
2195 AviMuxIn_MemInputPin_ReceiveMultiple,
2196 AviMuxIn_MemInputPin_ReceiveCanBlock
2199 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface)
2201 return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface);
2204 static HRESULT WINAPI AviMuxIn_PropertyBag_QueryInterface(
2205 IPropertyBag *iface, REFIID riid, void **ppv)
2207 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2208 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2211 static ULONG WINAPI AviMuxIn_PropertyBag_AddRef(IPropertyBag *iface)
2213 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2214 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2215 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2218 static ULONG WINAPI AviMuxIn_PropertyBag_Release(IPropertyBag *iface)
2220 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2221 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2222 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2225 static HRESULT WINAPI AviMuxIn_PropertyBag_Read(IPropertyBag *iface,
2226 LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
2228 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2229 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2230 FIXME("(%p:%s)->(%s %p %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2231 debugstr_w(pszPropName), pVar, pErrorLog);
2232 return E_NOTIMPL;
2235 static HRESULT WINAPI AviMuxIn_PropertyBag_Write(IPropertyBag *iface,
2236 LPCOLESTR pszPropName, VARIANT *pVar)
2238 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
2239 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2240 FIXME("(%p:%s)->(%s %p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName),
2241 debugstr_w(pszPropName), pVar);
2242 return E_NOTIMPL;
2245 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl = {
2246 AviMuxIn_PropertyBag_QueryInterface,
2247 AviMuxIn_PropertyBag_AddRef,
2248 AviMuxIn_PropertyBag_Release,
2249 AviMuxIn_PropertyBag_Read,
2250 AviMuxIn_PropertyBag_Write
2253 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface)
2255 return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface);
2258 static HRESULT WINAPI AviMuxIn_QualityControl_QueryInterface(
2259 IQualityControl *iface, REFIID riid, void **ppv)
2261 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2262 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
2265 static ULONG WINAPI AviMuxIn_QualityControl_AddRef(IQualityControl *iface)
2267 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2268 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2269 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
2272 static ULONG WINAPI AviMuxIn_QualityControl_Release(IQualityControl *iface)
2274 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2275 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2276 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
2279 static HRESULT WINAPI AviMuxIn_QualityControl_Notify(IQualityControl *iface,
2280 IBaseFilter *pSelf, Quality q)
2282 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2283 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2284 FIXME("(%p:%s)->(%p { 0x%x %u %s %s })\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), pSelf,
2285 q.Type, q.Proportion,
2286 wine_dbgstr_longlong(q.Late),
2287 wine_dbgstr_longlong(q.TimeStamp));
2288 return E_NOTIMPL;
2291 static HRESULT WINAPI AviMuxIn_QualityControl_SetSink(
2292 IQualityControl *iface, IQualityControl *piqc)
2294 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
2295 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
2296 FIXME("(%p:%s)->(%p)\n", This, debugstr_w(avimuxin->pin.pin.pinInfo.achName), piqc);
2297 return E_NOTIMPL;
2300 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl = {
2301 AviMuxIn_QualityControl_QueryInterface,
2302 AviMuxIn_QualityControl_AddRef,
2303 AviMuxIn_QualityControl_Release,
2304 AviMuxIn_QualityControl_Notify,
2305 AviMuxIn_QualityControl_SetSink
2308 static HRESULT create_input_pin(AviMux *avimux)
2310 static const WCHAR name[] = {'I','n','p','u','t',' ','0','0',0};
2311 PIN_INFO info;
2312 HRESULT hr;
2314 if(avimux->input_pin_no >= MAX_PIN_NO-1)
2315 return E_FAIL;
2317 info.dir = PINDIR_INPUT;
2318 info.pFilter = &avimux->filter.IBaseFilter_iface;
2319 memcpy(info.achName, name, sizeof(name));
2320 info.achName[7] = '0' + (avimux->input_pin_no+1) % 10;
2321 info.achName[6] = '0' + (avimux->input_pin_no+1) / 10;
2323 hr = BaseInputPin_Construct(&AviMuxIn_PinVtbl, sizeof(AviMuxIn), &info,
2324 &AviMuxIn_BaseInputFuncTable, &avimux->filter.csFilter, NULL, (IPin**)&avimux->in[avimux->input_pin_no]);
2325 if(FAILED(hr))
2326 return hr;
2327 avimux->in[avimux->input_pin_no]->pin.IMemInputPin_iface.lpVtbl = &AviMuxIn_MemInputPinVtbl;
2328 avimux->in[avimux->input_pin_no]->IAMStreamControl_iface.lpVtbl = &AviMuxIn_AMStreamControlVtbl;
2329 avimux->in[avimux->input_pin_no]->IPropertyBag_iface.lpVtbl = &AviMuxIn_PropertyBagVtbl;
2330 avimux->in[avimux->input_pin_no]->IQualityControl_iface.lpVtbl = &AviMuxIn_QualityControlVtbl;
2332 avimux->in[avimux->input_pin_no]->samples_head = NULL;
2333 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
2334 &IID_IMemAllocator, (void**)&avimux->in[avimux->input_pin_no]->samples_allocator);
2335 if(FAILED(hr)) {
2336 BaseInputPinImpl_Release(&avimux->in[avimux->input_pin_no]->pin.pin.IPin_iface);
2337 return hr;
2340 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
2341 &IID_IMemAllocator, (void**)&avimux->in[avimux->input_pin_no]->pin.pAllocator);
2342 if(FAILED(hr)) {
2343 IMemAllocator_Release(avimux->in[avimux->input_pin_no]->samples_allocator);
2344 BaseInputPinImpl_Release(&avimux->in[avimux->input_pin_no]->pin.pin.IPin_iface);
2345 return hr;
2348 avimux->in[avimux->input_pin_no]->stream_time = 0;
2349 memset(&avimux->in[avimux->input_pin_no]->strh, 0, sizeof(avimux->in[avimux->input_pin_no]->strh));
2350 avimux->in[avimux->input_pin_no]->strf = NULL;
2351 memset(&avimux->in[avimux->input_pin_no]->indx_data, 0, sizeof(avimux->in[avimux->input_pin_no]->indx_data));
2352 memset(&avimux->in[avimux->input_pin_no]->ix_data, 0, sizeof(avimux->in[avimux->input_pin_no]->ix_data));
2353 avimux->in[avimux->input_pin_no]->indx = (AVISUPERINDEX*)&avimux->in[avimux->input_pin_no]->indx_data;
2354 avimux->in[avimux->input_pin_no]->ix = (AVISTDINDEX*)avimux->in[avimux->input_pin_no]->ix_data;
2356 avimux->input_pin_no++;
2357 return S_OK;
2360 IUnknown* WINAPI QCAP_createAVIMux(IUnknown *pUnkOuter, HRESULT *phr)
2362 static const WCHAR output_name[] = {'A','V','I',' ','O','u','t',0};
2364 AviMux *avimux;
2365 PIN_INFO info;
2366 HRESULT hr;
2368 TRACE("(%p)\n", pUnkOuter);
2370 if(pUnkOuter) {
2371 *phr = CLASS_E_NOAGGREGATION;
2372 return NULL;
2375 avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux));
2376 if(!avimux) {
2377 *phr = E_OUTOFMEMORY;
2378 return NULL;
2381 BaseFilter_Init(&avimux->filter, &AviMuxVtbl, &CLSID_AviDest,
2382 (DWORD_PTR)(__FILE__ ": AviMux.csFilter"), &filter_func_table);
2383 avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl;
2384 avimux->IConfigInterleaving_iface.lpVtbl = &ConfigInterleavingVtbl;
2385 avimux->IMediaSeeking_iface.lpVtbl = &MediaSeekingVtbl;
2386 avimux->IPersistMediaPropertyBag_iface.lpVtbl = &PersistMediaPropertyBagVtbl;
2387 avimux->ISpecifyPropertyPages_iface.lpVtbl = &SpecifyPropertyPagesVtbl;
2389 info.dir = PINDIR_OUTPUT;
2390 info.pFilter = &avimux->filter.IBaseFilter_iface;
2391 lstrcpyW(info.achName, output_name);
2392 hr = BaseOutputPin_Construct(&AviMuxOut_PinVtbl, sizeof(AviMuxOut), &info,
2393 &AviMuxOut_BaseOutputFuncTable, &avimux->filter.csFilter, (IPin**)&avimux->out);
2394 if(FAILED(hr)) {
2395 BaseFilterImpl_Release(&avimux->filter.IBaseFilter_iface);
2396 HeapFree(GetProcessHeap(), 0, avimux);
2397 *phr = hr;
2398 return NULL;
2400 avimux->out->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl;
2401 avimux->out->cur_stream = 0;
2402 avimux->out->cur_time = 0;
2403 avimux->out->stream = NULL;
2405 hr = create_input_pin(avimux);
2406 if(FAILED(hr)) {
2407 BaseOutputPinImpl_Release(&avimux->out->pin.pin.IPin_iface);
2408 BaseFilterImpl_Release(&avimux->filter.IBaseFilter_iface);
2409 HeapFree(GetProcessHeap(), 0, avimux);
2410 *phr = hr;
2411 return NULL;
2414 avimux->interleave = 10000000;
2416 ObjectRefCount(TRUE);
2417 *phr = S_OK;
2418 return (IUnknown*)&avimux->filter.IBaseFilter_iface;