mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / qcap / avimux.c
blob0fcf5b8402a445a762ed1375c6c0bfc7c4703506
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 free(filter->in[i]);
131 free(filter->idx1);
132 strmbase_filter_cleanup(&filter->filter);
133 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 = realloc(avimux->idx1, sizeof(*avimux->idx1) * 2 * avimux->idx1_size);
229 if(!new_idx)
230 return E_OUTOFMEMORY;
232 avimux->idx1_size *= 2;
233 avimux->idx1 = new_idx;
236 avimux->idx1[avimux->idx1_entries].ckid = ckid;
237 avimux->idx1[avimux->idx1_entries].dwFlags = flags;
238 avimux->idx1[avimux->idx1_entries].dwChunkOffset = off;
239 avimux->idx1[avimux->idx1_entries].dwChunkLength = len;
240 avimux->idx1_entries++;
241 return S_OK;
244 static HRESULT flush_queue(AviMux *avimux, AviMuxIn *avimuxin, BOOL closing)
246 IMediaSample *sample, **prev, **head_prev;
247 BYTE *data;
248 RIFFCHUNK rf;
249 DWORD size;
250 DWORD flags;
251 HRESULT hr;
253 if (avimux->cur_stream != avimuxin->stream_id)
254 return S_OK;
256 while(avimuxin->samples_head) {
257 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
258 if(FAILED(hr))
259 return hr;
260 head_prev--;
262 hr = IMediaSample_GetPointer(*head_prev, (BYTE**)&prev);
263 if(FAILED(hr))
264 return hr;
265 prev--;
267 sample = *head_prev;
268 size = IMediaSample_GetActualDataLength(sample);
269 hr = IMediaSample_GetPointer(sample, &data);
270 if(FAILED(hr))
271 return hr;
272 flags = IMediaSample_IsDiscontinuity(sample)==S_OK ? AM_SAMPLE_TIMEDISCONTINUITY : 0;
273 if(IMediaSample_IsSyncPoint(sample) == S_OK)
274 flags |= AM_SAMPLE_SPLICEPOINT;
276 if (avimuxin->stream_time + (closing ? 0 : avimuxin->strh.dwScale) > avimux->cur_time
277 && !(flags & AM_SAMPLE_TIMEDISCONTINUITY))
279 if(closing)
280 break;
282 avimux->cur_stream++;
283 if(avimux->cur_stream >= avimux->input_pin_no-1) {
284 avimux->cur_time += avimux->interleave;
285 avimux->cur_stream = 0;
287 avimuxin = avimux->in[avimux->cur_stream];
288 continue;
291 if(avimuxin->ix->nEntriesInUse == AVISTDINDEX_ENTRIES) {
292 /* TODO: use output pins Deliver/Receive method */
293 hr = out_seek(avimux, avimuxin->ix_off);
294 if(FAILED(hr))
295 return hr;
296 hr = out_write(avimux, avimuxin->ix, sizeof(avimuxin->ix_data));
297 if(FAILED(hr))
298 return hr;
300 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].qwOffset = avimuxin->ix_off;
301 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwSize = sizeof(avimuxin->ix_data);
302 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwDuration = AVISTDINDEX_ENTRIES;
303 avimuxin->indx->nEntriesInUse++;
305 memset(avimuxin->ix->aIndex, 0, sizeof(avimuxin->ix->aIndex)*avimuxin->ix->nEntriesInUse);
306 avimuxin->ix->nEntriesInUse = 0;
307 avimuxin->ix->qwBaseOffset = 0;
309 avimuxin->ix_off = avimux->size;
310 avimux->size += sizeof(avimuxin->ix_data);
313 if(*head_prev == avimuxin->samples_head)
314 avimuxin->samples_head = NULL;
315 else
316 *head_prev = *prev;
318 avimuxin->stream_time += avimuxin->strh.dwScale;
319 avimuxin->strh.dwLength++;
320 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
321 if(!avimuxin->ix->qwBaseOffset)
322 avimuxin->ix->qwBaseOffset = avimux->size;
323 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwOffset =
324 avimux->size + sizeof(RIFFCHUNK) - avimuxin->ix->qwBaseOffset;
326 hr = out_seek(avimux, avimux->size);
327 if(FAILED(hr)) {
328 IMediaSample_Release(sample);
329 return hr;
332 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwSize = size |
333 (flags & AM_SAMPLE_SPLICEPOINT ? 0 : AVISTDINDEX_DELTAFRAME);
334 avimuxin->ix->nEntriesInUse++;
336 rf.fcc = FCC('0'+avimuxin->stream_id/10, '0'+avimuxin->stream_id%10,
337 'd', flags & AM_SAMPLE_SPLICEPOINT ? 'b' : 'c');
338 rf.cb = size;
339 hr = idx1_add_entry(avimux, rf.fcc, flags & AM_SAMPLE_SPLICEPOINT ? AVIIF_KEYFRAME : 0,
340 flags & AM_SAMPLE_TIMEDISCONTINUITY ?
341 avimux->idx1[avimux->idx1_entries-1].dwChunkOffset : avimux->size, size);
342 if(FAILED(hr)) {
343 IMediaSample_Release(sample);
344 return hr;
347 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
348 hr = out_write(avimux, &rf, sizeof(rf));
349 if(FAILED(hr)) {
350 IMediaSample_Release(sample);
351 return hr;
353 hr = out_write(avimux, data, size);
354 if(FAILED(hr)) {
355 IMediaSample_Release(sample);
356 return hr;
358 flags = 0;
359 hr = out_write(avimux, &flags, ALIGN(rf.cb)-rf.cb);
360 if(FAILED(hr)) {
361 IMediaSample_Release(sample);
362 return hr;
365 IMediaSample_Release(sample);
367 return S_OK;
370 static HRESULT queue_sample(AviMux *avimux, AviMuxIn *avimuxin, IMediaSample *sample)
372 IMediaSample **prev, **head_prev;
373 HRESULT hr;
375 hr = IMediaSample_GetPointer(sample, (BYTE**)&prev);
376 if(FAILED(hr))
377 return hr;
378 prev--;
380 if(avimuxin->samples_head) {
381 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
382 if(FAILED(hr))
383 return hr;
384 head_prev--;
386 *prev = *head_prev;
387 *head_prev = sample;
388 }else {
389 *prev = sample;
391 avimuxin->samples_head = sample;
392 IMediaSample_AddRef(sample);
394 return flush_queue(avimux, avimuxin, FALSE);
397 static HRESULT avi_mux_cleanup_stream(struct strmbase_filter *iface)
399 AviMux *This = impl_from_strmbase_filter(iface);
400 HRESULT hr;
401 int i;
403 if (This->stream)
405 AVIEXTHEADER dmlh;
406 RIFFCHUNK rc;
407 RIFFLIST rl;
408 int idx1_off, empty_stream;
410 empty_stream = This->cur_stream;
411 for(i=empty_stream+1; ; i++) {
412 if(i >= This->input_pin_no-1)
413 i = 0;
414 if(i == empty_stream)
415 break;
417 This->cur_stream = i;
418 hr = flush_queue(This, This->in[This->cur_stream], TRUE);
419 if(FAILED(hr))
420 return hr;
423 idx1_off = This->size;
424 rc.fcc = ckidAVIOLDINDEX;
425 rc.cb = This->idx1_entries * sizeof(*This->idx1);
426 hr = out_write(This, &rc, sizeof(rc));
427 if(FAILED(hr))
428 return hr;
429 hr = out_write(This, This->idx1, This->idx1_entries * sizeof(*This->idx1));
430 if(FAILED(hr))
431 return hr;
432 /* native writes 8 '\0' characters after the end of RIFF data */
433 i = 0;
434 hr = out_write(This, &i, sizeof(i));
435 if(FAILED(hr))
436 return hr;
437 hr = out_write(This, &i, sizeof(i));
438 if(FAILED(hr))
439 return hr;
441 for(i=0; i<This->input_pin_no; i++) {
442 if(!This->in[i]->pin.pin.peer)
443 continue;
445 hr = out_seek(This, This->in[i]->ix_off);
446 if(FAILED(hr))
447 return hr;
449 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].qwOffset = This->in[i]->ix_off;
450 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwSize = sizeof(This->in[i]->ix_data);
451 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration = This->in[i]->strh.dwLength;
452 if(This->in[i]->indx->nEntriesInUse) {
453 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration -=
454 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse-1].dwDuration;
456 This->in[i]->indx->nEntriesInUse++;
457 hr = out_write(This, This->in[i]->ix, sizeof(This->in[i]->ix_data));
458 if(FAILED(hr))
459 return hr;
462 hr = out_seek(This, 0);
463 if(FAILED(hr))
464 return hr;
466 rl.fcc = FCC('R','I','F','F');
467 rl.cb = This->size - sizeof(RIFFCHUNK) - 2 * sizeof(int);
468 rl.fccListType = FCC('A','V','I',' ');
469 hr = out_write(This, &rl, sizeof(rl));
470 if(FAILED(hr))
471 return hr;
473 rl.fcc = FCC('L','I','S','T');
474 rl.cb = This->movi_off - sizeof(RIFFLIST) - sizeof(RIFFCHUNK);
475 rl.fccListType = FCC('h','d','r','l');
476 hr = out_write(This, &rl, sizeof(rl));
477 if(FAILED(hr))
478 return hr;
480 /* FIXME: set This->avih.dwMaxBytesPerSec value */
481 This->avih.dwTotalFrames = (This->stop-This->start) / 10 / This->avih.dwMicroSecPerFrame;
482 hr = out_write(This, &This->avih, sizeof(This->avih));
483 if(FAILED(hr))
484 return hr;
486 for(i=0; i<This->input_pin_no; i++) {
487 if(!This->in[i]->pin.pin.peer)
488 continue;
490 rl.cb = sizeof(FOURCC) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK) +
491 This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
492 rl.fccListType = ckidSTREAMLIST;
493 hr = out_write(This, &rl, sizeof(rl));
494 if(FAILED(hr))
495 return hr;
497 hr = out_write(This, &This->in[i]->strh, sizeof(AVISTREAMHEADER));
498 if(FAILED(hr))
499 return hr;
501 hr = out_write(This, This->in[i]->strf, sizeof(RIFFCHUNK) + This->in[i]->strf->cb);
502 if(FAILED(hr))
503 return hr;
505 hr = out_write(This, This->in[i]->indx, sizeof(This->in[i]->indx_data));
506 if(FAILED(hr))
507 return hr;
510 rl.cb = sizeof(dmlh) + sizeof(FOURCC);
511 rl.fccListType = ckidODML;
512 hr = out_write(This, &rl, sizeof(rl));
513 if(FAILED(hr))
514 return hr;
516 memset(&dmlh, 0, sizeof(dmlh));
517 dmlh.fcc = ckidAVIEXTHEADER;
518 dmlh.cb = sizeof(dmlh) - sizeof(RIFFCHUNK);
519 dmlh.dwGrandFrames = This->in[0]->strh.dwLength;
520 hr = out_write(This, &dmlh, sizeof(dmlh));
522 rl.cb = idx1_off - This->movi_off - sizeof(RIFFCHUNK);
523 rl.fccListType = FCC('m','o','v','i');
524 out_write(This, &rl, sizeof(rl));
525 out_flush(This);
527 IStream_Release(This->stream);
528 This->stream = NULL;
531 return S_OK;
534 static HRESULT avi_mux_init_stream(struct strmbase_filter *iface)
536 AviMux *This = impl_from_strmbase_filter(iface);
537 HRESULT hr;
538 int i, stream_id;
540 if(This->mode != INTERLEAVE_FULL) {
541 FIXME("mode not supported (%d)\n", This->mode);
542 return E_NOTIMPL;
545 for(i=0; i<This->input_pin_no; i++) {
546 IMediaSeeking *ms;
547 LONGLONG cur, stop;
549 if(!This->in[i]->pin.pin.peer)
550 continue;
552 hr = IPin_QueryInterface(This->in[i]->pin.pin.peer,
553 &IID_IMediaSeeking, (void**)&ms);
554 if(FAILED(hr))
555 continue;
557 hr = IMediaSeeking_GetPositions(ms, &cur, &stop);
558 if(FAILED(hr)) {
559 IMediaSeeking_Release(ms);
560 continue;
563 FIXME("Use IMediaSeeking to fill stream header\n");
564 IMediaSeeking_Release(ms);
567 if (This->source.pMemInputPin)
569 hr = IMemInputPin_QueryInterface(This->source.pMemInputPin,
570 &IID_IStream, (void **)&This->stream);
571 if(FAILED(hr))
572 return hr;
575 This->idx1_entries = 0;
576 if(!This->idx1_size) {
577 This->idx1_size = 1024;
578 if (!(This->idx1 = malloc(sizeof(*This->idx1) * This->idx1_size)))
579 return E_OUTOFMEMORY;
582 This->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER);
583 This->start = -1;
584 This->stop = -1;
585 memset(&This->avih, 0, sizeof(This->avih));
586 for(i=0; i<This->input_pin_no; i++) {
587 if(!This->in[i]->pin.pin.peer)
588 continue;
590 This->avih.dwStreams++;
591 This->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK)
592 + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
594 This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000);
595 This->in[i]->strh.dwRate = This->interleave;
597 hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator);
598 if(FAILED(hr)) {
599 if (This->stream)
601 IStream_Release(This->stream);
602 This->stream = NULL;
604 return hr;
608 This->movi_off = This->size;
609 This->size += sizeof(RIFFLIST);
611 idx1_add_entry(This, FCC('7','F','x','x'), 0, This->movi_off + sizeof(RIFFLIST), 0);
613 stream_id = 0;
614 for(i=0; i<This->input_pin_no; i++) {
615 if(!This->in[i]->pin.pin.peer)
616 continue;
618 This->in[i]->ix_off = This->size;
619 This->size += sizeof(This->in[i]->ix_data);
620 This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10);
621 This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK);
622 This->in[i]->ix->wLongsPerEntry = 2;
623 This->in[i]->ix->bIndexSubType = 0;
624 This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS;
625 This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b');
626 This->in[i]->ix->qwBaseOffset = 0;
628 This->in[i]->indx->fcc = ckidAVISUPERINDEX;
629 This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK);
630 This->in[i]->indx->wLongsPerEntry = 4;
631 This->in[i]->indx->bIndexSubType = 0;
632 This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES;
633 This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId;
634 This->in[i]->stream_id = stream_id++;
637 This->buf_pos = 0;
638 This->out_pos = 0;
640 This->avih.fcc = ckidMAINAVIHEADER;
641 This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK);
642 /* TODO: Use first video stream */
643 This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10;
644 This->avih.dwPaddingGranularity = 1;
645 This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX;
646 This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth;
647 This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight;
649 return S_OK;
652 static const struct strmbase_filter_ops filter_ops =
654 .filter_get_pin = avi_mux_get_pin,
655 .filter_destroy = avi_mux_destroy,
656 .filter_query_interface = avi_mux_query_interface,
657 .filter_init_stream = avi_mux_init_stream,
658 .filter_cleanup_stream = avi_mux_cleanup_stream,
661 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface)
663 return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface);
666 static HRESULT WINAPI ConfigAviMux_QueryInterface(
667 IConfigAviMux *iface, REFIID riid, void **ppv)
669 AviMux *This = impl_from_IConfigAviMux(iface);
670 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
673 static ULONG WINAPI ConfigAviMux_AddRef(IConfigAviMux *iface)
675 AviMux *This = impl_from_IConfigAviMux(iface);
676 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
679 static ULONG WINAPI ConfigAviMux_Release(IConfigAviMux *iface)
681 AviMux *This = impl_from_IConfigAviMux(iface);
682 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
685 static HRESULT WINAPI ConfigAviMux_SetMasterStream(IConfigAviMux *iface, LONG iStream)
687 AviMux *This = impl_from_IConfigAviMux(iface);
688 FIXME("(%p)->(%d)\n", This, iStream);
689 return E_NOTIMPL;
692 static HRESULT WINAPI ConfigAviMux_GetMasterStream(IConfigAviMux *iface, LONG *pStream)
694 AviMux *This = impl_from_IConfigAviMux(iface);
695 FIXME("(%p)->(%p)\n", This, pStream);
696 return E_NOTIMPL;
699 static HRESULT WINAPI ConfigAviMux_SetOutputCompatibilityIndex(
700 IConfigAviMux *iface, BOOL fOldIndex)
702 AviMux *This = impl_from_IConfigAviMux(iface);
703 FIXME("(%p)->(%x)\n", This, fOldIndex);
704 return E_NOTIMPL;
707 static HRESULT WINAPI ConfigAviMux_GetOutputCompatibilityIndex(
708 IConfigAviMux *iface, BOOL *pfOldIndex)
710 AviMux *This = impl_from_IConfigAviMux(iface);
711 FIXME("(%p)->(%p)\n", This, pfOldIndex);
712 return E_NOTIMPL;
715 static const IConfigAviMuxVtbl ConfigAviMuxVtbl = {
716 ConfigAviMux_QueryInterface,
717 ConfigAviMux_AddRef,
718 ConfigAviMux_Release,
719 ConfigAviMux_SetMasterStream,
720 ConfigAviMux_GetMasterStream,
721 ConfigAviMux_SetOutputCompatibilityIndex,
722 ConfigAviMux_GetOutputCompatibilityIndex
725 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface)
727 return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface);
730 static HRESULT WINAPI ConfigInterleaving_QueryInterface(
731 IConfigInterleaving *iface, REFIID riid, void **ppv)
733 AviMux *This = impl_from_IConfigInterleaving(iface);
734 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
737 static ULONG WINAPI ConfigInterleaving_AddRef(IConfigInterleaving *iface)
739 AviMux *This = impl_from_IConfigInterleaving(iface);
740 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
743 static ULONG WINAPI ConfigInterleaving_Release(IConfigInterleaving *iface)
745 AviMux *This = impl_from_IConfigInterleaving(iface);
746 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
749 static HRESULT WINAPI ConfigInterleaving_put_Mode(
750 IConfigInterleaving *iface, InterleavingMode mode)
752 AviMux *This = impl_from_IConfigInterleaving(iface);
754 TRACE("(%p)->(%d)\n", This, mode);
756 if(mode>INTERLEAVE_NONE_BUFFERED)
757 return E_INVALIDARG;
759 if(This->mode != mode) {
760 if(This->source.pin.peer) {
761 HRESULT hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
762 if(FAILED(hr))
763 return hr;
766 This->mode = mode;
769 return S_OK;
772 static HRESULT WINAPI ConfigInterleaving_get_Mode(
773 IConfigInterleaving *iface, InterleavingMode *pMode)
775 AviMux *This = impl_from_IConfigInterleaving(iface);
776 FIXME("(%p)->(%p)\n", This, pMode);
777 return E_NOTIMPL;
780 static HRESULT WINAPI ConfigInterleaving_put_Interleaving(IConfigInterleaving *iface,
781 const REFERENCE_TIME *prtInterleave, const REFERENCE_TIME *prtPreroll)
783 AviMux *This = impl_from_IConfigInterleaving(iface);
785 TRACE("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
787 if(prtInterleave)
788 This->interleave = *prtInterleave;
789 if(prtPreroll)
790 This->preroll = *prtPreroll;
791 return S_OK;
794 static HRESULT WINAPI ConfigInterleaving_get_Interleaving(IConfigInterleaving *iface,
795 REFERENCE_TIME *prtInterleave, REFERENCE_TIME *prtPreroll)
797 AviMux *This = impl_from_IConfigInterleaving(iface);
798 FIXME("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
799 return E_NOTIMPL;
802 static const IConfigInterleavingVtbl ConfigInterleavingVtbl = {
803 ConfigInterleaving_QueryInterface,
804 ConfigInterleaving_AddRef,
805 ConfigInterleaving_Release,
806 ConfigInterleaving_put_Mode,
807 ConfigInterleaving_get_Mode,
808 ConfigInterleaving_put_Interleaving,
809 ConfigInterleaving_get_Interleaving
812 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface)
814 return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface);
817 static HRESULT WINAPI MediaSeeking_QueryInterface(
818 IMediaSeeking *iface, REFIID riid, void **ppv)
820 AviMux *This = impl_from_IMediaSeeking(iface);
821 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
824 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
826 AviMux *This = impl_from_IMediaSeeking(iface);
827 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
830 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
832 AviMux *This = impl_from_IMediaSeeking(iface);
833 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
836 static HRESULT WINAPI MediaSeeking_GetCapabilities(
837 IMediaSeeking *iface, DWORD *pCapabilities)
839 AviMux *This = impl_from_IMediaSeeking(iface);
840 FIXME("(%p)->(%p)\n", This, pCapabilities);
841 return E_NOTIMPL;
844 static HRESULT WINAPI MediaSeeking_CheckCapabilities(
845 IMediaSeeking *iface, DWORD *pCapabilities)
847 AviMux *This = impl_from_IMediaSeeking(iface);
848 FIXME("(%p)->(%p)\n", This, pCapabilities);
849 return E_NOTIMPL;
852 static HRESULT WINAPI MediaSeeking_IsFormatSupported(
853 IMediaSeeking *iface, const GUID *pFormat)
855 AviMux *This = impl_from_IMediaSeeking(iface);
856 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
857 return E_NOTIMPL;
860 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(
861 IMediaSeeking *iface, GUID *pFormat)
863 AviMux *This = impl_from_IMediaSeeking(iface);
864 FIXME("(%p)->(%p)\n", This, pFormat);
865 return E_NOTIMPL;
868 static HRESULT WINAPI MediaSeeking_GetTimeFormat(
869 IMediaSeeking *iface, GUID *pFormat)
871 AviMux *This = impl_from_IMediaSeeking(iface);
872 FIXME("(%p)->(%p)\n", This, pFormat);
873 return E_NOTIMPL;
876 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(
877 IMediaSeeking *iface, const GUID *pFormat)
879 AviMux *This = impl_from_IMediaSeeking(iface);
880 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
881 return E_NOTIMPL;
884 static HRESULT WINAPI MediaSeeking_SetTimeFormat(
885 IMediaSeeking *iface, const GUID *pFormat)
887 AviMux *This = impl_from_IMediaSeeking(iface);
888 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
889 return E_NOTIMPL;
892 static HRESULT WINAPI MediaSeeking_GetDuration(
893 IMediaSeeking *iface, LONGLONG *pDuration)
895 AviMux *This = impl_from_IMediaSeeking(iface);
896 FIXME("(%p)->(%p)\n", This, pDuration);
897 return E_NOTIMPL;
900 static HRESULT WINAPI MediaSeeking_GetStopPosition(
901 IMediaSeeking *iface, LONGLONG *pStop)
903 AviMux *This = impl_from_IMediaSeeking(iface);
904 FIXME("(%p)->(%p)\n", This, pStop);
905 return E_NOTIMPL;
908 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(
909 IMediaSeeking *iface, LONGLONG *pCurrent)
911 AviMux *This = impl_from_IMediaSeeking(iface);
912 FIXME("(%p)->(%p)\n", This, pCurrent);
913 return E_NOTIMPL;
916 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
917 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
919 AviMux *This = impl_from_IMediaSeeking(iface);
920 FIXME("(%p)->(%p %s %s %s)\n", This, pTarget, debugstr_guid(pTargetFormat),
921 wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
922 return E_NOTIMPL;
925 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
926 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
928 AviMux *This = impl_from_IMediaSeeking(iface);
929 FIXME("(%p)->(%p %x %p %x)\n", This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
930 return E_NOTIMPL;
933 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
934 LONGLONG *pCurrent, LONGLONG *pStop)
936 AviMux *This = impl_from_IMediaSeeking(iface);
937 FIXME("(%p)->(%p %p)\n", This, pCurrent, pStop);
938 return E_NOTIMPL;
941 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
942 LONGLONG *pEarliest, LONGLONG *pLatest)
944 AviMux *This = impl_from_IMediaSeeking(iface);
945 FIXME("(%p)->(%p %p)\n", This, pEarliest, pLatest);
946 return E_NOTIMPL;
949 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
951 AviMux *This = impl_from_IMediaSeeking(iface);
952 FIXME("(%p)->(%lf)\n", This, dRate);
953 return E_NOTIMPL;
956 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
958 AviMux *This = impl_from_IMediaSeeking(iface);
959 FIXME("(%p)->(%p)\n", This, pdRate);
960 return E_NOTIMPL;
963 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
965 AviMux *This = impl_from_IMediaSeeking(iface);
966 FIXME("(%p)->(%p)\n", This, pllPreroll);
967 return E_NOTIMPL;
970 static const IMediaSeekingVtbl MediaSeekingVtbl = {
971 MediaSeeking_QueryInterface,
972 MediaSeeking_AddRef,
973 MediaSeeking_Release,
974 MediaSeeking_GetCapabilities,
975 MediaSeeking_CheckCapabilities,
976 MediaSeeking_IsFormatSupported,
977 MediaSeeking_QueryPreferredFormat,
978 MediaSeeking_GetTimeFormat,
979 MediaSeeking_IsUsingTimeFormat,
980 MediaSeeking_SetTimeFormat,
981 MediaSeeking_GetDuration,
982 MediaSeeking_GetStopPosition,
983 MediaSeeking_GetCurrentPosition,
984 MediaSeeking_ConvertTimeFormat,
985 MediaSeeking_SetPositions,
986 MediaSeeking_GetPositions,
987 MediaSeeking_GetAvailable,
988 MediaSeeking_SetRate,
989 MediaSeeking_GetRate,
990 MediaSeeking_GetPreroll
993 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface)
995 return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface);
998 static HRESULT WINAPI PersistMediaPropertyBag_QueryInterface(
999 IPersistMediaPropertyBag *iface, REFIID riid, void **ppv)
1001 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1002 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1005 static ULONG WINAPI PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag *iface)
1007 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1008 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1011 static ULONG WINAPI PersistMediaPropertyBag_Release(IPersistMediaPropertyBag *iface)
1013 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1014 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1017 static HRESULT WINAPI PersistMediaPropertyBag_GetClassID(
1018 IPersistMediaPropertyBag *iface, CLSID *pClassID)
1020 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1021 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID);
1024 static HRESULT WINAPI PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag *iface)
1026 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1027 FIXME("(%p)->()\n", This);
1028 return E_NOTIMPL;
1031 static HRESULT WINAPI PersistMediaPropertyBag_Load(IPersistMediaPropertyBag *iface,
1032 IMediaPropertyBag *pPropBag, IErrorLog *pErrorLog)
1034 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1035 FIXME("(%p)->()\n", This);
1036 return E_NOTIMPL;
1039 static HRESULT WINAPI PersistMediaPropertyBag_Save(IPersistMediaPropertyBag *iface,
1040 IMediaPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
1042 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1043 FIXME("(%p)->()\n", This);
1044 return E_NOTIMPL;
1047 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl = {
1048 PersistMediaPropertyBag_QueryInterface,
1049 PersistMediaPropertyBag_AddRef,
1050 PersistMediaPropertyBag_Release,
1051 PersistMediaPropertyBag_GetClassID,
1052 PersistMediaPropertyBag_InitNew,
1053 PersistMediaPropertyBag_Load,
1054 PersistMediaPropertyBag_Save
1057 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface)
1059 return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface);
1062 static HRESULT WINAPI SpecifyPropertyPages_QueryInterface(
1063 ISpecifyPropertyPages *iface, REFIID riid, void **ppv)
1065 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1066 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1069 static ULONG WINAPI SpecifyPropertyPages_AddRef(ISpecifyPropertyPages *iface)
1071 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1072 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1075 static ULONG WINAPI SpecifyPropertyPages_Release(ISpecifyPropertyPages *iface)
1077 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1078 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1081 static HRESULT WINAPI SpecifyPropertyPages_GetPages(
1082 ISpecifyPropertyPages *iface, CAUUID *pPages)
1084 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1085 FIXME("(%p)->(%p)\n", This, pPages);
1086 return E_NOTIMPL;
1089 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = {
1090 SpecifyPropertyPages_QueryInterface,
1091 SpecifyPropertyPages_AddRef,
1092 SpecifyPropertyPages_Release,
1093 SpecifyPropertyPages_GetPages
1096 static inline AviMux *impl_from_source_pin(struct strmbase_pin *iface)
1098 return CONTAINING_RECORD(iface, AviMux, source.pin);
1101 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
1103 AviMux *filter = impl_from_source_pin(iface);
1105 if (IsEqualGUID(iid, &IID_IQualityControl))
1106 *out = &filter->IQualityControl_iface;
1107 else
1108 return E_NOINTERFACE;
1110 IUnknown_AddRef((IUnknown *)*out);
1111 return S_OK;
1114 static HRESULT source_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *amt)
1116 FIXME("(%p) stub\n", base);
1117 return S_OK;
1120 static HRESULT WINAPI AviMuxOut_AttemptConnection(struct strmbase_source *iface,
1121 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1123 AviMux *filter = impl_from_source_pin(&iface->pin);
1124 PIN_DIRECTION dir;
1125 unsigned int i;
1126 HRESULT hr;
1128 hr = IPin_QueryDirection(pReceivePin, &dir);
1129 if(hr==S_OK && dir!=PINDIR_INPUT)
1130 return VFW_E_INVALID_DIRECTION;
1132 if (FAILED(hr = BaseOutputPinImpl_AttemptConnection(iface, pReceivePin, pmt)))
1133 return hr;
1135 for (i = 0; i < filter->input_pin_no; ++i)
1137 if (!filter->in[i]->pin.pin.peer)
1138 continue;
1140 hr = IFilterGraph_Reconnect(filter->filter.graph, &filter->in[i]->pin.pin.IPin_iface);
1141 if (FAILED(hr))
1143 IPin_Disconnect(&iface->pin.IPin_iface);
1144 break;
1148 return hr;
1151 static HRESULT source_get_media_type(struct strmbase_pin *base, unsigned int iPosition, AM_MEDIA_TYPE *amt)
1153 TRACE("(%p)->(%d %p)\n", base, iPosition, amt);
1155 if(iPosition > 0)
1156 return VFW_S_NO_MORE_ITEMS;
1158 amt->majortype = MEDIATYPE_Stream;
1159 amt->subtype = MEDIASUBTYPE_Avi;
1160 amt->bFixedSizeSamples = TRUE;
1161 amt->bTemporalCompression = FALSE;
1162 amt->lSampleSize = 1;
1163 amt->formattype = GUID_NULL;
1164 amt->pUnk = NULL;
1165 amt->cbFormat = 0;
1166 amt->pbFormat = NULL;
1167 return S_OK;
1170 static HRESULT WINAPI AviMuxOut_DecideAllocator(struct strmbase_source *base,
1171 IMemInputPin *pPin, IMemAllocator **pAlloc)
1173 ALLOCATOR_PROPERTIES req, actual;
1174 HRESULT hr;
1176 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc);
1178 hr = BaseOutputPinImpl_InitAllocator(base, pAlloc);
1179 if(FAILED(hr))
1180 return hr;
1182 hr = IMemInputPin_GetAllocatorRequirements(pPin, &req);
1183 if(FAILED(hr))
1184 req.cbAlign = 1;
1185 req.cBuffers = 32;
1186 req.cbBuffer = 0;
1187 req.cbPrefix = 0;
1189 hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual);
1190 if(FAILED(hr))
1191 return hr;
1193 return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE);
1196 static const struct strmbase_source_ops source_ops =
1198 .base.pin_query_interface = source_query_interface,
1199 .base.pin_query_accept = source_query_accept,
1200 .base.pin_get_media_type = source_get_media_type,
1201 .pfnAttemptConnection = AviMuxOut_AttemptConnection,
1202 .pfnDecideAllocator = AviMuxOut_DecideAllocator,
1205 static inline AviMux* impl_from_out_IQualityControl(IQualityControl *iface)
1207 return CONTAINING_RECORD(iface, AviMux, IQualityControl_iface);
1210 static HRESULT WINAPI AviMuxOut_QualityControl_QueryInterface(
1211 IQualityControl *iface, REFIID riid, void **ppv)
1213 AviMux *This = impl_from_out_IQualityControl(iface);
1214 return IPin_QueryInterface(&This->source.pin.IPin_iface, riid, ppv);
1217 static ULONG WINAPI AviMuxOut_QualityControl_AddRef(IQualityControl *iface)
1219 AviMux *This = impl_from_out_IQualityControl(iface);
1220 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1223 static ULONG WINAPI AviMuxOut_QualityControl_Release(IQualityControl *iface)
1225 AviMux *This = impl_from_out_IQualityControl(iface);
1226 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1229 static HRESULT WINAPI AviMuxOut_QualityControl_Notify(IQualityControl *iface,
1230 IBaseFilter *pSelf, Quality q)
1232 AviMux *This = impl_from_out_IQualityControl(iface);
1233 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This, pSelf,
1234 q.Type, q.Proportion,
1235 wine_dbgstr_longlong(q.Late),
1236 wine_dbgstr_longlong(q.TimeStamp));
1237 return E_NOTIMPL;
1240 static HRESULT WINAPI AviMuxOut_QualityControl_SetSink(
1241 IQualityControl *iface, IQualityControl *piqc)
1243 AviMux *This = impl_from_out_IQualityControl(iface);
1244 FIXME("(%p)->(%p)\n", This, piqc);
1245 return E_NOTIMPL;
1248 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl = {
1249 AviMuxOut_QualityControl_QueryInterface,
1250 AviMuxOut_QualityControl_AddRef,
1251 AviMuxOut_QualityControl_Release,
1252 AviMuxOut_QualityControl_Notify,
1253 AviMuxOut_QualityControl_SetSink
1256 static inline AviMuxIn *impl_sink_from_strmbase_pin(struct strmbase_pin *iface)
1258 return CONTAINING_RECORD(iface, AviMuxIn, pin.pin);
1261 static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
1263 AviMuxIn *pin = impl_sink_from_strmbase_pin(iface);
1265 if (IsEqualGUID(iid, &IID_IAMStreamControl))
1266 *out = &pin->IAMStreamControl_iface;
1267 else if (IsEqualGUID(iid, &IID_IMemInputPin))
1268 *out = &pin->pin.IMemInputPin_iface;
1269 else if (IsEqualGUID(iid, &IID_IPropertyBag))
1270 *out = &pin->IPropertyBag_iface;
1271 else if (IsEqualGUID(iid, &IID_IQualityControl))
1272 *out = &pin->IQualityControl_iface;
1273 else
1274 return E_NOINTERFACE;
1276 IUnknown_AddRef((IUnknown *)*out);
1277 return S_OK;
1280 static HRESULT sink_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *pmt)
1282 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) &&
1283 IsEqualIID(&pmt->formattype, &FORMAT_WaveFormatEx))
1284 return S_OK;
1285 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Interleaved) &&
1286 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo))
1287 return S_OK;
1288 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1289 (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo) ||
1290 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo)))
1291 return S_OK;
1292 return S_FALSE;
1295 static HRESULT WINAPI AviMuxIn_Receive(struct strmbase_sink *base, IMediaSample *pSample)
1297 AviMux *avimux = impl_from_strmbase_filter(base->pin.filter);
1298 AviMuxIn *avimuxin = CONTAINING_RECORD(base, AviMuxIn, pin);
1299 REFERENCE_TIME start, stop;
1300 IMediaSample *sample;
1301 int frames_no;
1302 IMediaSample2 *ms2;
1303 BYTE *frame, *buf;
1304 DWORD max_size, size;
1305 DWORD flags;
1306 HRESULT hr;
1308 TRACE("pin %p, pSample %p.\n", avimuxin, pSample);
1310 hr = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&ms2);
1311 if(SUCCEEDED(hr)) {
1312 AM_SAMPLE2_PROPERTIES props;
1314 memset(&props, 0, sizeof(props));
1315 hr = IMediaSample2_GetProperties(ms2, sizeof(props), (BYTE*)&props);
1316 IMediaSample2_Release(ms2);
1317 if(FAILED(hr))
1318 return hr;
1320 flags = props.dwSampleFlags;
1321 frame = props.pbBuffer;
1322 size = props.lActual;
1323 }else {
1324 flags = IMediaSample_IsSyncPoint(pSample) == S_OK ? AM_SAMPLE_SPLICEPOINT : 0;
1325 hr = IMediaSample_GetPointer(pSample, &frame);
1326 if(FAILED(hr))
1327 return hr;
1328 size = IMediaSample_GetActualDataLength(pSample);
1331 if(!avimuxin->pin.pin.mt.bTemporalCompression)
1332 flags |= AM_SAMPLE_SPLICEPOINT;
1334 hr = IMediaSample_GetTime(pSample, &start, &stop);
1335 if(FAILED(hr))
1336 return hr;
1338 if(avimuxin->stop>stop)
1339 return VFW_E_START_TIME_AFTER_END;
1341 if(avimux->start == -1)
1342 avimux->start = start;
1343 if(avimux->stop < stop)
1344 avimux->stop = stop;
1346 if(avimux->avih.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1347 avimux->avih.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1348 if(avimuxin->strh.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1349 avimuxin->strh.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1351 frames_no = 1;
1352 if(avimuxin->stop!=-1 && start > avimuxin->stop) {
1353 frames_no += (double)(start - avimuxin->stop) / 10000000
1354 * avimuxin->strh.dwRate / avimuxin->strh.dwScale + 0.5;
1356 avimuxin->stop = stop;
1358 while(--frames_no) {
1359 /* TODO: store all control frames in one buffer */
1360 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1361 if(FAILED(hr))
1362 return hr;
1363 hr = IMediaSample_SetActualDataLength(sample, 0);
1364 if(SUCCEEDED(hr))
1365 hr = IMediaSample_SetDiscontinuity(sample, TRUE);
1366 if(SUCCEEDED(hr))
1367 hr = IMediaSample_SetSyncPoint(sample, FALSE);
1368 if(SUCCEEDED(hr))
1369 hr = queue_sample(avimux, avimuxin, sample);
1370 IMediaSample_Release(sample);
1371 if(FAILED(hr))
1372 return hr;
1375 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1376 if(FAILED(hr))
1377 return hr;
1378 max_size = IMediaSample_GetSize(sample);
1379 if(size > max_size)
1380 size = max_size;
1381 hr = IMediaSample_SetActualDataLength(sample, size);
1382 if(SUCCEEDED(hr))
1383 hr = IMediaSample_SetDiscontinuity(sample, FALSE);
1384 if(SUCCEEDED(hr))
1385 hr = IMediaSample_SetSyncPoint(sample, flags & AM_SAMPLE_SPLICEPOINT);
1386 /* TODO: avoid unnecessary copying */
1387 if(SUCCEEDED(hr))
1388 hr = IMediaSample_GetPointer(sample, &buf);
1389 if(SUCCEEDED(hr)) {
1390 memcpy(buf, frame, size);
1391 hr = queue_sample(avimux, avimuxin, sample);
1393 IMediaSample_Release(sample);
1395 return hr;
1398 static HRESULT avi_mux_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt)
1400 AviMuxIn *avimuxin = impl_sink_from_strmbase_pin(&iface->pin);
1401 AviMux *This = impl_from_strmbase_filter(iface->pin.filter);
1402 HRESULT hr;
1404 if(!pmt)
1405 return E_POINTER;
1407 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1408 IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
1409 ALLOCATOR_PROPERTIES req, act;
1410 VIDEOINFOHEADER *vih;
1411 int size;
1413 vih = (VIDEOINFOHEADER*)pmt->pbFormat;
1414 avimuxin->strh.fcc = ckidSTREAMHEADER;
1415 avimuxin->strh.cb = sizeof(AVISTREAMHEADER) - FIELD_OFFSET(AVISTREAMHEADER, fccType);
1416 avimuxin->strh.fccType = streamtypeVIDEO;
1417 /* FIXME: fccHandler should be set differently */
1418 avimuxin->strh.fccHandler = vih->bmiHeader.biCompression ?
1419 vih->bmiHeader.biCompression : FCC('D','I','B',' ');
1420 avimuxin->avg_time_per_frame = vih->AvgTimePerFrame;
1421 avimuxin->stop = -1;
1423 req.cBuffers = 32;
1424 req.cbBuffer = vih->bmiHeader.biSizeImage;
1425 req.cbAlign = 1;
1426 req.cbPrefix = sizeof(void*);
1427 hr = IMemAllocator_SetProperties(avimuxin->samples_allocator, &req, &act);
1428 if(SUCCEEDED(hr))
1429 hr = IMemAllocator_Commit(avimuxin->samples_allocator);
1430 if (FAILED(hr))
1431 return hr;
1433 size = pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
1434 avimuxin->strf = malloc(sizeof(RIFFCHUNK) + ALIGN(FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed])));
1435 avimuxin->strf->fcc = ckidSTREAMFORMAT;
1436 avimuxin->strf->cb = FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]);
1437 if(size > avimuxin->strf->cb)
1438 size = avimuxin->strf->cb;
1439 memcpy(avimuxin->strf->data, &vih->bmiHeader, size);
1440 }else {
1441 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt->majortype),
1442 debugstr_guid(&pmt->formattype));
1443 return E_NOTIMPL;
1446 return create_input_pin(This);
1449 static void avi_mux_sink_disconnect(struct strmbase_sink *iface)
1451 AviMuxIn *avimuxin = impl_sink_from_strmbase_pin(&iface->pin);
1452 IMediaSample **prev, *cur;
1454 IMemAllocator_Decommit(avimuxin->samples_allocator);
1455 while(avimuxin->samples_head) {
1456 cur = avimuxin->samples_head;
1457 if (FAILED(IMediaSample_GetPointer(cur, (BYTE **)&prev)))
1458 break;
1459 prev--;
1461 cur = avimuxin->samples_head;
1462 avimuxin->samples_head = *prev;
1463 IMediaSample_Release(cur);
1465 if(cur == avimuxin->samples_head)
1466 avimuxin->samples_head = NULL;
1468 free(avimuxin->strf);
1469 avimuxin->strf = NULL;
1472 static const struct strmbase_sink_ops sink_ops =
1474 .base.pin_query_interface = sink_query_interface,
1475 .base.pin_query_accept = sink_query_accept,
1476 .pfnReceive = AviMuxIn_Receive,
1477 .sink_connect = avi_mux_sink_connect,
1478 .sink_disconnect = avi_mux_sink_disconnect,
1481 static inline AviMux* impl_from_in_IPin(IPin *iface)
1483 struct strmbase_pin *pin = CONTAINING_RECORD(iface, struct strmbase_pin, IPin_iface);
1484 return impl_from_strmbase_filter(pin->filter);
1487 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface)
1489 return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface);
1492 static HRESULT WINAPI AviMuxIn_AMStreamControl_QueryInterface(
1493 IAMStreamControl *iface, REFIID riid, void **ppv)
1495 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1496 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1499 static ULONG WINAPI AviMuxIn_AMStreamControl_AddRef(IAMStreamControl *iface)
1501 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1502 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1503 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1506 static ULONG WINAPI AviMuxIn_AMStreamControl_Release(IAMStreamControl *iface)
1508 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1509 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1510 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1513 static HRESULT WINAPI AviMuxIn_AMStreamControl_StartAt(IAMStreamControl *iface,
1514 const REFERENCE_TIME *start, DWORD cookie)
1516 FIXME("iface %p, start %p, cookie %#x, stub!\n", iface, start, cookie);
1517 return E_NOTIMPL;
1520 static HRESULT WINAPI AviMuxIn_AMStreamControl_StopAt(IAMStreamControl *iface,
1521 const REFERENCE_TIME *stop, BOOL send_extra, DWORD cookie)
1523 FIXME("iface %p, stop %p, send_extra %d, cookie %#x, stub!\n", iface, stop, send_extra, cookie);
1524 return E_NOTIMPL;
1527 static HRESULT WINAPI AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl *iface,
1528 AM_STREAM_INFO *info)
1530 FIXME("iface %p, info %p, stub!\n", iface, info);
1531 return E_NOTIMPL;
1534 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl = {
1535 AviMuxIn_AMStreamControl_QueryInterface,
1536 AviMuxIn_AMStreamControl_AddRef,
1537 AviMuxIn_AMStreamControl_Release,
1538 AviMuxIn_AMStreamControl_StartAt,
1539 AviMuxIn_AMStreamControl_StopAt,
1540 AviMuxIn_AMStreamControl_GetInfo
1543 static inline AviMuxIn* AviMuxIn_from_IMemInputPin(IMemInputPin *iface)
1545 return CONTAINING_RECORD(iface, AviMuxIn, pin.IMemInputPin_iface);
1548 static HRESULT WINAPI AviMuxIn_MemInputPin_QueryInterface(
1549 IMemInputPin *iface, REFIID riid, void **ppv)
1551 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1552 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1555 static ULONG WINAPI AviMuxIn_MemInputPin_AddRef(IMemInputPin *iface)
1557 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1558 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1559 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1562 static ULONG WINAPI AviMuxIn_MemInputPin_Release(IMemInputPin *iface)
1564 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1565 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1566 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1569 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocator(
1570 IMemInputPin *iface, IMemAllocator **ppAllocator)
1572 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1574 TRACE("pin %p, ppAllocator %p.\n", avimuxin, ppAllocator);
1576 if(!ppAllocator)
1577 return E_POINTER;
1579 IMemAllocator_AddRef(avimuxin->pin.pAllocator);
1580 *ppAllocator = avimuxin->pin.pAllocator;
1581 return S_OK;
1584 static HRESULT WINAPI AviMuxIn_MemInputPin_NotifyAllocator(
1585 IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly)
1587 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1588 ALLOCATOR_PROPERTIES props;
1589 HRESULT hr;
1591 TRACE("pin %p, pAllocator %p, bReadOnly %d.\n", avimuxin, pAllocator, bReadOnly);
1593 if(!pAllocator)
1594 return E_POINTER;
1596 memset(&props, 0, sizeof(props));
1597 hr = IMemAllocator_GetProperties(pAllocator, &props);
1598 if(FAILED(hr))
1599 return hr;
1601 props.cbAlign = 1;
1602 props.cbPrefix = 8;
1603 return IMemAllocator_SetProperties(avimuxin->pin.pAllocator, &props, &props);
1606 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocatorRequirements(
1607 IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps)
1609 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1611 TRACE("pin %p, pProps %p.\n", avimuxin, pProps);
1613 if(!pProps)
1614 return E_POINTER;
1616 pProps->cbAlign = 1;
1617 pProps->cbPrefix = 8;
1618 return S_OK;
1621 static HRESULT WINAPI AviMuxIn_MemInputPin_Receive(
1622 IMemInputPin *iface, IMediaSample *pSample)
1624 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1626 TRACE("pin %p, pSample %p.\n", avimuxin, pSample);
1628 return avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSample);
1631 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin *iface,
1632 IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed)
1634 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1635 HRESULT hr = S_OK;
1637 TRACE("pin %p, pSamples %p, nSamples %d, nSamplesProcessed %p.\n",
1638 avimuxin, pSamples, nSamples, nSamplesProcessed);
1640 for(*nSamplesProcessed=0; *nSamplesProcessed<nSamples; (*nSamplesProcessed)++)
1642 hr = avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSamples[*nSamplesProcessed]);
1643 if(hr != S_OK)
1644 break;
1647 return hr;
1650 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1652 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1653 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1654 HRESULT hr;
1656 TRACE("avimuxin %p.\n", avimuxin);
1658 if(!This->source.pMemInputPin)
1659 return S_FALSE;
1661 hr = IMemInputPin_ReceiveCanBlock(This->source.pMemInputPin);
1662 return hr != S_FALSE ? S_OK : S_FALSE;
1665 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl = {
1666 AviMuxIn_MemInputPin_QueryInterface,
1667 AviMuxIn_MemInputPin_AddRef,
1668 AviMuxIn_MemInputPin_Release,
1669 AviMuxIn_MemInputPin_GetAllocator,
1670 AviMuxIn_MemInputPin_NotifyAllocator,
1671 AviMuxIn_MemInputPin_GetAllocatorRequirements,
1672 AviMuxIn_MemInputPin_Receive,
1673 AviMuxIn_MemInputPin_ReceiveMultiple,
1674 AviMuxIn_MemInputPin_ReceiveCanBlock
1677 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface)
1679 return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface);
1682 static HRESULT WINAPI AviMuxIn_PropertyBag_QueryInterface(
1683 IPropertyBag *iface, REFIID riid, void **ppv)
1685 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1686 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1689 static ULONG WINAPI AviMuxIn_PropertyBag_AddRef(IPropertyBag *iface)
1691 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1692 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1693 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1696 static ULONG WINAPI AviMuxIn_PropertyBag_Release(IPropertyBag *iface)
1698 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1699 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1700 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1703 static HRESULT WINAPI AviMuxIn_PropertyBag_Read(IPropertyBag *iface,
1704 const WCHAR *name, VARIANT *value, IErrorLog *error_log)
1706 FIXME("iface %p, name %s, value %p, error_log %p, stub!\n",
1707 iface, debugstr_w(name), value, error_log);
1708 return E_NOTIMPL;
1711 static HRESULT WINAPI AviMuxIn_PropertyBag_Write(IPropertyBag *iface,
1712 const WCHAR *name, VARIANT *value)
1714 FIXME("iface %p, name %s, value %s, stub!\n",
1715 iface, debugstr_w(name), debugstr_variant(value));
1716 return E_NOTIMPL;
1719 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl = {
1720 AviMuxIn_PropertyBag_QueryInterface,
1721 AviMuxIn_PropertyBag_AddRef,
1722 AviMuxIn_PropertyBag_Release,
1723 AviMuxIn_PropertyBag_Read,
1724 AviMuxIn_PropertyBag_Write
1727 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface)
1729 return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface);
1732 static HRESULT WINAPI AviMuxIn_QualityControl_QueryInterface(
1733 IQualityControl *iface, REFIID riid, void **ppv)
1735 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1736 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1739 static ULONG WINAPI AviMuxIn_QualityControl_AddRef(IQualityControl *iface)
1741 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1742 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1743 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1746 static ULONG WINAPI AviMuxIn_QualityControl_Release(IQualityControl *iface)
1748 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1749 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1750 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1753 static HRESULT WINAPI AviMuxIn_QualityControl_Notify(IQualityControl *iface,
1754 IBaseFilter *filter, Quality q)
1756 FIXME("iface %p, filter %p, type %u, proportion %d, late %s, timestamp %s, stub!\n",
1757 iface, filter, q.Type, q.Proportion, wine_dbgstr_longlong(q.Late),
1758 wine_dbgstr_longlong(q.TimeStamp));
1759 return E_NOTIMPL;
1762 static HRESULT WINAPI AviMuxIn_QualityControl_SetSink(IQualityControl *iface, IQualityControl *sink)
1764 FIXME("iface %p, sink %p, stub!\n", iface, sink);
1765 return E_NOTIMPL;
1768 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl = {
1769 AviMuxIn_QualityControl_QueryInterface,
1770 AviMuxIn_QualityControl_AddRef,
1771 AviMuxIn_QualityControl_Release,
1772 AviMuxIn_QualityControl_Notify,
1773 AviMuxIn_QualityControl_SetSink
1776 static HRESULT create_input_pin(AviMux *avimux)
1778 AviMuxIn *object;
1779 WCHAR name[19];
1780 HRESULT hr;
1782 if(avimux->input_pin_no >= MAX_PIN_NO-1)
1783 return E_FAIL;
1785 swprintf(name, ARRAY_SIZE(name), L"Input %02u", avimux->input_pin_no + 1);
1787 if (!(object = calloc(1, sizeof(*object))))
1788 return E_OUTOFMEMORY;
1790 strmbase_sink_init(&object->pin, &avimux->filter, name, &sink_ops, NULL);
1791 object->pin.IMemInputPin_iface.lpVtbl = &AviMuxIn_MemInputPinVtbl;
1792 object->IAMStreamControl_iface.lpVtbl = &AviMuxIn_AMStreamControlVtbl;
1793 object->IPropertyBag_iface.lpVtbl = &AviMuxIn_PropertyBagVtbl;
1794 object->IQualityControl_iface.lpVtbl = &AviMuxIn_QualityControlVtbl;
1796 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
1797 &IID_IMemAllocator, (void **)&object->samples_allocator);
1798 if (FAILED(hr))
1800 strmbase_sink_cleanup(&object->pin);
1801 free(object);
1802 return hr;
1805 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
1806 &IID_IMemAllocator, (void **)&object->pin.pAllocator);
1807 if (FAILED(hr))
1809 IMemAllocator_Release(object->samples_allocator);
1810 strmbase_sink_cleanup(&object->pin);
1811 free(object);
1812 return hr;
1815 object->indx = (AVISUPERINDEX *)&object->indx_data;
1816 object->ix = (AVISTDINDEX *)object->ix_data;
1818 avimux->in[avimux->input_pin_no++] = object;
1819 return S_OK;
1822 HRESULT avi_mux_create(IUnknown *outer, IUnknown **out)
1824 AviMux *avimux;
1825 HRESULT hr;
1827 if (!(avimux = calloc(1, sizeof(AviMux))))
1828 return E_OUTOFMEMORY;
1830 strmbase_filter_init(&avimux->filter, outer, &CLSID_AviDest, &filter_ops);
1831 avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl;
1832 avimux->IConfigInterleaving_iface.lpVtbl = &ConfigInterleavingVtbl;
1833 avimux->IMediaSeeking_iface.lpVtbl = &MediaSeekingVtbl;
1834 avimux->IPersistMediaPropertyBag_iface.lpVtbl = &PersistMediaPropertyBagVtbl;
1835 avimux->ISpecifyPropertyPages_iface.lpVtbl = &SpecifyPropertyPagesVtbl;
1837 strmbase_source_init(&avimux->source, &avimux->filter, L"AVI Out", &source_ops);
1838 avimux->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl;
1839 avimux->cur_stream = 0;
1840 avimux->cur_time = 0;
1841 avimux->stream = NULL;
1843 hr = create_input_pin(avimux);
1844 if(FAILED(hr)) {
1845 strmbase_source_cleanup(&avimux->source);
1846 strmbase_filter_cleanup(&avimux->filter);
1847 free(avimux);
1848 return hr;
1851 avimux->interleave = 10000000;
1853 TRACE("Created AVI mux %p.\n", avimux);
1854 ObjectRefCount(TRUE);
1855 *out = &avimux->filter.IUnknown_inner;
1856 return S_OK;