taskmgr: Shell32 is imported, no need to load it again.
[wine.git] / dlls / qcap / avimux.c
blob3f4d0f2cd6e5a4ac08ccdfba30151b13e7e009da
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 "qcap_private.h"
20 #include "vfw.h"
21 #include "aviriff.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
25 #define MAX_PIN_NO 128
26 #define AVISUPERINDEX_ENTRIES 2000
27 #define AVISTDINDEX_ENTRIES 4000
28 #define ALIGN(x) ((x+1)/2*2)
30 typedef struct {
31 struct strmbase_sink pin;
32 IAMStreamControl IAMStreamControl_iface;
33 IPropertyBag IPropertyBag_iface;
34 IQualityControl IQualityControl_iface;
36 REFERENCE_TIME avg_time_per_frame;
37 REFERENCE_TIME stop;
38 int stream_id;
39 LONGLONG stream_time;
41 /* strl chunk */
42 AVISTREAMHEADER strh;
43 struct {
44 FOURCC fcc;
45 DWORD cb;
46 BYTE data[1];
47 } *strf;
48 AVISUPERINDEX *indx;
49 BYTE indx_data[FIELD_OFFSET(AVISUPERINDEX, aIndex[AVISUPERINDEX_ENTRIES])];
51 /* movi chunk */
52 int ix_off;
53 AVISTDINDEX *ix;
54 BYTE ix_data[FIELD_OFFSET(AVISTDINDEX, aIndex[AVISTDINDEX_ENTRIES])];
56 IMediaSample *samples_head;
57 IMemAllocator *samples_allocator;
58 } AviMuxIn;
60 typedef struct {
61 struct strmbase_filter filter;
62 IConfigAviMux IConfigAviMux_iface;
63 IConfigInterleaving IConfigInterleaving_iface;
64 IMediaSeeking IMediaSeeking_iface;
65 IPersistMediaPropertyBag IPersistMediaPropertyBag_iface;
66 ISpecifyPropertyPages ISpecifyPropertyPages_iface;
68 InterleavingMode mode;
69 REFERENCE_TIME interleave;
70 REFERENCE_TIME preroll;
72 struct strmbase_source source;
73 IQualityControl IQualityControl_iface;
75 int input_pin_no;
76 AviMuxIn *in[MAX_PIN_NO-1];
78 REFERENCE_TIME start, stop;
79 AVIMAINHEADER avih;
81 int idx1_entries;
82 int idx1_size;
83 AVIINDEXENTRY *idx1;
85 int cur_stream;
86 LONGLONG cur_time;
88 int buf_pos;
89 BYTE buf[65536];
91 int movi_off;
92 int out_pos;
93 int size;
94 IStream *stream;
95 } AviMux;
97 static HRESULT create_input_pin(AviMux*);
99 static inline AviMux* impl_from_strmbase_filter(struct strmbase_filter *filter)
101 return CONTAINING_RECORD(filter, AviMux, filter);
104 static struct strmbase_pin *avi_mux_get_pin(struct strmbase_filter *iface, unsigned int index)
106 AviMux *filter = impl_from_strmbase_filter(iface);
108 if (!index)
109 return &filter->source.pin;
110 else if (index <= filter->input_pin_no)
111 return &filter->in[index - 1]->pin.pin;
112 return NULL;
115 static void avi_mux_destroy(struct strmbase_filter *iface)
117 AviMux *filter = impl_from_strmbase_filter(iface);
118 int i;
120 strmbase_source_cleanup(&filter->source);
122 for (i = 0; i < filter->input_pin_no; ++i)
124 IPin_Disconnect(&filter->in[i]->pin.pin.IPin_iface);
125 IMemAllocator_Release(filter->in[i]->samples_allocator);
126 filter->in[i]->samples_allocator = NULL;
127 strmbase_sink_cleanup(&filter->in[i]->pin);
128 heap_free(filter->in[i]);
131 heap_free(filter->idx1);
132 strmbase_filter_cleanup(&filter->filter);
133 heap_free(filter);
134 ObjectRefCount(FALSE);
137 static HRESULT avi_mux_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
139 AviMux *filter = impl_from_strmbase_filter(iface);
141 if (IsEqualGUID(iid, &IID_IConfigAviMux))
142 *out = &filter->IConfigAviMux_iface;
143 else if (IsEqualGUID(iid, &IID_IConfigInterleaving))
144 *out = &filter->IConfigInterleaving_iface;
145 else if (IsEqualGUID(iid, &IID_IMediaSeeking))
146 *out = &filter->IMediaSeeking_iface;
147 else if (IsEqualGUID(iid, &IID_IPersistMediaPropertyBag))
148 *out = &filter->IPersistMediaPropertyBag_iface;
149 else if (IsEqualGUID(iid, &IID_ISpecifyPropertyPages))
150 *out = &filter->ISpecifyPropertyPages_iface;
151 else
152 return E_NOINTERFACE;
154 IUnknown_AddRef((IUnknown *)*out);
155 return S_OK;
158 static HRESULT out_flush(AviMux *This)
160 ULONG written;
161 HRESULT hr;
163 if(!This->buf_pos)
164 return S_OK;
166 hr = IStream_Write(This->stream, This->buf, This->buf_pos, &written);
167 if(FAILED(hr))
168 return hr;
169 if (written != This->buf_pos)
170 return E_FAIL;
172 This->buf_pos = 0;
173 return S_OK;
176 static HRESULT out_seek(AviMux *This, int pos)
178 LARGE_INTEGER li;
179 HRESULT hr;
181 hr = out_flush(This);
182 if(FAILED(hr))
183 return hr;
185 li.QuadPart = pos;
186 hr = IStream_Seek(This->stream, li, STREAM_SEEK_SET, NULL);
187 if(FAILED(hr))
188 return hr;
190 This->out_pos = pos;
191 if(This->out_pos > This->size)
192 This->size = This->out_pos;
193 return hr;
196 static HRESULT out_write(AviMux *This, const void *data, int size)
198 int chunk_size;
199 HRESULT hr;
201 while(1) {
202 if (size > sizeof(This->buf) - This->buf_pos)
203 chunk_size = sizeof(This->buf) - This->buf_pos;
204 else
205 chunk_size = size;
207 memcpy(This->buf + This->buf_pos, data, chunk_size);
208 size -= chunk_size;
209 data = (const BYTE*)data + chunk_size;
210 This->buf_pos += chunk_size;
211 This->out_pos += chunk_size;
212 if (This->out_pos > This->size)
213 This->size = This->out_pos;
215 if(!size)
216 break;
217 hr = out_flush(This);
218 if(FAILED(hr))
219 return hr;
222 return S_OK;
225 static inline HRESULT idx1_add_entry(AviMux *avimux, DWORD ckid, DWORD flags, DWORD off, DWORD len)
227 if(avimux->idx1_entries == avimux->idx1_size) {
228 AVIINDEXENTRY *new_idx = HeapReAlloc(GetProcessHeap(), 0, avimux->idx1,
229 sizeof(*avimux->idx1)*2*avimux->idx1_size);
230 if(!new_idx)
231 return E_OUTOFMEMORY;
233 avimux->idx1_size *= 2;
234 avimux->idx1 = new_idx;
237 avimux->idx1[avimux->idx1_entries].ckid = ckid;
238 avimux->idx1[avimux->idx1_entries].dwFlags = flags;
239 avimux->idx1[avimux->idx1_entries].dwChunkOffset = off;
240 avimux->idx1[avimux->idx1_entries].dwChunkLength = len;
241 avimux->idx1_entries++;
242 return S_OK;
245 static HRESULT flush_queue(AviMux *avimux, AviMuxIn *avimuxin, BOOL closing)
247 IMediaSample *sample, **prev, **head_prev;
248 BYTE *data;
249 RIFFCHUNK rf;
250 DWORD size;
251 DWORD flags;
252 HRESULT hr;
254 if (avimux->cur_stream != avimuxin->stream_id)
255 return S_OK;
257 while(avimuxin->samples_head) {
258 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
259 if(FAILED(hr))
260 return hr;
261 head_prev--;
263 hr = IMediaSample_GetPointer(*head_prev, (BYTE**)&prev);
264 if(FAILED(hr))
265 return hr;
266 prev--;
268 sample = *head_prev;
269 size = IMediaSample_GetActualDataLength(sample);
270 hr = IMediaSample_GetPointer(sample, &data);
271 if(FAILED(hr))
272 return hr;
273 flags = IMediaSample_IsDiscontinuity(sample)==S_OK ? AM_SAMPLE_TIMEDISCONTINUITY : 0;
274 if(IMediaSample_IsSyncPoint(sample) == S_OK)
275 flags |= AM_SAMPLE_SPLICEPOINT;
277 if (avimuxin->stream_time + (closing ? 0 : avimuxin->strh.dwScale) > avimux->cur_time
278 && !(flags & AM_SAMPLE_TIMEDISCONTINUITY))
280 if(closing)
281 break;
283 avimux->cur_stream++;
284 if(avimux->cur_stream >= avimux->input_pin_no-1) {
285 avimux->cur_time += avimux->interleave;
286 avimux->cur_stream = 0;
288 avimuxin = avimux->in[avimux->cur_stream];
289 continue;
292 if(avimuxin->ix->nEntriesInUse == AVISTDINDEX_ENTRIES) {
293 /* TODO: use output pins Deliver/Receive method */
294 hr = out_seek(avimux, avimuxin->ix_off);
295 if(FAILED(hr))
296 return hr;
297 hr = out_write(avimux, avimuxin->ix, sizeof(avimuxin->ix_data));
298 if(FAILED(hr))
299 return hr;
301 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].qwOffset = avimuxin->ix_off;
302 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwSize = sizeof(avimuxin->ix_data);
303 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwDuration = AVISTDINDEX_ENTRIES;
304 avimuxin->indx->nEntriesInUse++;
306 memset(avimuxin->ix->aIndex, 0, sizeof(avimuxin->ix->aIndex)*avimuxin->ix->nEntriesInUse);
307 avimuxin->ix->nEntriesInUse = 0;
308 avimuxin->ix->qwBaseOffset = 0;
310 avimuxin->ix_off = avimux->size;
311 avimux->size += sizeof(avimuxin->ix_data);
314 if(*head_prev == avimuxin->samples_head)
315 avimuxin->samples_head = NULL;
316 else
317 *head_prev = *prev;
319 avimuxin->stream_time += avimuxin->strh.dwScale;
320 avimuxin->strh.dwLength++;
321 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
322 if(!avimuxin->ix->qwBaseOffset)
323 avimuxin->ix->qwBaseOffset = avimux->size;
324 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwOffset =
325 avimux->size + sizeof(RIFFCHUNK) - avimuxin->ix->qwBaseOffset;
327 hr = out_seek(avimux, avimux->size);
328 if(FAILED(hr)) {
329 IMediaSample_Release(sample);
330 return hr;
333 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwSize = size |
334 (flags & AM_SAMPLE_SPLICEPOINT ? 0 : AVISTDINDEX_DELTAFRAME);
335 avimuxin->ix->nEntriesInUse++;
337 rf.fcc = FCC('0'+avimuxin->stream_id/10, '0'+avimuxin->stream_id%10,
338 'd', flags & AM_SAMPLE_SPLICEPOINT ? 'b' : 'c');
339 rf.cb = size;
340 hr = idx1_add_entry(avimux, rf.fcc, flags & AM_SAMPLE_SPLICEPOINT ? AVIIF_KEYFRAME : 0,
341 flags & AM_SAMPLE_TIMEDISCONTINUITY ?
342 avimux->idx1[avimux->idx1_entries-1].dwChunkOffset : avimux->size, size);
343 if(FAILED(hr)) {
344 IMediaSample_Release(sample);
345 return hr;
348 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
349 hr = out_write(avimux, &rf, sizeof(rf));
350 if(FAILED(hr)) {
351 IMediaSample_Release(sample);
352 return hr;
354 hr = out_write(avimux, data, size);
355 if(FAILED(hr)) {
356 IMediaSample_Release(sample);
357 return hr;
359 flags = 0;
360 hr = out_write(avimux, &flags, ALIGN(rf.cb)-rf.cb);
361 if(FAILED(hr)) {
362 IMediaSample_Release(sample);
363 return hr;
366 IMediaSample_Release(sample);
368 return S_OK;
371 static HRESULT queue_sample(AviMux *avimux, AviMuxIn *avimuxin, IMediaSample *sample)
373 IMediaSample **prev, **head_prev;
374 HRESULT hr;
376 hr = IMediaSample_GetPointer(sample, (BYTE**)&prev);
377 if(FAILED(hr))
378 return hr;
379 prev--;
381 if(avimuxin->samples_head) {
382 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
383 if(FAILED(hr))
384 return hr;
385 head_prev--;
387 *prev = *head_prev;
388 *head_prev = sample;
389 }else {
390 *prev = sample;
392 avimuxin->samples_head = sample;
393 IMediaSample_AddRef(sample);
395 return flush_queue(avimux, avimuxin, FALSE);
398 static HRESULT avi_mux_cleanup_stream(struct strmbase_filter *iface)
400 AviMux *This = impl_from_strmbase_filter(iface);
401 HRESULT hr;
402 int i;
404 if (This->stream)
406 AVIEXTHEADER dmlh;
407 RIFFCHUNK rc;
408 RIFFLIST rl;
409 int idx1_off, empty_stream;
411 empty_stream = This->cur_stream;
412 for(i=empty_stream+1; ; i++) {
413 if(i >= This->input_pin_no-1)
414 i = 0;
415 if(i == empty_stream)
416 break;
418 This->cur_stream = i;
419 hr = flush_queue(This, This->in[This->cur_stream], TRUE);
420 if(FAILED(hr))
421 return hr;
424 idx1_off = This->size;
425 rc.fcc = ckidAVIOLDINDEX;
426 rc.cb = This->idx1_entries * sizeof(*This->idx1);
427 hr = out_write(This, &rc, sizeof(rc));
428 if(FAILED(hr))
429 return hr;
430 hr = out_write(This, This->idx1, This->idx1_entries * sizeof(*This->idx1));
431 if(FAILED(hr))
432 return hr;
433 /* native writes 8 '\0' characters after the end of RIFF data */
434 i = 0;
435 hr = out_write(This, &i, sizeof(i));
436 if(FAILED(hr))
437 return hr;
438 hr = out_write(This, &i, sizeof(i));
439 if(FAILED(hr))
440 return hr;
442 for(i=0; i<This->input_pin_no; i++) {
443 if(!This->in[i]->pin.pin.peer)
444 continue;
446 hr = out_seek(This, This->in[i]->ix_off);
447 if(FAILED(hr))
448 return hr;
450 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].qwOffset = This->in[i]->ix_off;
451 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwSize = sizeof(This->in[i]->ix_data);
452 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration = This->in[i]->strh.dwLength;
453 if(This->in[i]->indx->nEntriesInUse) {
454 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration -=
455 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse-1].dwDuration;
457 This->in[i]->indx->nEntriesInUse++;
458 hr = out_write(This, This->in[i]->ix, sizeof(This->in[i]->ix_data));
459 if(FAILED(hr))
460 return hr;
463 hr = out_seek(This, 0);
464 if(FAILED(hr))
465 return hr;
467 rl.fcc = FCC('R','I','F','F');
468 rl.cb = This->size - sizeof(RIFFCHUNK) - 2 * sizeof(int);
469 rl.fccListType = FCC('A','V','I',' ');
470 hr = out_write(This, &rl, sizeof(rl));
471 if(FAILED(hr))
472 return hr;
474 rl.fcc = FCC('L','I','S','T');
475 rl.cb = This->movi_off - sizeof(RIFFLIST) - sizeof(RIFFCHUNK);
476 rl.fccListType = FCC('h','d','r','l');
477 hr = out_write(This, &rl, sizeof(rl));
478 if(FAILED(hr))
479 return hr;
481 /* FIXME: set This->avih.dwMaxBytesPerSec value */
482 This->avih.dwTotalFrames = (This->stop-This->start) / 10 / This->avih.dwMicroSecPerFrame;
483 hr = out_write(This, &This->avih, sizeof(This->avih));
484 if(FAILED(hr))
485 return hr;
487 for(i=0; i<This->input_pin_no; i++) {
488 if(!This->in[i]->pin.pin.peer)
489 continue;
491 rl.cb = sizeof(FOURCC) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK) +
492 This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
493 rl.fccListType = ckidSTREAMLIST;
494 hr = out_write(This, &rl, sizeof(rl));
495 if(FAILED(hr))
496 return hr;
498 hr = out_write(This, &This->in[i]->strh, sizeof(AVISTREAMHEADER));
499 if(FAILED(hr))
500 return hr;
502 hr = out_write(This, This->in[i]->strf, sizeof(RIFFCHUNK) + This->in[i]->strf->cb);
503 if(FAILED(hr))
504 return hr;
506 hr = out_write(This, This->in[i]->indx, sizeof(This->in[i]->indx_data));
507 if(FAILED(hr))
508 return hr;
511 rl.cb = sizeof(dmlh) + sizeof(FOURCC);
512 rl.fccListType = ckidODML;
513 hr = out_write(This, &rl, sizeof(rl));
514 if(FAILED(hr))
515 return hr;
517 memset(&dmlh, 0, sizeof(dmlh));
518 dmlh.fcc = ckidAVIEXTHEADER;
519 dmlh.cb = sizeof(dmlh) - sizeof(RIFFCHUNK);
520 dmlh.dwGrandFrames = This->in[0]->strh.dwLength;
521 hr = out_write(This, &dmlh, sizeof(dmlh));
523 rl.cb = idx1_off - This->movi_off - sizeof(RIFFCHUNK);
524 rl.fccListType = FCC('m','o','v','i');
525 out_write(This, &rl, sizeof(rl));
526 out_flush(This);
528 IStream_Release(This->stream);
529 This->stream = NULL;
532 return S_OK;
535 static HRESULT avi_mux_init_stream(struct strmbase_filter *iface)
537 AviMux *This = impl_from_strmbase_filter(iface);
538 HRESULT hr;
539 int i, stream_id;
541 if(This->mode != INTERLEAVE_FULL) {
542 FIXME("mode not supported (%d)\n", This->mode);
543 return E_NOTIMPL;
546 for(i=0; i<This->input_pin_no; i++) {
547 IMediaSeeking *ms;
548 LONGLONG cur, stop;
550 if(!This->in[i]->pin.pin.peer)
551 continue;
553 hr = IPin_QueryInterface(This->in[i]->pin.pin.peer,
554 &IID_IMediaSeeking, (void**)&ms);
555 if(FAILED(hr))
556 continue;
558 hr = IMediaSeeking_GetPositions(ms, &cur, &stop);
559 if(FAILED(hr)) {
560 IMediaSeeking_Release(ms);
561 continue;
564 FIXME("Use IMediaSeeking to fill stream header\n");
565 IMediaSeeking_Release(ms);
568 if (This->source.pMemInputPin)
570 hr = IMemInputPin_QueryInterface(This->source.pMemInputPin,
571 &IID_IStream, (void **)&This->stream);
572 if(FAILED(hr))
573 return hr;
576 This->idx1_entries = 0;
577 if(!This->idx1_size) {
578 This->idx1_size = 1024;
579 This->idx1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->idx1)*This->idx1_size);
580 if(!This->idx1)
581 return E_OUTOFMEMORY;
584 This->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER);
585 This->start = -1;
586 This->stop = -1;
587 memset(&This->avih, 0, sizeof(This->avih));
588 for(i=0; i<This->input_pin_no; i++) {
589 if(!This->in[i]->pin.pin.peer)
590 continue;
592 This->avih.dwStreams++;
593 This->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK)
594 + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
596 This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000);
597 This->in[i]->strh.dwRate = This->interleave;
599 hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator);
600 if(FAILED(hr)) {
601 if (This->stream)
603 IStream_Release(This->stream);
604 This->stream = NULL;
606 return hr;
610 This->movi_off = This->size;
611 This->size += sizeof(RIFFLIST);
613 idx1_add_entry(This, FCC('7','F','x','x'), 0, This->movi_off + sizeof(RIFFLIST), 0);
615 stream_id = 0;
616 for(i=0; i<This->input_pin_no; i++) {
617 if(!This->in[i]->pin.pin.peer)
618 continue;
620 This->in[i]->ix_off = This->size;
621 This->size += sizeof(This->in[i]->ix_data);
622 This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10);
623 This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK);
624 This->in[i]->ix->wLongsPerEntry = 2;
625 This->in[i]->ix->bIndexSubType = 0;
626 This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS;
627 This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b');
628 This->in[i]->ix->qwBaseOffset = 0;
630 This->in[i]->indx->fcc = ckidAVISUPERINDEX;
631 This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK);
632 This->in[i]->indx->wLongsPerEntry = 4;
633 This->in[i]->indx->bIndexSubType = 0;
634 This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES;
635 This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId;
636 This->in[i]->stream_id = stream_id++;
639 This->buf_pos = 0;
640 This->out_pos = 0;
642 This->avih.fcc = ckidMAINAVIHEADER;
643 This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK);
644 /* TODO: Use first video stream */
645 This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10;
646 This->avih.dwPaddingGranularity = 1;
647 This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX;
648 This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth;
649 This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight;
651 return S_OK;
654 static const struct strmbase_filter_ops filter_ops =
656 .filter_get_pin = avi_mux_get_pin,
657 .filter_destroy = avi_mux_destroy,
658 .filter_query_interface = avi_mux_query_interface,
659 .filter_init_stream = avi_mux_init_stream,
660 .filter_cleanup_stream = avi_mux_cleanup_stream,
663 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface)
665 return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface);
668 static HRESULT WINAPI ConfigAviMux_QueryInterface(
669 IConfigAviMux *iface, REFIID riid, void **ppv)
671 AviMux *This = impl_from_IConfigAviMux(iface);
672 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
675 static ULONG WINAPI ConfigAviMux_AddRef(IConfigAviMux *iface)
677 AviMux *This = impl_from_IConfigAviMux(iface);
678 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
681 static ULONG WINAPI ConfigAviMux_Release(IConfigAviMux *iface)
683 AviMux *This = impl_from_IConfigAviMux(iface);
684 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
687 static HRESULT WINAPI ConfigAviMux_SetMasterStream(IConfigAviMux *iface, LONG iStream)
689 AviMux *This = impl_from_IConfigAviMux(iface);
690 FIXME("(%p)->(%d)\n", This, iStream);
691 return E_NOTIMPL;
694 static HRESULT WINAPI ConfigAviMux_GetMasterStream(IConfigAviMux *iface, LONG *pStream)
696 AviMux *This = impl_from_IConfigAviMux(iface);
697 FIXME("(%p)->(%p)\n", This, pStream);
698 return E_NOTIMPL;
701 static HRESULT WINAPI ConfigAviMux_SetOutputCompatibilityIndex(
702 IConfigAviMux *iface, BOOL fOldIndex)
704 AviMux *This = impl_from_IConfigAviMux(iface);
705 FIXME("(%p)->(%x)\n", This, fOldIndex);
706 return E_NOTIMPL;
709 static HRESULT WINAPI ConfigAviMux_GetOutputCompatibilityIndex(
710 IConfigAviMux *iface, BOOL *pfOldIndex)
712 AviMux *This = impl_from_IConfigAviMux(iface);
713 FIXME("(%p)->(%p)\n", This, pfOldIndex);
714 return E_NOTIMPL;
717 static const IConfigAviMuxVtbl ConfigAviMuxVtbl = {
718 ConfigAviMux_QueryInterface,
719 ConfigAviMux_AddRef,
720 ConfigAviMux_Release,
721 ConfigAviMux_SetMasterStream,
722 ConfigAviMux_GetMasterStream,
723 ConfigAviMux_SetOutputCompatibilityIndex,
724 ConfigAviMux_GetOutputCompatibilityIndex
727 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface)
729 return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface);
732 static HRESULT WINAPI ConfigInterleaving_QueryInterface(
733 IConfigInterleaving *iface, REFIID riid, void **ppv)
735 AviMux *This = impl_from_IConfigInterleaving(iface);
736 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
739 static ULONG WINAPI ConfigInterleaving_AddRef(IConfigInterleaving *iface)
741 AviMux *This = impl_from_IConfigInterleaving(iface);
742 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
745 static ULONG WINAPI ConfigInterleaving_Release(IConfigInterleaving *iface)
747 AviMux *This = impl_from_IConfigInterleaving(iface);
748 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
751 static HRESULT WINAPI ConfigInterleaving_put_Mode(
752 IConfigInterleaving *iface, InterleavingMode mode)
754 AviMux *This = impl_from_IConfigInterleaving(iface);
756 TRACE("(%p)->(%d)\n", This, mode);
758 if(mode>INTERLEAVE_NONE_BUFFERED)
759 return E_INVALIDARG;
761 if(This->mode != mode) {
762 if(This->source.pin.peer) {
763 HRESULT hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
764 if(FAILED(hr))
765 return hr;
768 This->mode = mode;
771 return S_OK;
774 static HRESULT WINAPI ConfigInterleaving_get_Mode(
775 IConfigInterleaving *iface, InterleavingMode *pMode)
777 AviMux *This = impl_from_IConfigInterleaving(iface);
778 FIXME("(%p)->(%p)\n", This, pMode);
779 return E_NOTIMPL;
782 static HRESULT WINAPI ConfigInterleaving_put_Interleaving(IConfigInterleaving *iface,
783 const REFERENCE_TIME *prtInterleave, const REFERENCE_TIME *prtPreroll)
785 AviMux *This = impl_from_IConfigInterleaving(iface);
787 TRACE("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
789 if(prtInterleave)
790 This->interleave = *prtInterleave;
791 if(prtPreroll)
792 This->preroll = *prtPreroll;
793 return S_OK;
796 static HRESULT WINAPI ConfigInterleaving_get_Interleaving(IConfigInterleaving *iface,
797 REFERENCE_TIME *prtInterleave, REFERENCE_TIME *prtPreroll)
799 AviMux *This = impl_from_IConfigInterleaving(iface);
800 FIXME("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
801 return E_NOTIMPL;
804 static const IConfigInterleavingVtbl ConfigInterleavingVtbl = {
805 ConfigInterleaving_QueryInterface,
806 ConfigInterleaving_AddRef,
807 ConfigInterleaving_Release,
808 ConfigInterleaving_put_Mode,
809 ConfigInterleaving_get_Mode,
810 ConfigInterleaving_put_Interleaving,
811 ConfigInterleaving_get_Interleaving
814 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface)
816 return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface);
819 static HRESULT WINAPI MediaSeeking_QueryInterface(
820 IMediaSeeking *iface, REFIID riid, void **ppv)
822 AviMux *This = impl_from_IMediaSeeking(iface);
823 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
826 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
828 AviMux *This = impl_from_IMediaSeeking(iface);
829 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
832 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
834 AviMux *This = impl_from_IMediaSeeking(iface);
835 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
838 static HRESULT WINAPI MediaSeeking_GetCapabilities(
839 IMediaSeeking *iface, DWORD *pCapabilities)
841 AviMux *This = impl_from_IMediaSeeking(iface);
842 FIXME("(%p)->(%p)\n", This, pCapabilities);
843 return E_NOTIMPL;
846 static HRESULT WINAPI MediaSeeking_CheckCapabilities(
847 IMediaSeeking *iface, DWORD *pCapabilities)
849 AviMux *This = impl_from_IMediaSeeking(iface);
850 FIXME("(%p)->(%p)\n", This, pCapabilities);
851 return E_NOTIMPL;
854 static HRESULT WINAPI MediaSeeking_IsFormatSupported(
855 IMediaSeeking *iface, const GUID *pFormat)
857 AviMux *This = impl_from_IMediaSeeking(iface);
858 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
859 return E_NOTIMPL;
862 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(
863 IMediaSeeking *iface, GUID *pFormat)
865 AviMux *This = impl_from_IMediaSeeking(iface);
866 FIXME("(%p)->(%p)\n", This, pFormat);
867 return E_NOTIMPL;
870 static HRESULT WINAPI MediaSeeking_GetTimeFormat(
871 IMediaSeeking *iface, GUID *pFormat)
873 AviMux *This = impl_from_IMediaSeeking(iface);
874 FIXME("(%p)->(%p)\n", This, pFormat);
875 return E_NOTIMPL;
878 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(
879 IMediaSeeking *iface, const GUID *pFormat)
881 AviMux *This = impl_from_IMediaSeeking(iface);
882 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
883 return E_NOTIMPL;
886 static HRESULT WINAPI MediaSeeking_SetTimeFormat(
887 IMediaSeeking *iface, const GUID *pFormat)
889 AviMux *This = impl_from_IMediaSeeking(iface);
890 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
891 return E_NOTIMPL;
894 static HRESULT WINAPI MediaSeeking_GetDuration(
895 IMediaSeeking *iface, LONGLONG *pDuration)
897 AviMux *This = impl_from_IMediaSeeking(iface);
898 FIXME("(%p)->(%p)\n", This, pDuration);
899 return E_NOTIMPL;
902 static HRESULT WINAPI MediaSeeking_GetStopPosition(
903 IMediaSeeking *iface, LONGLONG *pStop)
905 AviMux *This = impl_from_IMediaSeeking(iface);
906 FIXME("(%p)->(%p)\n", This, pStop);
907 return E_NOTIMPL;
910 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(
911 IMediaSeeking *iface, LONGLONG *pCurrent)
913 AviMux *This = impl_from_IMediaSeeking(iface);
914 FIXME("(%p)->(%p)\n", This, pCurrent);
915 return E_NOTIMPL;
918 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
919 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
921 AviMux *This = impl_from_IMediaSeeking(iface);
922 FIXME("(%p)->(%p %s %s %s)\n", This, pTarget, debugstr_guid(pTargetFormat),
923 wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
924 return E_NOTIMPL;
927 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
928 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
930 AviMux *This = impl_from_IMediaSeeking(iface);
931 FIXME("(%p)->(%p %x %p %x)\n", This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
932 return E_NOTIMPL;
935 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
936 LONGLONG *pCurrent, LONGLONG *pStop)
938 AviMux *This = impl_from_IMediaSeeking(iface);
939 FIXME("(%p)->(%p %p)\n", This, pCurrent, pStop);
940 return E_NOTIMPL;
943 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
944 LONGLONG *pEarliest, LONGLONG *pLatest)
946 AviMux *This = impl_from_IMediaSeeking(iface);
947 FIXME("(%p)->(%p %p)\n", This, pEarliest, pLatest);
948 return E_NOTIMPL;
951 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
953 AviMux *This = impl_from_IMediaSeeking(iface);
954 FIXME("(%p)->(%lf)\n", This, dRate);
955 return E_NOTIMPL;
958 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
960 AviMux *This = impl_from_IMediaSeeking(iface);
961 FIXME("(%p)->(%p)\n", This, pdRate);
962 return E_NOTIMPL;
965 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
967 AviMux *This = impl_from_IMediaSeeking(iface);
968 FIXME("(%p)->(%p)\n", This, pllPreroll);
969 return E_NOTIMPL;
972 static const IMediaSeekingVtbl MediaSeekingVtbl = {
973 MediaSeeking_QueryInterface,
974 MediaSeeking_AddRef,
975 MediaSeeking_Release,
976 MediaSeeking_GetCapabilities,
977 MediaSeeking_CheckCapabilities,
978 MediaSeeking_IsFormatSupported,
979 MediaSeeking_QueryPreferredFormat,
980 MediaSeeking_GetTimeFormat,
981 MediaSeeking_IsUsingTimeFormat,
982 MediaSeeking_SetTimeFormat,
983 MediaSeeking_GetDuration,
984 MediaSeeking_GetStopPosition,
985 MediaSeeking_GetCurrentPosition,
986 MediaSeeking_ConvertTimeFormat,
987 MediaSeeking_SetPositions,
988 MediaSeeking_GetPositions,
989 MediaSeeking_GetAvailable,
990 MediaSeeking_SetRate,
991 MediaSeeking_GetRate,
992 MediaSeeking_GetPreroll
995 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface)
997 return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface);
1000 static HRESULT WINAPI PersistMediaPropertyBag_QueryInterface(
1001 IPersistMediaPropertyBag *iface, REFIID riid, void **ppv)
1003 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1004 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1007 static ULONG WINAPI PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag *iface)
1009 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1010 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1013 static ULONG WINAPI PersistMediaPropertyBag_Release(IPersistMediaPropertyBag *iface)
1015 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1016 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1019 static HRESULT WINAPI PersistMediaPropertyBag_GetClassID(
1020 IPersistMediaPropertyBag *iface, CLSID *pClassID)
1022 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1023 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID);
1026 static HRESULT WINAPI PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag *iface)
1028 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1029 FIXME("(%p)->()\n", This);
1030 return E_NOTIMPL;
1033 static HRESULT WINAPI PersistMediaPropertyBag_Load(IPersistMediaPropertyBag *iface,
1034 IMediaPropertyBag *pPropBag, IErrorLog *pErrorLog)
1036 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1037 FIXME("(%p)->()\n", This);
1038 return E_NOTIMPL;
1041 static HRESULT WINAPI PersistMediaPropertyBag_Save(IPersistMediaPropertyBag *iface,
1042 IMediaPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
1044 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1045 FIXME("(%p)->()\n", This);
1046 return E_NOTIMPL;
1049 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl = {
1050 PersistMediaPropertyBag_QueryInterface,
1051 PersistMediaPropertyBag_AddRef,
1052 PersistMediaPropertyBag_Release,
1053 PersistMediaPropertyBag_GetClassID,
1054 PersistMediaPropertyBag_InitNew,
1055 PersistMediaPropertyBag_Load,
1056 PersistMediaPropertyBag_Save
1059 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface)
1061 return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface);
1064 static HRESULT WINAPI SpecifyPropertyPages_QueryInterface(
1065 ISpecifyPropertyPages *iface, REFIID riid, void **ppv)
1067 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1068 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1071 static ULONG WINAPI SpecifyPropertyPages_AddRef(ISpecifyPropertyPages *iface)
1073 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1074 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1077 static ULONG WINAPI SpecifyPropertyPages_Release(ISpecifyPropertyPages *iface)
1079 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1080 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1083 static HRESULT WINAPI SpecifyPropertyPages_GetPages(
1084 ISpecifyPropertyPages *iface, CAUUID *pPages)
1086 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1087 FIXME("(%p)->(%p)\n", This, pPages);
1088 return E_NOTIMPL;
1091 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = {
1092 SpecifyPropertyPages_QueryInterface,
1093 SpecifyPropertyPages_AddRef,
1094 SpecifyPropertyPages_Release,
1095 SpecifyPropertyPages_GetPages
1098 static inline AviMux *impl_from_source_pin(struct strmbase_pin *iface)
1100 return CONTAINING_RECORD(iface, AviMux, source.pin);
1103 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
1105 AviMux *filter = impl_from_source_pin(iface);
1107 if (IsEqualGUID(iid, &IID_IQualityControl))
1108 *out = &filter->IQualityControl_iface;
1109 else
1110 return E_NOINTERFACE;
1112 IUnknown_AddRef((IUnknown *)*out);
1113 return S_OK;
1116 static HRESULT source_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *amt)
1118 FIXME("(%p) stub\n", base);
1119 return S_OK;
1122 static HRESULT WINAPI AviMuxOut_AttemptConnection(struct strmbase_source *iface,
1123 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1125 AviMux *filter = impl_from_source_pin(&iface->pin);
1126 PIN_DIRECTION dir;
1127 unsigned int i;
1128 HRESULT hr;
1130 hr = IPin_QueryDirection(pReceivePin, &dir);
1131 if(hr==S_OK && dir!=PINDIR_INPUT)
1132 return VFW_E_INVALID_DIRECTION;
1134 if (FAILED(hr = BaseOutputPinImpl_AttemptConnection(iface, pReceivePin, pmt)))
1135 return hr;
1137 for (i = 0; i < filter->input_pin_no; ++i)
1139 if (!filter->in[i]->pin.pin.peer)
1140 continue;
1142 hr = IFilterGraph_Reconnect(filter->filter.graph, &filter->in[i]->pin.pin.IPin_iface);
1143 if (FAILED(hr))
1145 IPin_Disconnect(&iface->pin.IPin_iface);
1146 break;
1150 return hr;
1153 static HRESULT source_get_media_type(struct strmbase_pin *base, unsigned int iPosition, AM_MEDIA_TYPE *amt)
1155 TRACE("(%p)->(%d %p)\n", base, iPosition, amt);
1157 if(iPosition > 0)
1158 return VFW_S_NO_MORE_ITEMS;
1160 amt->majortype = MEDIATYPE_Stream;
1161 amt->subtype = MEDIASUBTYPE_Avi;
1162 amt->bFixedSizeSamples = TRUE;
1163 amt->bTemporalCompression = FALSE;
1164 amt->lSampleSize = 1;
1165 amt->formattype = GUID_NULL;
1166 amt->pUnk = NULL;
1167 amt->cbFormat = 0;
1168 amt->pbFormat = NULL;
1169 return S_OK;
1172 static HRESULT WINAPI AviMuxOut_DecideAllocator(struct strmbase_source *base,
1173 IMemInputPin *pPin, IMemAllocator **pAlloc)
1175 ALLOCATOR_PROPERTIES req, actual;
1176 HRESULT hr;
1178 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc);
1180 hr = BaseOutputPinImpl_InitAllocator(base, pAlloc);
1181 if(FAILED(hr))
1182 return hr;
1184 hr = IMemInputPin_GetAllocatorRequirements(pPin, &req);
1185 if(FAILED(hr))
1186 req.cbAlign = 1;
1187 req.cBuffers = 32;
1188 req.cbBuffer = 0;
1189 req.cbPrefix = 0;
1191 hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual);
1192 if(FAILED(hr))
1193 return hr;
1195 return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE);
1198 static const struct strmbase_source_ops source_ops =
1200 .base.pin_query_interface = source_query_interface,
1201 .base.pin_query_accept = source_query_accept,
1202 .base.pin_get_media_type = source_get_media_type,
1203 .pfnAttemptConnection = AviMuxOut_AttemptConnection,
1204 .pfnDecideAllocator = AviMuxOut_DecideAllocator,
1207 static inline AviMux* impl_from_out_IQualityControl(IQualityControl *iface)
1209 return CONTAINING_RECORD(iface, AviMux, IQualityControl_iface);
1212 static HRESULT WINAPI AviMuxOut_QualityControl_QueryInterface(
1213 IQualityControl *iface, REFIID riid, void **ppv)
1215 AviMux *This = impl_from_out_IQualityControl(iface);
1216 return IPin_QueryInterface(&This->source.pin.IPin_iface, riid, ppv);
1219 static ULONG WINAPI AviMuxOut_QualityControl_AddRef(IQualityControl *iface)
1221 AviMux *This = impl_from_out_IQualityControl(iface);
1222 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1225 static ULONG WINAPI AviMuxOut_QualityControl_Release(IQualityControl *iface)
1227 AviMux *This = impl_from_out_IQualityControl(iface);
1228 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1231 static HRESULT WINAPI AviMuxOut_QualityControl_Notify(IQualityControl *iface,
1232 IBaseFilter *pSelf, Quality q)
1234 AviMux *This = impl_from_out_IQualityControl(iface);
1235 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This, pSelf,
1236 q.Type, q.Proportion,
1237 wine_dbgstr_longlong(q.Late),
1238 wine_dbgstr_longlong(q.TimeStamp));
1239 return E_NOTIMPL;
1242 static HRESULT WINAPI AviMuxOut_QualityControl_SetSink(
1243 IQualityControl *iface, IQualityControl *piqc)
1245 AviMux *This = impl_from_out_IQualityControl(iface);
1246 FIXME("(%p)->(%p)\n", This, piqc);
1247 return E_NOTIMPL;
1250 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl = {
1251 AviMuxOut_QualityControl_QueryInterface,
1252 AviMuxOut_QualityControl_AddRef,
1253 AviMuxOut_QualityControl_Release,
1254 AviMuxOut_QualityControl_Notify,
1255 AviMuxOut_QualityControl_SetSink
1258 static inline AviMuxIn *impl_sink_from_strmbase_pin(struct strmbase_pin *iface)
1260 return CONTAINING_RECORD(iface, AviMuxIn, pin.pin);
1263 static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
1265 AviMuxIn *pin = impl_sink_from_strmbase_pin(iface);
1267 if (IsEqualGUID(iid, &IID_IAMStreamControl))
1268 *out = &pin->IAMStreamControl_iface;
1269 else if (IsEqualGUID(iid, &IID_IMemInputPin))
1270 *out = &pin->pin.IMemInputPin_iface;
1271 else if (IsEqualGUID(iid, &IID_IPropertyBag))
1272 *out = &pin->IPropertyBag_iface;
1273 else if (IsEqualGUID(iid, &IID_IQualityControl))
1274 *out = &pin->IQualityControl_iface;
1275 else
1276 return E_NOINTERFACE;
1278 IUnknown_AddRef((IUnknown *)*out);
1279 return S_OK;
1282 static HRESULT sink_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *pmt)
1284 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) &&
1285 IsEqualIID(&pmt->formattype, &FORMAT_WaveFormatEx))
1286 return S_OK;
1287 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Interleaved) &&
1288 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo))
1289 return S_OK;
1290 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1291 (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo) ||
1292 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo)))
1293 return S_OK;
1294 return S_FALSE;
1297 static HRESULT WINAPI AviMuxIn_Receive(struct strmbase_sink *base, IMediaSample *pSample)
1299 AviMux *avimux = impl_from_strmbase_filter(base->pin.filter);
1300 AviMuxIn *avimuxin = CONTAINING_RECORD(base, AviMuxIn, pin);
1301 REFERENCE_TIME start, stop;
1302 IMediaSample *sample;
1303 int frames_no;
1304 IMediaSample2 *ms2;
1305 BYTE *frame, *buf;
1306 DWORD max_size, size;
1307 DWORD flags;
1308 HRESULT hr;
1310 TRACE("pin %p, pSample %p.\n", avimuxin, pSample);
1312 hr = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&ms2);
1313 if(SUCCEEDED(hr)) {
1314 AM_SAMPLE2_PROPERTIES props;
1316 memset(&props, 0, sizeof(props));
1317 hr = IMediaSample2_GetProperties(ms2, sizeof(props), (BYTE*)&props);
1318 IMediaSample2_Release(ms2);
1319 if(FAILED(hr))
1320 return hr;
1322 flags = props.dwSampleFlags;
1323 frame = props.pbBuffer;
1324 size = props.lActual;
1325 }else {
1326 flags = IMediaSample_IsSyncPoint(pSample) == S_OK ? AM_SAMPLE_SPLICEPOINT : 0;
1327 hr = IMediaSample_GetPointer(pSample, &frame);
1328 if(FAILED(hr))
1329 return hr;
1330 size = IMediaSample_GetActualDataLength(pSample);
1333 if(!avimuxin->pin.pin.mt.bTemporalCompression)
1334 flags |= AM_SAMPLE_SPLICEPOINT;
1336 hr = IMediaSample_GetTime(pSample, &start, &stop);
1337 if(FAILED(hr))
1338 return hr;
1340 if(avimuxin->stop>stop)
1341 return VFW_E_START_TIME_AFTER_END;
1343 if(avimux->start == -1)
1344 avimux->start = start;
1345 if(avimux->stop < stop)
1346 avimux->stop = stop;
1348 if(avimux->avih.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1349 avimux->avih.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1350 if(avimuxin->strh.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1351 avimuxin->strh.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1353 frames_no = 1;
1354 if(avimuxin->stop!=-1 && start > avimuxin->stop) {
1355 frames_no += (double)(start - avimuxin->stop) / 10000000
1356 * avimuxin->strh.dwRate / avimuxin->strh.dwScale + 0.5;
1358 avimuxin->stop = stop;
1360 while(--frames_no) {
1361 /* TODO: store all control frames in one buffer */
1362 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1363 if(FAILED(hr))
1364 return hr;
1365 hr = IMediaSample_SetActualDataLength(sample, 0);
1366 if(SUCCEEDED(hr))
1367 hr = IMediaSample_SetDiscontinuity(sample, TRUE);
1368 if(SUCCEEDED(hr))
1369 hr = IMediaSample_SetSyncPoint(sample, FALSE);
1370 if(SUCCEEDED(hr))
1371 hr = queue_sample(avimux, avimuxin, sample);
1372 IMediaSample_Release(sample);
1373 if(FAILED(hr))
1374 return hr;
1377 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1378 if(FAILED(hr))
1379 return hr;
1380 max_size = IMediaSample_GetSize(sample);
1381 if(size > max_size)
1382 size = max_size;
1383 hr = IMediaSample_SetActualDataLength(sample, size);
1384 if(SUCCEEDED(hr))
1385 hr = IMediaSample_SetDiscontinuity(sample, FALSE);
1386 if(SUCCEEDED(hr))
1387 hr = IMediaSample_SetSyncPoint(sample, flags & AM_SAMPLE_SPLICEPOINT);
1388 /* TODO: avoid unnecessary copying */
1389 if(SUCCEEDED(hr))
1390 hr = IMediaSample_GetPointer(sample, &buf);
1391 if(SUCCEEDED(hr)) {
1392 memcpy(buf, frame, size);
1393 hr = queue_sample(avimux, avimuxin, sample);
1395 IMediaSample_Release(sample);
1397 return hr;
1400 static HRESULT avi_mux_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt)
1402 AviMuxIn *avimuxin = impl_sink_from_strmbase_pin(&iface->pin);
1403 AviMux *This = impl_from_strmbase_filter(iface->pin.filter);
1404 HRESULT hr;
1406 if(!pmt)
1407 return E_POINTER;
1409 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1410 IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
1411 ALLOCATOR_PROPERTIES req, act;
1412 VIDEOINFOHEADER *vih;
1413 int size;
1415 vih = (VIDEOINFOHEADER*)pmt->pbFormat;
1416 avimuxin->strh.fcc = ckidSTREAMHEADER;
1417 avimuxin->strh.cb = sizeof(AVISTREAMHEADER) - FIELD_OFFSET(AVISTREAMHEADER, fccType);
1418 avimuxin->strh.fccType = streamtypeVIDEO;
1419 /* FIXME: fccHandler should be set differently */
1420 avimuxin->strh.fccHandler = vih->bmiHeader.biCompression ?
1421 vih->bmiHeader.biCompression : FCC('D','I','B',' ');
1422 avimuxin->avg_time_per_frame = vih->AvgTimePerFrame;
1423 avimuxin->stop = -1;
1425 req.cBuffers = 32;
1426 req.cbBuffer = vih->bmiHeader.biSizeImage;
1427 req.cbAlign = 1;
1428 req.cbPrefix = sizeof(void*);
1429 hr = IMemAllocator_SetProperties(avimuxin->samples_allocator, &req, &act);
1430 if(SUCCEEDED(hr))
1431 hr = IMemAllocator_Commit(avimuxin->samples_allocator);
1432 if (FAILED(hr))
1433 return hr;
1435 size = pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
1436 avimuxin->strf = CoTaskMemAlloc(sizeof(RIFFCHUNK) + ALIGN(FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed])));
1437 avimuxin->strf->fcc = ckidSTREAMFORMAT;
1438 avimuxin->strf->cb = FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]);
1439 if(size > avimuxin->strf->cb)
1440 size = avimuxin->strf->cb;
1441 memcpy(avimuxin->strf->data, &vih->bmiHeader, size);
1442 }else {
1443 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt->majortype),
1444 debugstr_guid(&pmt->formattype));
1445 return E_NOTIMPL;
1448 return create_input_pin(This);
1451 static void avi_mux_sink_disconnect(struct strmbase_sink *iface)
1453 AviMuxIn *avimuxin = impl_sink_from_strmbase_pin(&iface->pin);
1454 IMediaSample **prev, *cur;
1456 IMemAllocator_Decommit(avimuxin->samples_allocator);
1457 while(avimuxin->samples_head) {
1458 cur = avimuxin->samples_head;
1459 if (FAILED(IMediaSample_GetPointer(cur, (BYTE **)&prev)))
1460 break;
1461 prev--;
1463 cur = avimuxin->samples_head;
1464 avimuxin->samples_head = *prev;
1465 IMediaSample_Release(cur);
1467 if(cur == avimuxin->samples_head)
1468 avimuxin->samples_head = NULL;
1470 CoTaskMemFree(avimuxin->strf);
1471 avimuxin->strf = NULL;
1474 static const struct strmbase_sink_ops sink_ops =
1476 .base.pin_query_interface = sink_query_interface,
1477 .base.pin_query_accept = sink_query_accept,
1478 .base.pin_get_media_type = strmbase_pin_get_media_type,
1479 .pfnReceive = AviMuxIn_Receive,
1480 .sink_connect = avi_mux_sink_connect,
1481 .sink_disconnect = avi_mux_sink_disconnect,
1484 static inline AviMux* impl_from_in_IPin(IPin *iface)
1486 struct strmbase_pin *pin = CONTAINING_RECORD(iface, struct strmbase_pin, IPin_iface);
1487 return impl_from_strmbase_filter(pin->filter);
1490 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface)
1492 return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface);
1495 static HRESULT WINAPI AviMuxIn_AMStreamControl_QueryInterface(
1496 IAMStreamControl *iface, REFIID riid, void **ppv)
1498 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1499 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1502 static ULONG WINAPI AviMuxIn_AMStreamControl_AddRef(IAMStreamControl *iface)
1504 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1505 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1506 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1509 static ULONG WINAPI AviMuxIn_AMStreamControl_Release(IAMStreamControl *iface)
1511 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1512 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1513 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1516 static HRESULT WINAPI AviMuxIn_AMStreamControl_StartAt(IAMStreamControl *iface,
1517 const REFERENCE_TIME *start, DWORD cookie)
1519 FIXME("iface %p, start %p, cookie %#x, stub!\n", iface, start, cookie);
1520 return E_NOTIMPL;
1523 static HRESULT WINAPI AviMuxIn_AMStreamControl_StopAt(IAMStreamControl *iface,
1524 const REFERENCE_TIME *stop, BOOL send_extra, DWORD cookie)
1526 FIXME("iface %p, stop %p, send_extra %d, cookie %#x, stub!\n", iface, stop, send_extra, cookie);
1527 return E_NOTIMPL;
1530 static HRESULT WINAPI AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl *iface,
1531 AM_STREAM_INFO *info)
1533 FIXME("iface %p, info %p, stub!\n", iface, info);
1534 return E_NOTIMPL;
1537 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl = {
1538 AviMuxIn_AMStreamControl_QueryInterface,
1539 AviMuxIn_AMStreamControl_AddRef,
1540 AviMuxIn_AMStreamControl_Release,
1541 AviMuxIn_AMStreamControl_StartAt,
1542 AviMuxIn_AMStreamControl_StopAt,
1543 AviMuxIn_AMStreamControl_GetInfo
1546 static inline AviMuxIn* AviMuxIn_from_IMemInputPin(IMemInputPin *iface)
1548 return CONTAINING_RECORD(iface, AviMuxIn, pin.IMemInputPin_iface);
1551 static HRESULT WINAPI AviMuxIn_MemInputPin_QueryInterface(
1552 IMemInputPin *iface, REFIID riid, void **ppv)
1554 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1555 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1558 static ULONG WINAPI AviMuxIn_MemInputPin_AddRef(IMemInputPin *iface)
1560 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1561 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1562 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1565 static ULONG WINAPI AviMuxIn_MemInputPin_Release(IMemInputPin *iface)
1567 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1568 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1569 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1572 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocator(
1573 IMemInputPin *iface, IMemAllocator **ppAllocator)
1575 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1577 TRACE("pin %p, ppAllocator %p.\n", avimuxin, ppAllocator);
1579 if(!ppAllocator)
1580 return E_POINTER;
1582 IMemAllocator_AddRef(avimuxin->pin.pAllocator);
1583 *ppAllocator = avimuxin->pin.pAllocator;
1584 return S_OK;
1587 static HRESULT WINAPI AviMuxIn_MemInputPin_NotifyAllocator(
1588 IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly)
1590 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1591 ALLOCATOR_PROPERTIES props;
1592 HRESULT hr;
1594 TRACE("pin %p, pAllocator %p, bReadOnly %d.\n", avimuxin, pAllocator, bReadOnly);
1596 if(!pAllocator)
1597 return E_POINTER;
1599 memset(&props, 0, sizeof(props));
1600 hr = IMemAllocator_GetProperties(pAllocator, &props);
1601 if(FAILED(hr))
1602 return hr;
1604 props.cbAlign = 1;
1605 props.cbPrefix = 8;
1606 return IMemAllocator_SetProperties(avimuxin->pin.pAllocator, &props, &props);
1609 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocatorRequirements(
1610 IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps)
1612 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1614 TRACE("pin %p, pProps %p.\n", avimuxin, pProps);
1616 if(!pProps)
1617 return E_POINTER;
1619 pProps->cbAlign = 1;
1620 pProps->cbPrefix = 8;
1621 return S_OK;
1624 static HRESULT WINAPI AviMuxIn_MemInputPin_Receive(
1625 IMemInputPin *iface, IMediaSample *pSample)
1627 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1629 TRACE("pin %p, pSample %p.\n", avimuxin, pSample);
1631 return avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSample);
1634 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin *iface,
1635 IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed)
1637 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1638 HRESULT hr = S_OK;
1640 TRACE("pin %p, pSamples %p, nSamples %d, nSamplesProcessed %p.\n",
1641 avimuxin, pSamples, nSamples, nSamplesProcessed);
1643 for(*nSamplesProcessed=0; *nSamplesProcessed<nSamples; (*nSamplesProcessed)++)
1645 hr = avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSamples[*nSamplesProcessed]);
1646 if(hr != S_OK)
1647 break;
1650 return hr;
1653 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1655 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1656 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1657 HRESULT hr;
1659 TRACE("avimuxin %p.\n", avimuxin);
1661 if(!This->source.pMemInputPin)
1662 return S_FALSE;
1664 hr = IMemInputPin_ReceiveCanBlock(This->source.pMemInputPin);
1665 return hr != S_FALSE ? S_OK : S_FALSE;
1668 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl = {
1669 AviMuxIn_MemInputPin_QueryInterface,
1670 AviMuxIn_MemInputPin_AddRef,
1671 AviMuxIn_MemInputPin_Release,
1672 AviMuxIn_MemInputPin_GetAllocator,
1673 AviMuxIn_MemInputPin_NotifyAllocator,
1674 AviMuxIn_MemInputPin_GetAllocatorRequirements,
1675 AviMuxIn_MemInputPin_Receive,
1676 AviMuxIn_MemInputPin_ReceiveMultiple,
1677 AviMuxIn_MemInputPin_ReceiveCanBlock
1680 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface)
1682 return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface);
1685 static HRESULT WINAPI AviMuxIn_PropertyBag_QueryInterface(
1686 IPropertyBag *iface, REFIID riid, void **ppv)
1688 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1689 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1692 static ULONG WINAPI AviMuxIn_PropertyBag_AddRef(IPropertyBag *iface)
1694 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1695 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1696 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1699 static ULONG WINAPI AviMuxIn_PropertyBag_Release(IPropertyBag *iface)
1701 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1702 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1703 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1706 static HRESULT WINAPI AviMuxIn_PropertyBag_Read(IPropertyBag *iface,
1707 const WCHAR *name, VARIANT *value, IErrorLog *error_log)
1709 FIXME("iface %p, name %s, value %p, error_log %p, stub!\n",
1710 iface, debugstr_w(name), value, error_log);
1711 return E_NOTIMPL;
1714 static HRESULT WINAPI AviMuxIn_PropertyBag_Write(IPropertyBag *iface,
1715 const WCHAR *name, VARIANT *value)
1717 FIXME("iface %p, name %s, value %s, stub!\n",
1718 iface, debugstr_w(name), debugstr_variant(value));
1719 return E_NOTIMPL;
1722 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl = {
1723 AviMuxIn_PropertyBag_QueryInterface,
1724 AviMuxIn_PropertyBag_AddRef,
1725 AviMuxIn_PropertyBag_Release,
1726 AviMuxIn_PropertyBag_Read,
1727 AviMuxIn_PropertyBag_Write
1730 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface)
1732 return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface);
1735 static HRESULT WINAPI AviMuxIn_QualityControl_QueryInterface(
1736 IQualityControl *iface, REFIID riid, void **ppv)
1738 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1739 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1742 static ULONG WINAPI AviMuxIn_QualityControl_AddRef(IQualityControl *iface)
1744 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1745 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1746 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1749 static ULONG WINAPI AviMuxIn_QualityControl_Release(IQualityControl *iface)
1751 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1752 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1753 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1756 static HRESULT WINAPI AviMuxIn_QualityControl_Notify(IQualityControl *iface,
1757 IBaseFilter *filter, Quality q)
1759 FIXME("iface %p, filter %p, type %u, proportion %d, late %s, timestamp %s, stub!\n",
1760 iface, filter, q.Type, q.Proportion, wine_dbgstr_longlong(q.Late),
1761 wine_dbgstr_longlong(q.TimeStamp));
1762 return E_NOTIMPL;
1765 static HRESULT WINAPI AviMuxIn_QualityControl_SetSink(IQualityControl *iface, IQualityControl *sink)
1767 FIXME("iface %p, sink %p, stub!\n", iface, sink);
1768 return E_NOTIMPL;
1771 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl = {
1772 AviMuxIn_QualityControl_QueryInterface,
1773 AviMuxIn_QualityControl_AddRef,
1774 AviMuxIn_QualityControl_Release,
1775 AviMuxIn_QualityControl_Notify,
1776 AviMuxIn_QualityControl_SetSink
1779 static HRESULT create_input_pin(AviMux *avimux)
1781 WCHAR name[] = {'I','n','p','u','t',' ','0','0',0};
1782 AviMuxIn *object;
1783 HRESULT hr;
1785 if(avimux->input_pin_no >= MAX_PIN_NO-1)
1786 return E_FAIL;
1788 name[7] = '0' + (avimux->input_pin_no+1) % 10;
1789 name[6] = '0' + (avimux->input_pin_no+1) / 10;
1791 if (!(object = heap_alloc_zero(sizeof(*object))))
1792 return E_OUTOFMEMORY;
1794 strmbase_sink_init(&object->pin, &avimux->filter, name, &sink_ops, NULL);
1795 object->pin.IMemInputPin_iface.lpVtbl = &AviMuxIn_MemInputPinVtbl;
1796 object->IAMStreamControl_iface.lpVtbl = &AviMuxIn_AMStreamControlVtbl;
1797 object->IPropertyBag_iface.lpVtbl = &AviMuxIn_PropertyBagVtbl;
1798 object->IQualityControl_iface.lpVtbl = &AviMuxIn_QualityControlVtbl;
1800 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
1801 &IID_IMemAllocator, (void **)&object->samples_allocator);
1802 if (FAILED(hr))
1804 strmbase_sink_cleanup(&object->pin);
1805 heap_free(object);
1806 return hr;
1809 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
1810 &IID_IMemAllocator, (void **)&object->pin.pAllocator);
1811 if (FAILED(hr))
1813 IMemAllocator_Release(object->samples_allocator);
1814 strmbase_sink_cleanup(&object->pin);
1815 heap_free(object);
1816 return hr;
1819 object->indx = (AVISUPERINDEX *)&object->indx_data;
1820 object->ix = (AVISTDINDEX *)object->ix_data;
1822 avimux->in[avimux->input_pin_no++] = object;
1823 return S_OK;
1826 HRESULT avi_mux_create(IUnknown *outer, IUnknown **out)
1828 static const WCHAR output_name[] = {'A','V','I',' ','O','u','t',0};
1830 AviMux *avimux;
1831 PIN_INFO info;
1832 HRESULT hr;
1834 if (!(avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux))))
1835 return E_OUTOFMEMORY;
1837 strmbase_filter_init(&avimux->filter, outer, &CLSID_AviDest, &filter_ops);
1838 avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl;
1839 avimux->IConfigInterleaving_iface.lpVtbl = &ConfigInterleavingVtbl;
1840 avimux->IMediaSeeking_iface.lpVtbl = &MediaSeekingVtbl;
1841 avimux->IPersistMediaPropertyBag_iface.lpVtbl = &PersistMediaPropertyBagVtbl;
1842 avimux->ISpecifyPropertyPages_iface.lpVtbl = &SpecifyPropertyPagesVtbl;
1844 info.dir = PINDIR_OUTPUT;
1845 info.pFilter = &avimux->filter.IBaseFilter_iface;
1846 lstrcpyW(info.achName, output_name);
1847 strmbase_source_init(&avimux->source, &avimux->filter, output_name, &source_ops);
1848 avimux->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl;
1849 avimux->cur_stream = 0;
1850 avimux->cur_time = 0;
1851 avimux->stream = NULL;
1853 hr = create_input_pin(avimux);
1854 if(FAILED(hr)) {
1855 strmbase_source_cleanup(&avimux->source);
1856 strmbase_filter_cleanup(&avimux->filter);
1857 HeapFree(GetProcessHeap(), 0, avimux);
1858 return hr;
1861 avimux->interleave = 10000000;
1863 TRACE("Created AVI mux %p.\n", avimux);
1864 ObjectRefCount(TRUE);
1865 *out = &avimux->filter.IUnknown_inner;
1866 return S_OK;