iphlpapi: Remove unnecessary memcpy from build_udp6_table.
[wine.git] / dlls / qcap / avimux.c
blob91a0b17f8e1c91b2548cb52c5f4e04ce6660e8e2
1 /*
2 * Copyright (C) 2013 Piotr Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <stdio.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wtypes.h"
27 #include "dshow.h"
28 #include "vfw.h"
29 #include "aviriff.h"
31 #include "qcap_main.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
37 #define MAX_PIN_NO 128
38 #define AVISUPERINDEX_ENTRIES 2000
39 #define AVISTDINDEX_ENTRIES 4000
40 #define ALIGN(x) ((x+1)/2*2)
42 typedef struct {
43 struct strmbase_sink pin;
44 IAMStreamControl IAMStreamControl_iface;
45 IPropertyBag IPropertyBag_iface;
46 IQualityControl IQualityControl_iface;
48 REFERENCE_TIME avg_time_per_frame;
49 REFERENCE_TIME stop;
50 int stream_id;
51 LONGLONG stream_time;
53 /* strl chunk */
54 AVISTREAMHEADER strh;
55 struct {
56 FOURCC fcc;
57 DWORD cb;
58 BYTE data[1];
59 } *strf;
60 AVISUPERINDEX *indx;
61 BYTE indx_data[FIELD_OFFSET(AVISUPERINDEX, aIndex[AVISUPERINDEX_ENTRIES])];
63 /* movi chunk */
64 int ix_off;
65 AVISTDINDEX *ix;
66 BYTE ix_data[FIELD_OFFSET(AVISTDINDEX, aIndex[AVISTDINDEX_ENTRIES])];
68 IMediaSample *samples_head;
69 IMemAllocator *samples_allocator;
70 } AviMuxIn;
72 typedef struct {
73 struct strmbase_filter filter;
74 IConfigAviMux IConfigAviMux_iface;
75 IConfigInterleaving IConfigInterleaving_iface;
76 IMediaSeeking IMediaSeeking_iface;
77 IPersistMediaPropertyBag IPersistMediaPropertyBag_iface;
78 ISpecifyPropertyPages ISpecifyPropertyPages_iface;
80 InterleavingMode mode;
81 REFERENCE_TIME interleave;
82 REFERENCE_TIME preroll;
84 struct strmbase_source source;
85 IQualityControl IQualityControl_iface;
87 int input_pin_no;
88 AviMuxIn *in[MAX_PIN_NO-1];
90 REFERENCE_TIME start, stop;
91 AVIMAINHEADER avih;
93 int idx1_entries;
94 int idx1_size;
95 AVIINDEXENTRY *idx1;
97 int cur_stream;
98 LONGLONG cur_time;
100 int buf_pos;
101 BYTE buf[65536];
103 int movi_off;
104 int out_pos;
105 int size;
106 IStream *stream;
107 } AviMux;
109 static HRESULT create_input_pin(AviMux*);
111 static inline AviMux* impl_from_strmbase_filter(struct strmbase_filter *filter)
113 return CONTAINING_RECORD(filter, AviMux, filter);
116 static struct strmbase_pin *avi_mux_get_pin(struct strmbase_filter *iface, unsigned int index)
118 AviMux *filter = impl_from_strmbase_filter(iface);
120 if (!index)
121 return &filter->source.pin;
122 else if (index <= filter->input_pin_no)
123 return &filter->in[index - 1]->pin.pin;
124 return NULL;
127 static void avi_mux_destroy(struct strmbase_filter *iface)
129 AviMux *filter = impl_from_strmbase_filter(iface);
130 int i;
132 strmbase_source_cleanup(&filter->source);
134 for (i = 0; i < filter->input_pin_no; ++i)
136 IPin_Disconnect(&filter->in[i]->pin.pin.IPin_iface);
137 IMemAllocator_Release(filter->in[i]->samples_allocator);
138 filter->in[i]->samples_allocator = NULL;
139 strmbase_sink_cleanup(&filter->in[i]->pin);
140 heap_free(filter->in[i]);
143 heap_free(filter->idx1);
144 strmbase_filter_cleanup(&filter->filter);
145 heap_free(filter);
146 ObjectRefCount(FALSE);
149 static HRESULT avi_mux_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
151 AviMux *filter = impl_from_strmbase_filter(iface);
153 if (IsEqualGUID(iid, &IID_IConfigAviMux))
154 *out = &filter->IConfigAviMux_iface;
155 else if (IsEqualGUID(iid, &IID_IConfigInterleaving))
156 *out = &filter->IConfigInterleaving_iface;
157 else if (IsEqualGUID(iid, &IID_IMediaSeeking))
158 *out = &filter->IMediaSeeking_iface;
159 else if (IsEqualGUID(iid, &IID_IPersistMediaPropertyBag))
160 *out = &filter->IPersistMediaPropertyBag_iface;
161 else if (IsEqualGUID(iid, &IID_ISpecifyPropertyPages))
162 *out = &filter->ISpecifyPropertyPages_iface;
163 else
164 return E_NOINTERFACE;
166 IUnknown_AddRef((IUnknown *)*out);
167 return S_OK;
170 static HRESULT out_flush(AviMux *This)
172 ULONG written;
173 HRESULT hr;
175 if(!This->buf_pos)
176 return S_OK;
178 hr = IStream_Write(This->stream, This->buf, This->buf_pos, &written);
179 if(FAILED(hr))
180 return hr;
181 if (written != This->buf_pos)
182 return E_FAIL;
184 This->buf_pos = 0;
185 return S_OK;
188 static HRESULT out_seek(AviMux *This, int pos)
190 LARGE_INTEGER li;
191 HRESULT hr;
193 hr = out_flush(This);
194 if(FAILED(hr))
195 return hr;
197 li.QuadPart = pos;
198 hr = IStream_Seek(This->stream, li, STREAM_SEEK_SET, NULL);
199 if(FAILED(hr))
200 return hr;
202 This->out_pos = pos;
203 if(This->out_pos > This->size)
204 This->size = This->out_pos;
205 return hr;
208 static HRESULT out_write(AviMux *This, const void *data, int size)
210 int chunk_size;
211 HRESULT hr;
213 while(1) {
214 if (size > sizeof(This->buf) - This->buf_pos)
215 chunk_size = sizeof(This->buf) - This->buf_pos;
216 else
217 chunk_size = size;
219 memcpy(This->buf + This->buf_pos, data, chunk_size);
220 size -= chunk_size;
221 data = (const BYTE*)data + chunk_size;
222 This->buf_pos += chunk_size;
223 This->out_pos += chunk_size;
224 if (This->out_pos > This->size)
225 This->size = This->out_pos;
227 if(!size)
228 break;
229 hr = out_flush(This);
230 if(FAILED(hr))
231 return hr;
234 return S_OK;
237 static inline HRESULT idx1_add_entry(AviMux *avimux, DWORD ckid, DWORD flags, DWORD off, DWORD len)
239 if(avimux->idx1_entries == avimux->idx1_size) {
240 AVIINDEXENTRY *new_idx = HeapReAlloc(GetProcessHeap(), 0, avimux->idx1,
241 sizeof(*avimux->idx1)*2*avimux->idx1_size);
242 if(!new_idx)
243 return E_OUTOFMEMORY;
245 avimux->idx1_size *= 2;
246 avimux->idx1 = new_idx;
249 avimux->idx1[avimux->idx1_entries].ckid = ckid;
250 avimux->idx1[avimux->idx1_entries].dwFlags = flags;
251 avimux->idx1[avimux->idx1_entries].dwChunkOffset = off;
252 avimux->idx1[avimux->idx1_entries].dwChunkLength = len;
253 avimux->idx1_entries++;
254 return S_OK;
257 static HRESULT flush_queue(AviMux *avimux, AviMuxIn *avimuxin, BOOL closing)
259 IMediaSample *sample, **prev, **head_prev;
260 BYTE *data;
261 RIFFCHUNK rf;
262 DWORD size;
263 DWORD flags;
264 HRESULT hr;
266 if (avimux->cur_stream != avimuxin->stream_id)
267 return S_OK;
269 while(avimuxin->samples_head) {
270 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
271 if(FAILED(hr))
272 return hr;
273 head_prev--;
275 hr = IMediaSample_GetPointer(*head_prev, (BYTE**)&prev);
276 if(FAILED(hr))
277 return hr;
278 prev--;
280 sample = *head_prev;
281 size = IMediaSample_GetActualDataLength(sample);
282 hr = IMediaSample_GetPointer(sample, &data);
283 if(FAILED(hr))
284 return hr;
285 flags = IMediaSample_IsDiscontinuity(sample)==S_OK ? AM_SAMPLE_TIMEDISCONTINUITY : 0;
286 if(IMediaSample_IsSyncPoint(sample) == S_OK)
287 flags |= AM_SAMPLE_SPLICEPOINT;
289 if (avimuxin->stream_time + (closing ? 0 : avimuxin->strh.dwScale) > avimux->cur_time
290 && !(flags & AM_SAMPLE_TIMEDISCONTINUITY))
292 if(closing)
293 break;
295 avimux->cur_stream++;
296 if(avimux->cur_stream >= avimux->input_pin_no-1) {
297 avimux->cur_time += avimux->interleave;
298 avimux->cur_stream = 0;
300 avimuxin = avimux->in[avimux->cur_stream];
301 continue;
304 if(avimuxin->ix->nEntriesInUse == AVISTDINDEX_ENTRIES) {
305 /* TODO: use output pins Deliver/Receive method */
306 hr = out_seek(avimux, avimuxin->ix_off);
307 if(FAILED(hr))
308 return hr;
309 hr = out_write(avimux, avimuxin->ix, sizeof(avimuxin->ix_data));
310 if(FAILED(hr))
311 return hr;
313 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].qwOffset = avimuxin->ix_off;
314 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwSize = sizeof(avimuxin->ix_data);
315 avimuxin->indx->aIndex[avimuxin->indx->nEntriesInUse].dwDuration = AVISTDINDEX_ENTRIES;
316 avimuxin->indx->nEntriesInUse++;
318 memset(avimuxin->ix->aIndex, 0, sizeof(avimuxin->ix->aIndex)*avimuxin->ix->nEntriesInUse);
319 avimuxin->ix->nEntriesInUse = 0;
320 avimuxin->ix->qwBaseOffset = 0;
322 avimuxin->ix_off = avimux->size;
323 avimux->size += sizeof(avimuxin->ix_data);
326 if(*head_prev == avimuxin->samples_head)
327 avimuxin->samples_head = NULL;
328 else
329 *head_prev = *prev;
331 avimuxin->stream_time += avimuxin->strh.dwScale;
332 avimuxin->strh.dwLength++;
333 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
334 if(!avimuxin->ix->qwBaseOffset)
335 avimuxin->ix->qwBaseOffset = avimux->size;
336 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwOffset =
337 avimux->size + sizeof(RIFFCHUNK) - avimuxin->ix->qwBaseOffset;
339 hr = out_seek(avimux, avimux->size);
340 if(FAILED(hr)) {
341 IMediaSample_Release(sample);
342 return hr;
345 avimuxin->ix->aIndex[avimuxin->ix->nEntriesInUse].dwSize = size |
346 (flags & AM_SAMPLE_SPLICEPOINT ? 0 : AVISTDINDEX_DELTAFRAME);
347 avimuxin->ix->nEntriesInUse++;
349 rf.fcc = FCC('0'+avimuxin->stream_id/10, '0'+avimuxin->stream_id%10,
350 'd', flags & AM_SAMPLE_SPLICEPOINT ? 'b' : 'c');
351 rf.cb = size;
352 hr = idx1_add_entry(avimux, rf.fcc, flags & AM_SAMPLE_SPLICEPOINT ? AVIIF_KEYFRAME : 0,
353 flags & AM_SAMPLE_TIMEDISCONTINUITY ?
354 avimux->idx1[avimux->idx1_entries-1].dwChunkOffset : avimux->size, size);
355 if(FAILED(hr)) {
356 IMediaSample_Release(sample);
357 return hr;
360 if(!(flags & AM_SAMPLE_TIMEDISCONTINUITY)) {
361 hr = out_write(avimux, &rf, sizeof(rf));
362 if(FAILED(hr)) {
363 IMediaSample_Release(sample);
364 return hr;
366 hr = out_write(avimux, data, size);
367 if(FAILED(hr)) {
368 IMediaSample_Release(sample);
369 return hr;
371 flags = 0;
372 hr = out_write(avimux, &flags, ALIGN(rf.cb)-rf.cb);
373 if(FAILED(hr)) {
374 IMediaSample_Release(sample);
375 return hr;
378 IMediaSample_Release(sample);
380 return S_OK;
383 static HRESULT queue_sample(AviMux *avimux, AviMuxIn *avimuxin, IMediaSample *sample)
385 IMediaSample **prev, **head_prev;
386 HRESULT hr;
388 hr = IMediaSample_GetPointer(sample, (BYTE**)&prev);
389 if(FAILED(hr))
390 return hr;
391 prev--;
393 if(avimuxin->samples_head) {
394 hr = IMediaSample_GetPointer(avimuxin->samples_head, (BYTE**)&head_prev);
395 if(FAILED(hr))
396 return hr;
397 head_prev--;
399 *prev = *head_prev;
400 *head_prev = sample;
401 }else {
402 *prev = sample;
404 avimuxin->samples_head = sample;
405 IMediaSample_AddRef(sample);
407 return flush_queue(avimux, avimuxin, FALSE);
410 static HRESULT avi_mux_cleanup_stream(struct strmbase_filter *iface)
412 AviMux *This = impl_from_strmbase_filter(iface);
413 HRESULT hr;
414 int i;
416 if (This->stream)
418 AVIEXTHEADER dmlh;
419 RIFFCHUNK rc;
420 RIFFLIST rl;
421 int idx1_off, empty_stream;
423 empty_stream = This->cur_stream;
424 for(i=empty_stream+1; ; i++) {
425 if(i >= This->input_pin_no-1)
426 i = 0;
427 if(i == empty_stream)
428 break;
430 This->cur_stream = i;
431 hr = flush_queue(This, This->in[This->cur_stream], TRUE);
432 if(FAILED(hr))
433 return hr;
436 idx1_off = This->size;
437 rc.fcc = ckidAVIOLDINDEX;
438 rc.cb = This->idx1_entries * sizeof(*This->idx1);
439 hr = out_write(This, &rc, sizeof(rc));
440 if(FAILED(hr))
441 return hr;
442 hr = out_write(This, This->idx1, This->idx1_entries * sizeof(*This->idx1));
443 if(FAILED(hr))
444 return hr;
445 /* native writes 8 '\0' characters after the end of RIFF data */
446 i = 0;
447 hr = out_write(This, &i, sizeof(i));
448 if(FAILED(hr))
449 return hr;
450 hr = out_write(This, &i, sizeof(i));
451 if(FAILED(hr))
452 return hr;
454 for(i=0; i<This->input_pin_no; i++) {
455 if(!This->in[i]->pin.pin.peer)
456 continue;
458 hr = out_seek(This, This->in[i]->ix_off);
459 if(FAILED(hr))
460 return hr;
462 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].qwOffset = This->in[i]->ix_off;
463 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwSize = sizeof(This->in[i]->ix_data);
464 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration = This->in[i]->strh.dwLength;
465 if(This->in[i]->indx->nEntriesInUse) {
466 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse].dwDuration -=
467 This->in[i]->indx->aIndex[This->in[i]->indx->nEntriesInUse-1].dwDuration;
469 This->in[i]->indx->nEntriesInUse++;
470 hr = out_write(This, This->in[i]->ix, sizeof(This->in[i]->ix_data));
471 if(FAILED(hr))
472 return hr;
475 hr = out_seek(This, 0);
476 if(FAILED(hr))
477 return hr;
479 rl.fcc = FCC('R','I','F','F');
480 rl.cb = This->size - sizeof(RIFFCHUNK) - 2 * sizeof(int);
481 rl.fccListType = FCC('A','V','I',' ');
482 hr = out_write(This, &rl, sizeof(rl));
483 if(FAILED(hr))
484 return hr;
486 rl.fcc = FCC('L','I','S','T');
487 rl.cb = This->movi_off - sizeof(RIFFLIST) - sizeof(RIFFCHUNK);
488 rl.fccListType = FCC('h','d','r','l');
489 hr = out_write(This, &rl, sizeof(rl));
490 if(FAILED(hr))
491 return hr;
493 /* FIXME: set This->avih.dwMaxBytesPerSec value */
494 This->avih.dwTotalFrames = (This->stop-This->start) / 10 / This->avih.dwMicroSecPerFrame;
495 hr = out_write(This, &This->avih, sizeof(This->avih));
496 if(FAILED(hr))
497 return hr;
499 for(i=0; i<This->input_pin_no; i++) {
500 if(!This->in[i]->pin.pin.peer)
501 continue;
503 rl.cb = sizeof(FOURCC) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK) +
504 This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
505 rl.fccListType = ckidSTREAMLIST;
506 hr = out_write(This, &rl, sizeof(rl));
507 if(FAILED(hr))
508 return hr;
510 hr = out_write(This, &This->in[i]->strh, sizeof(AVISTREAMHEADER));
511 if(FAILED(hr))
512 return hr;
514 hr = out_write(This, This->in[i]->strf, sizeof(RIFFCHUNK) + This->in[i]->strf->cb);
515 if(FAILED(hr))
516 return hr;
518 hr = out_write(This, This->in[i]->indx, sizeof(This->in[i]->indx_data));
519 if(FAILED(hr))
520 return hr;
523 rl.cb = sizeof(dmlh) + sizeof(FOURCC);
524 rl.fccListType = ckidODML;
525 hr = out_write(This, &rl, sizeof(rl));
526 if(FAILED(hr))
527 return hr;
529 memset(&dmlh, 0, sizeof(dmlh));
530 dmlh.fcc = ckidAVIEXTHEADER;
531 dmlh.cb = sizeof(dmlh) - sizeof(RIFFCHUNK);
532 dmlh.dwGrandFrames = This->in[0]->strh.dwLength;
533 hr = out_write(This, &dmlh, sizeof(dmlh));
535 rl.cb = idx1_off - This->movi_off - sizeof(RIFFCHUNK);
536 rl.fccListType = FCC('m','o','v','i');
537 out_write(This, &rl, sizeof(rl));
538 out_flush(This);
540 IStream_Release(This->stream);
541 This->stream = NULL;
544 return S_OK;
547 static HRESULT avi_mux_init_stream(struct strmbase_filter *iface)
549 AviMux *This = impl_from_strmbase_filter(iface);
550 HRESULT hr;
551 int i, stream_id;
553 if(This->mode != INTERLEAVE_FULL) {
554 FIXME("mode not supported (%d)\n", This->mode);
555 return E_NOTIMPL;
558 for(i=0; i<This->input_pin_no; i++) {
559 IMediaSeeking *ms;
560 LONGLONG cur, stop;
562 if(!This->in[i]->pin.pin.peer)
563 continue;
565 hr = IPin_QueryInterface(This->in[i]->pin.pin.peer,
566 &IID_IMediaSeeking, (void**)&ms);
567 if(FAILED(hr))
568 continue;
570 hr = IMediaSeeking_GetPositions(ms, &cur, &stop);
571 if(FAILED(hr)) {
572 IMediaSeeking_Release(ms);
573 continue;
576 FIXME("Use IMediaSeeking to fill stream header\n");
577 IMediaSeeking_Release(ms);
580 if (This->source.pMemInputPin)
582 hr = IMemInputPin_QueryInterface(This->source.pMemInputPin,
583 &IID_IStream, (void **)&This->stream);
584 if(FAILED(hr))
585 return hr;
588 This->idx1_entries = 0;
589 if(!This->idx1_size) {
590 This->idx1_size = 1024;
591 This->idx1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->idx1)*This->idx1_size);
592 if(!This->idx1)
593 return E_OUTOFMEMORY;
596 This->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER);
597 This->start = -1;
598 This->stop = -1;
599 memset(&This->avih, 0, sizeof(This->avih));
600 for(i=0; i<This->input_pin_no; i++) {
601 if(!This->in[i]->pin.pin.peer)
602 continue;
604 This->avih.dwStreams++;
605 This->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK)
606 + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
608 This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000);
609 This->in[i]->strh.dwRate = This->interleave;
611 hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator);
612 if(FAILED(hr)) {
613 if (This->stream)
615 IStream_Release(This->stream);
616 This->stream = NULL;
618 return hr;
622 This->movi_off = This->size;
623 This->size += sizeof(RIFFLIST);
625 idx1_add_entry(This, FCC('7','F','x','x'), 0, This->movi_off + sizeof(RIFFLIST), 0);
627 stream_id = 0;
628 for(i=0; i<This->input_pin_no; i++) {
629 if(!This->in[i]->pin.pin.peer)
630 continue;
632 This->in[i]->ix_off = This->size;
633 This->size += sizeof(This->in[i]->ix_data);
634 This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10);
635 This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK);
636 This->in[i]->ix->wLongsPerEntry = 2;
637 This->in[i]->ix->bIndexSubType = 0;
638 This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS;
639 This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b');
640 This->in[i]->ix->qwBaseOffset = 0;
642 This->in[i]->indx->fcc = ckidAVISUPERINDEX;
643 This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK);
644 This->in[i]->indx->wLongsPerEntry = 4;
645 This->in[i]->indx->bIndexSubType = 0;
646 This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES;
647 This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId;
648 This->in[i]->stream_id = stream_id++;
651 This->buf_pos = 0;
652 This->out_pos = 0;
654 This->avih.fcc = ckidMAINAVIHEADER;
655 This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK);
656 /* TODO: Use first video stream */
657 This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10;
658 This->avih.dwPaddingGranularity = 1;
659 This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX;
660 This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth;
661 This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight;
663 return S_OK;
666 static const struct strmbase_filter_ops filter_ops =
668 .filter_get_pin = avi_mux_get_pin,
669 .filter_destroy = avi_mux_destroy,
670 .filter_query_interface = avi_mux_query_interface,
671 .filter_init_stream = avi_mux_init_stream,
672 .filter_cleanup_stream = avi_mux_cleanup_stream,
675 static inline AviMux* impl_from_IConfigAviMux(IConfigAviMux *iface)
677 return CONTAINING_RECORD(iface, AviMux, IConfigAviMux_iface);
680 static HRESULT WINAPI ConfigAviMux_QueryInterface(
681 IConfigAviMux *iface, REFIID riid, void **ppv)
683 AviMux *This = impl_from_IConfigAviMux(iface);
684 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
687 static ULONG WINAPI ConfigAviMux_AddRef(IConfigAviMux *iface)
689 AviMux *This = impl_from_IConfigAviMux(iface);
690 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
693 static ULONG WINAPI ConfigAviMux_Release(IConfigAviMux *iface)
695 AviMux *This = impl_from_IConfigAviMux(iface);
696 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
699 static HRESULT WINAPI ConfigAviMux_SetMasterStream(IConfigAviMux *iface, LONG iStream)
701 AviMux *This = impl_from_IConfigAviMux(iface);
702 FIXME("(%p)->(%d)\n", This, iStream);
703 return E_NOTIMPL;
706 static HRESULT WINAPI ConfigAviMux_GetMasterStream(IConfigAviMux *iface, LONG *pStream)
708 AviMux *This = impl_from_IConfigAviMux(iface);
709 FIXME("(%p)->(%p)\n", This, pStream);
710 return E_NOTIMPL;
713 static HRESULT WINAPI ConfigAviMux_SetOutputCompatibilityIndex(
714 IConfigAviMux *iface, BOOL fOldIndex)
716 AviMux *This = impl_from_IConfigAviMux(iface);
717 FIXME("(%p)->(%x)\n", This, fOldIndex);
718 return E_NOTIMPL;
721 static HRESULT WINAPI ConfigAviMux_GetOutputCompatibilityIndex(
722 IConfigAviMux *iface, BOOL *pfOldIndex)
724 AviMux *This = impl_from_IConfigAviMux(iface);
725 FIXME("(%p)->(%p)\n", This, pfOldIndex);
726 return E_NOTIMPL;
729 static const IConfigAviMuxVtbl ConfigAviMuxVtbl = {
730 ConfigAviMux_QueryInterface,
731 ConfigAviMux_AddRef,
732 ConfigAviMux_Release,
733 ConfigAviMux_SetMasterStream,
734 ConfigAviMux_GetMasterStream,
735 ConfigAviMux_SetOutputCompatibilityIndex,
736 ConfigAviMux_GetOutputCompatibilityIndex
739 static inline AviMux* impl_from_IConfigInterleaving(IConfigInterleaving *iface)
741 return CONTAINING_RECORD(iface, AviMux, IConfigInterleaving_iface);
744 static HRESULT WINAPI ConfigInterleaving_QueryInterface(
745 IConfigInterleaving *iface, REFIID riid, void **ppv)
747 AviMux *This = impl_from_IConfigInterleaving(iface);
748 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
751 static ULONG WINAPI ConfigInterleaving_AddRef(IConfigInterleaving *iface)
753 AviMux *This = impl_from_IConfigInterleaving(iface);
754 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
757 static ULONG WINAPI ConfigInterleaving_Release(IConfigInterleaving *iface)
759 AviMux *This = impl_from_IConfigInterleaving(iface);
760 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
763 static HRESULT WINAPI ConfigInterleaving_put_Mode(
764 IConfigInterleaving *iface, InterleavingMode mode)
766 AviMux *This = impl_from_IConfigInterleaving(iface);
768 TRACE("(%p)->(%d)\n", This, mode);
770 if(mode>INTERLEAVE_NONE_BUFFERED)
771 return E_INVALIDARG;
773 if(This->mode != mode) {
774 if(This->source.pin.peer) {
775 HRESULT hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
776 if(FAILED(hr))
777 return hr;
780 This->mode = mode;
783 return S_OK;
786 static HRESULT WINAPI ConfigInterleaving_get_Mode(
787 IConfigInterleaving *iface, InterleavingMode *pMode)
789 AviMux *This = impl_from_IConfigInterleaving(iface);
790 FIXME("(%p)->(%p)\n", This, pMode);
791 return E_NOTIMPL;
794 static HRESULT WINAPI ConfigInterleaving_put_Interleaving(IConfigInterleaving *iface,
795 const REFERENCE_TIME *prtInterleave, const REFERENCE_TIME *prtPreroll)
797 AviMux *This = impl_from_IConfigInterleaving(iface);
799 TRACE("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
801 if(prtInterleave)
802 This->interleave = *prtInterleave;
803 if(prtPreroll)
804 This->preroll = *prtPreroll;
805 return S_OK;
808 static HRESULT WINAPI ConfigInterleaving_get_Interleaving(IConfigInterleaving *iface,
809 REFERENCE_TIME *prtInterleave, REFERENCE_TIME *prtPreroll)
811 AviMux *This = impl_from_IConfigInterleaving(iface);
812 FIXME("(%p)->(%p %p)\n", This, prtInterleave, prtPreroll);
813 return E_NOTIMPL;
816 static const IConfigInterleavingVtbl ConfigInterleavingVtbl = {
817 ConfigInterleaving_QueryInterface,
818 ConfigInterleaving_AddRef,
819 ConfigInterleaving_Release,
820 ConfigInterleaving_put_Mode,
821 ConfigInterleaving_get_Mode,
822 ConfigInterleaving_put_Interleaving,
823 ConfigInterleaving_get_Interleaving
826 static inline AviMux* impl_from_IMediaSeeking(IMediaSeeking *iface)
828 return CONTAINING_RECORD(iface, AviMux, IMediaSeeking_iface);
831 static HRESULT WINAPI MediaSeeking_QueryInterface(
832 IMediaSeeking *iface, REFIID riid, void **ppv)
834 AviMux *This = impl_from_IMediaSeeking(iface);
835 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
838 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
840 AviMux *This = impl_from_IMediaSeeking(iface);
841 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
844 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
846 AviMux *This = impl_from_IMediaSeeking(iface);
847 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
850 static HRESULT WINAPI MediaSeeking_GetCapabilities(
851 IMediaSeeking *iface, DWORD *pCapabilities)
853 AviMux *This = impl_from_IMediaSeeking(iface);
854 FIXME("(%p)->(%p)\n", This, pCapabilities);
855 return E_NOTIMPL;
858 static HRESULT WINAPI MediaSeeking_CheckCapabilities(
859 IMediaSeeking *iface, DWORD *pCapabilities)
861 AviMux *This = impl_from_IMediaSeeking(iface);
862 FIXME("(%p)->(%p)\n", This, pCapabilities);
863 return E_NOTIMPL;
866 static HRESULT WINAPI MediaSeeking_IsFormatSupported(
867 IMediaSeeking *iface, const GUID *pFormat)
869 AviMux *This = impl_from_IMediaSeeking(iface);
870 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
871 return E_NOTIMPL;
874 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(
875 IMediaSeeking *iface, GUID *pFormat)
877 AviMux *This = impl_from_IMediaSeeking(iface);
878 FIXME("(%p)->(%p)\n", This, pFormat);
879 return E_NOTIMPL;
882 static HRESULT WINAPI MediaSeeking_GetTimeFormat(
883 IMediaSeeking *iface, GUID *pFormat)
885 AviMux *This = impl_from_IMediaSeeking(iface);
886 FIXME("(%p)->(%p)\n", This, pFormat);
887 return E_NOTIMPL;
890 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(
891 IMediaSeeking *iface, const GUID *pFormat)
893 AviMux *This = impl_from_IMediaSeeking(iface);
894 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
895 return E_NOTIMPL;
898 static HRESULT WINAPI MediaSeeking_SetTimeFormat(
899 IMediaSeeking *iface, const GUID *pFormat)
901 AviMux *This = impl_from_IMediaSeeking(iface);
902 FIXME("(%p)->(%s)\n", This, debugstr_guid(pFormat));
903 return E_NOTIMPL;
906 static HRESULT WINAPI MediaSeeking_GetDuration(
907 IMediaSeeking *iface, LONGLONG *pDuration)
909 AviMux *This = impl_from_IMediaSeeking(iface);
910 FIXME("(%p)->(%p)\n", This, pDuration);
911 return E_NOTIMPL;
914 static HRESULT WINAPI MediaSeeking_GetStopPosition(
915 IMediaSeeking *iface, LONGLONG *pStop)
917 AviMux *This = impl_from_IMediaSeeking(iface);
918 FIXME("(%p)->(%p)\n", This, pStop);
919 return E_NOTIMPL;
922 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(
923 IMediaSeeking *iface, LONGLONG *pCurrent)
925 AviMux *This = impl_from_IMediaSeeking(iface);
926 FIXME("(%p)->(%p)\n", This, pCurrent);
927 return E_NOTIMPL;
930 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
931 const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
933 AviMux *This = impl_from_IMediaSeeking(iface);
934 FIXME("(%p)->(%p %s %s %s)\n", This, pTarget, debugstr_guid(pTargetFormat),
935 wine_dbgstr_longlong(Source), debugstr_guid(pSourceFormat));
936 return E_NOTIMPL;
939 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
940 DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
942 AviMux *This = impl_from_IMediaSeeking(iface);
943 FIXME("(%p)->(%p %x %p %x)\n", This, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
944 return E_NOTIMPL;
947 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
948 LONGLONG *pCurrent, LONGLONG *pStop)
950 AviMux *This = impl_from_IMediaSeeking(iface);
951 FIXME("(%p)->(%p %p)\n", This, pCurrent, pStop);
952 return E_NOTIMPL;
955 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
956 LONGLONG *pEarliest, LONGLONG *pLatest)
958 AviMux *This = impl_from_IMediaSeeking(iface);
959 FIXME("(%p)->(%p %p)\n", This, pEarliest, pLatest);
960 return E_NOTIMPL;
963 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
965 AviMux *This = impl_from_IMediaSeeking(iface);
966 FIXME("(%p)->(%lf)\n", This, dRate);
967 return E_NOTIMPL;
970 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
972 AviMux *This = impl_from_IMediaSeeking(iface);
973 FIXME("(%p)->(%p)\n", This, pdRate);
974 return E_NOTIMPL;
977 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
979 AviMux *This = impl_from_IMediaSeeking(iface);
980 FIXME("(%p)->(%p)\n", This, pllPreroll);
981 return E_NOTIMPL;
984 static const IMediaSeekingVtbl MediaSeekingVtbl = {
985 MediaSeeking_QueryInterface,
986 MediaSeeking_AddRef,
987 MediaSeeking_Release,
988 MediaSeeking_GetCapabilities,
989 MediaSeeking_CheckCapabilities,
990 MediaSeeking_IsFormatSupported,
991 MediaSeeking_QueryPreferredFormat,
992 MediaSeeking_GetTimeFormat,
993 MediaSeeking_IsUsingTimeFormat,
994 MediaSeeking_SetTimeFormat,
995 MediaSeeking_GetDuration,
996 MediaSeeking_GetStopPosition,
997 MediaSeeking_GetCurrentPosition,
998 MediaSeeking_ConvertTimeFormat,
999 MediaSeeking_SetPositions,
1000 MediaSeeking_GetPositions,
1001 MediaSeeking_GetAvailable,
1002 MediaSeeking_SetRate,
1003 MediaSeeking_GetRate,
1004 MediaSeeking_GetPreroll
1007 static inline AviMux* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag *iface)
1009 return CONTAINING_RECORD(iface, AviMux, IPersistMediaPropertyBag_iface);
1012 static HRESULT WINAPI PersistMediaPropertyBag_QueryInterface(
1013 IPersistMediaPropertyBag *iface, REFIID riid, void **ppv)
1015 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1016 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1019 static ULONG WINAPI PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag *iface)
1021 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1022 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1025 static ULONG WINAPI PersistMediaPropertyBag_Release(IPersistMediaPropertyBag *iface)
1027 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1028 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1031 static HRESULT WINAPI PersistMediaPropertyBag_GetClassID(
1032 IPersistMediaPropertyBag *iface, CLSID *pClassID)
1034 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1035 return IBaseFilter_GetClassID(&This->filter.IBaseFilter_iface, pClassID);
1038 static HRESULT WINAPI PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag *iface)
1040 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1041 FIXME("(%p)->()\n", This);
1042 return E_NOTIMPL;
1045 static HRESULT WINAPI PersistMediaPropertyBag_Load(IPersistMediaPropertyBag *iface,
1046 IMediaPropertyBag *pPropBag, IErrorLog *pErrorLog)
1048 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1049 FIXME("(%p)->()\n", This);
1050 return E_NOTIMPL;
1053 static HRESULT WINAPI PersistMediaPropertyBag_Save(IPersistMediaPropertyBag *iface,
1054 IMediaPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
1056 AviMux *This = impl_from_IPersistMediaPropertyBag(iface);
1057 FIXME("(%p)->()\n", This);
1058 return E_NOTIMPL;
1061 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl = {
1062 PersistMediaPropertyBag_QueryInterface,
1063 PersistMediaPropertyBag_AddRef,
1064 PersistMediaPropertyBag_Release,
1065 PersistMediaPropertyBag_GetClassID,
1066 PersistMediaPropertyBag_InitNew,
1067 PersistMediaPropertyBag_Load,
1068 PersistMediaPropertyBag_Save
1071 static inline AviMux* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages *iface)
1073 return CONTAINING_RECORD(iface, AviMux, ISpecifyPropertyPages_iface);
1076 static HRESULT WINAPI SpecifyPropertyPages_QueryInterface(
1077 ISpecifyPropertyPages *iface, REFIID riid, void **ppv)
1079 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1080 return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv);
1083 static ULONG WINAPI SpecifyPropertyPages_AddRef(ISpecifyPropertyPages *iface)
1085 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1086 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1089 static ULONG WINAPI SpecifyPropertyPages_Release(ISpecifyPropertyPages *iface)
1091 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1092 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1095 static HRESULT WINAPI SpecifyPropertyPages_GetPages(
1096 ISpecifyPropertyPages *iface, CAUUID *pPages)
1098 AviMux *This = impl_from_ISpecifyPropertyPages(iface);
1099 FIXME("(%p)->(%p)\n", This, pPages);
1100 return E_NOTIMPL;
1103 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = {
1104 SpecifyPropertyPages_QueryInterface,
1105 SpecifyPropertyPages_AddRef,
1106 SpecifyPropertyPages_Release,
1107 SpecifyPropertyPages_GetPages
1110 static inline AviMux *impl_from_source_pin(struct strmbase_pin *iface)
1112 return CONTAINING_RECORD(iface, AviMux, source.pin);
1115 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
1117 AviMux *filter = impl_from_source_pin(iface);
1119 if (IsEqualGUID(iid, &IID_IQualityControl))
1120 *out = &filter->IQualityControl_iface;
1121 else
1122 return E_NOINTERFACE;
1124 IUnknown_AddRef((IUnknown *)*out);
1125 return S_OK;
1128 static HRESULT source_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *amt)
1130 FIXME("(%p) stub\n", base);
1131 return S_OK;
1134 static HRESULT WINAPI AviMuxOut_AttemptConnection(struct strmbase_source *iface,
1135 IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1137 AviMux *filter = impl_from_source_pin(&iface->pin);
1138 PIN_DIRECTION dir;
1139 unsigned int i;
1140 HRESULT hr;
1142 hr = IPin_QueryDirection(pReceivePin, &dir);
1143 if(hr==S_OK && dir!=PINDIR_INPUT)
1144 return VFW_E_INVALID_DIRECTION;
1146 if (FAILED(hr = BaseOutputPinImpl_AttemptConnection(iface, pReceivePin, pmt)))
1147 return hr;
1149 for (i = 0; i < filter->input_pin_no; ++i)
1151 if (!filter->in[i]->pin.pin.peer)
1152 continue;
1154 hr = IFilterGraph_Reconnect(filter->filter.graph, &filter->in[i]->pin.pin.IPin_iface);
1155 if (FAILED(hr))
1157 IPin_Disconnect(&iface->pin.IPin_iface);
1158 break;
1162 return hr;
1165 static HRESULT source_get_media_type(struct strmbase_pin *base, unsigned int iPosition, AM_MEDIA_TYPE *amt)
1167 TRACE("(%p)->(%d %p)\n", base, iPosition, amt);
1169 if(iPosition > 0)
1170 return VFW_S_NO_MORE_ITEMS;
1172 amt->majortype = MEDIATYPE_Stream;
1173 amt->subtype = MEDIASUBTYPE_Avi;
1174 amt->bFixedSizeSamples = TRUE;
1175 amt->bTemporalCompression = FALSE;
1176 amt->lSampleSize = 1;
1177 amt->formattype = GUID_NULL;
1178 amt->pUnk = NULL;
1179 amt->cbFormat = 0;
1180 amt->pbFormat = NULL;
1181 return S_OK;
1184 static HRESULT WINAPI AviMuxOut_DecideAllocator(struct strmbase_source *base,
1185 IMemInputPin *pPin, IMemAllocator **pAlloc)
1187 ALLOCATOR_PROPERTIES req, actual;
1188 HRESULT hr;
1190 TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc);
1192 hr = BaseOutputPinImpl_InitAllocator(base, pAlloc);
1193 if(FAILED(hr))
1194 return hr;
1196 hr = IMemInputPin_GetAllocatorRequirements(pPin, &req);
1197 if(FAILED(hr))
1198 req.cbAlign = 1;
1199 req.cBuffers = 32;
1200 req.cbBuffer = 0;
1201 req.cbPrefix = 0;
1203 hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual);
1204 if(FAILED(hr))
1205 return hr;
1207 return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE);
1210 static const struct strmbase_source_ops source_ops =
1212 .base.pin_query_interface = source_query_interface,
1213 .base.pin_query_accept = source_query_accept,
1214 .base.pin_get_media_type = source_get_media_type,
1215 .pfnAttemptConnection = AviMuxOut_AttemptConnection,
1216 .pfnDecideAllocator = AviMuxOut_DecideAllocator,
1219 static inline AviMux* impl_from_out_IQualityControl(IQualityControl *iface)
1221 return CONTAINING_RECORD(iface, AviMux, IQualityControl_iface);
1224 static HRESULT WINAPI AviMuxOut_QualityControl_QueryInterface(
1225 IQualityControl *iface, REFIID riid, void **ppv)
1227 AviMux *This = impl_from_out_IQualityControl(iface);
1228 return IPin_QueryInterface(&This->source.pin.IPin_iface, riid, ppv);
1231 static ULONG WINAPI AviMuxOut_QualityControl_AddRef(IQualityControl *iface)
1233 AviMux *This = impl_from_out_IQualityControl(iface);
1234 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1237 static ULONG WINAPI AviMuxOut_QualityControl_Release(IQualityControl *iface)
1239 AviMux *This = impl_from_out_IQualityControl(iface);
1240 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1243 static HRESULT WINAPI AviMuxOut_QualityControl_Notify(IQualityControl *iface,
1244 IBaseFilter *pSelf, Quality q)
1246 AviMux *This = impl_from_out_IQualityControl(iface);
1247 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This, pSelf,
1248 q.Type, q.Proportion,
1249 wine_dbgstr_longlong(q.Late),
1250 wine_dbgstr_longlong(q.TimeStamp));
1251 return E_NOTIMPL;
1254 static HRESULT WINAPI AviMuxOut_QualityControl_SetSink(
1255 IQualityControl *iface, IQualityControl *piqc)
1257 AviMux *This = impl_from_out_IQualityControl(iface);
1258 FIXME("(%p)->(%p)\n", This, piqc);
1259 return E_NOTIMPL;
1262 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl = {
1263 AviMuxOut_QualityControl_QueryInterface,
1264 AviMuxOut_QualityControl_AddRef,
1265 AviMuxOut_QualityControl_Release,
1266 AviMuxOut_QualityControl_Notify,
1267 AviMuxOut_QualityControl_SetSink
1270 static inline AviMuxIn *impl_sink_from_strmbase_pin(struct strmbase_pin *iface)
1272 return CONTAINING_RECORD(iface, AviMuxIn, pin.pin.IPin_iface);
1275 static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
1277 AviMuxIn *pin = impl_sink_from_strmbase_pin(iface);
1279 if (IsEqualGUID(iid, &IID_IAMStreamControl))
1280 *out = &pin->IAMStreamControl_iface;
1281 else if (IsEqualGUID(iid, &IID_IMemInputPin))
1282 *out = &pin->pin.IMemInputPin_iface;
1283 else if (IsEqualGUID(iid, &IID_IPropertyBag))
1284 *out = &pin->IPropertyBag_iface;
1285 else if (IsEqualGUID(iid, &IID_IQualityControl))
1286 *out = &pin->IQualityControl_iface;
1287 else
1288 return E_NOINTERFACE;
1290 IUnknown_AddRef((IUnknown *)*out);
1291 return S_OK;
1294 static HRESULT sink_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *pmt)
1296 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) &&
1297 IsEqualIID(&pmt->formattype, &FORMAT_WaveFormatEx))
1298 return S_OK;
1299 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Interleaved) &&
1300 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo))
1301 return S_OK;
1302 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1303 (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo) ||
1304 IsEqualIID(&pmt->formattype, &FORMAT_DvInfo)))
1305 return S_OK;
1306 return S_FALSE;
1309 static HRESULT WINAPI AviMuxIn_Receive(struct strmbase_sink *base, IMediaSample *pSample)
1311 AviMux *avimux = impl_from_strmbase_filter(base->pin.filter);
1312 AviMuxIn *avimuxin = CONTAINING_RECORD(base, AviMuxIn, pin);
1313 REFERENCE_TIME start, stop;
1314 IMediaSample *sample;
1315 int frames_no;
1316 IMediaSample2 *ms2;
1317 BYTE *frame, *buf;
1318 DWORD max_size, size;
1319 DWORD flags;
1320 HRESULT hr;
1322 TRACE("pin %p, pSample %p.\n", avimuxin, pSample);
1324 hr = IMediaSample_QueryInterface(pSample, &IID_IMediaSample2, (void**)&ms2);
1325 if(SUCCEEDED(hr)) {
1326 AM_SAMPLE2_PROPERTIES props;
1328 memset(&props, 0, sizeof(props));
1329 hr = IMediaSample2_GetProperties(ms2, sizeof(props), (BYTE*)&props);
1330 IMediaSample2_Release(ms2);
1331 if(FAILED(hr))
1332 return hr;
1334 flags = props.dwSampleFlags;
1335 frame = props.pbBuffer;
1336 size = props.lActual;
1337 }else {
1338 flags = IMediaSample_IsSyncPoint(pSample) == S_OK ? AM_SAMPLE_SPLICEPOINT : 0;
1339 hr = IMediaSample_GetPointer(pSample, &frame);
1340 if(FAILED(hr))
1341 return hr;
1342 size = IMediaSample_GetActualDataLength(pSample);
1345 if(!avimuxin->pin.pin.mt.bTemporalCompression)
1346 flags |= AM_SAMPLE_SPLICEPOINT;
1348 hr = IMediaSample_GetTime(pSample, &start, &stop);
1349 if(FAILED(hr))
1350 return hr;
1352 if(avimuxin->stop>stop)
1353 return VFW_E_START_TIME_AFTER_END;
1355 if(avimux->start == -1)
1356 avimux->start = start;
1357 if(avimux->stop < stop)
1358 avimux->stop = stop;
1360 if(avimux->avih.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1361 avimux->avih.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1362 if(avimuxin->strh.dwSuggestedBufferSize < ALIGN(size)+sizeof(RIFFCHUNK))
1363 avimuxin->strh.dwSuggestedBufferSize = ALIGN(size) + sizeof(RIFFCHUNK);
1365 frames_no = 1;
1366 if(avimuxin->stop!=-1 && start > avimuxin->stop) {
1367 frames_no += (double)(start - avimuxin->stop) / 10000000
1368 * avimuxin->strh.dwRate / avimuxin->strh.dwScale + 0.5;
1370 avimuxin->stop = stop;
1372 while(--frames_no) {
1373 /* TODO: store all control frames in one buffer */
1374 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1375 if(FAILED(hr))
1376 return hr;
1377 hr = IMediaSample_SetActualDataLength(sample, 0);
1378 if(SUCCEEDED(hr))
1379 hr = IMediaSample_SetDiscontinuity(sample, TRUE);
1380 if(SUCCEEDED(hr))
1381 hr = IMediaSample_SetSyncPoint(sample, FALSE);
1382 if(SUCCEEDED(hr))
1383 hr = queue_sample(avimux, avimuxin, sample);
1384 IMediaSample_Release(sample);
1385 if(FAILED(hr))
1386 return hr;
1389 hr = IMemAllocator_GetBuffer(avimuxin->samples_allocator, &sample, NULL, NULL, 0);
1390 if(FAILED(hr))
1391 return hr;
1392 max_size = IMediaSample_GetSize(sample);
1393 if(size > max_size)
1394 size = max_size;
1395 hr = IMediaSample_SetActualDataLength(sample, size);
1396 if(SUCCEEDED(hr))
1397 hr = IMediaSample_SetDiscontinuity(sample, FALSE);
1398 if(SUCCEEDED(hr))
1399 hr = IMediaSample_SetSyncPoint(sample, flags & AM_SAMPLE_SPLICEPOINT);
1400 /* TODO: avoid unnecessary copying */
1401 if(SUCCEEDED(hr))
1402 hr = IMediaSample_GetPointer(sample, &buf);
1403 if(SUCCEEDED(hr)) {
1404 memcpy(buf, frame, size);
1405 hr = queue_sample(avimux, avimuxin, sample);
1407 IMediaSample_Release(sample);
1409 return hr;
1412 static HRESULT avi_mux_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt)
1414 AviMuxIn *avimuxin = impl_sink_from_strmbase_pin(&iface->pin);
1415 AviMux *This = impl_from_strmbase_filter(iface->pin.filter);
1416 HRESULT hr;
1418 if(!pmt)
1419 return E_POINTER;
1421 if(IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) &&
1422 IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
1423 ALLOCATOR_PROPERTIES req, act;
1424 VIDEOINFOHEADER *vih;
1425 int size;
1427 vih = (VIDEOINFOHEADER*)pmt->pbFormat;
1428 avimuxin->strh.fcc = ckidSTREAMHEADER;
1429 avimuxin->strh.cb = sizeof(AVISTREAMHEADER) - FIELD_OFFSET(AVISTREAMHEADER, fccType);
1430 avimuxin->strh.fccType = streamtypeVIDEO;
1431 /* FIXME: fccHandler should be set differently */
1432 avimuxin->strh.fccHandler = vih->bmiHeader.biCompression ?
1433 vih->bmiHeader.biCompression : FCC('D','I','B',' ');
1434 avimuxin->avg_time_per_frame = vih->AvgTimePerFrame;
1435 avimuxin->stop = -1;
1437 req.cBuffers = 32;
1438 req.cbBuffer = vih->bmiHeader.biSizeImage;
1439 req.cbAlign = 1;
1440 req.cbPrefix = sizeof(void*);
1441 hr = IMemAllocator_SetProperties(avimuxin->samples_allocator, &req, &act);
1442 if(SUCCEEDED(hr))
1443 hr = IMemAllocator_Commit(avimuxin->samples_allocator);
1444 if (FAILED(hr))
1445 return hr;
1447 size = pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader);
1448 avimuxin->strf = CoTaskMemAlloc(sizeof(RIFFCHUNK) + ALIGN(FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed])));
1449 avimuxin->strf->fcc = ckidSTREAMFORMAT;
1450 avimuxin->strf->cb = FIELD_OFFSET(BITMAPINFO, bmiColors[vih->bmiHeader.biClrUsed]);
1451 if(size > avimuxin->strf->cb)
1452 size = avimuxin->strf->cb;
1453 memcpy(avimuxin->strf->data, &vih->bmiHeader, size);
1454 }else {
1455 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt->majortype),
1456 debugstr_guid(&pmt->formattype));
1457 return E_NOTIMPL;
1460 return create_input_pin(This);
1463 static void avi_mux_sink_disconnect(struct strmbase_sink *iface)
1465 AviMuxIn *avimuxin = impl_sink_from_strmbase_pin(&iface->pin);
1466 IMediaSample **prev, *cur;
1468 IMemAllocator_Decommit(avimuxin->samples_allocator);
1469 while(avimuxin->samples_head) {
1470 cur = avimuxin->samples_head;
1471 if (FAILED(IMediaSample_GetPointer(cur, (BYTE **)&prev)))
1472 break;
1473 prev--;
1475 cur = avimuxin->samples_head;
1476 avimuxin->samples_head = *prev;
1477 IMediaSample_Release(cur);
1479 if(cur == avimuxin->samples_head)
1480 avimuxin->samples_head = NULL;
1482 CoTaskMemFree(avimuxin->strf);
1483 avimuxin->strf = NULL;
1486 static const struct strmbase_sink_ops sink_ops =
1488 .base.pin_query_interface = sink_query_interface,
1489 .base.pin_query_accept = sink_query_accept,
1490 .base.pin_get_media_type = strmbase_pin_get_media_type,
1491 .pfnReceive = AviMuxIn_Receive,
1492 .sink_connect = avi_mux_sink_connect,
1493 .sink_disconnect = avi_mux_sink_disconnect,
1496 static inline AviMux* impl_from_in_IPin(IPin *iface)
1498 struct strmbase_pin *pin = CONTAINING_RECORD(iface, struct strmbase_pin, IPin_iface);
1499 return impl_from_strmbase_filter(pin->filter);
1502 static inline AviMuxIn* AviMuxIn_from_IAMStreamControl(IAMStreamControl *iface)
1504 return CONTAINING_RECORD(iface, AviMuxIn, IAMStreamControl_iface);
1507 static HRESULT WINAPI AviMuxIn_AMStreamControl_QueryInterface(
1508 IAMStreamControl *iface, REFIID riid, void **ppv)
1510 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1511 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1514 static ULONG WINAPI AviMuxIn_AMStreamControl_AddRef(IAMStreamControl *iface)
1516 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1517 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1518 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1521 static ULONG WINAPI AviMuxIn_AMStreamControl_Release(IAMStreamControl *iface)
1523 AviMuxIn *avimuxin = AviMuxIn_from_IAMStreamControl(iface);
1524 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1525 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1528 static HRESULT WINAPI AviMuxIn_AMStreamControl_StartAt(IAMStreamControl *iface,
1529 const REFERENCE_TIME *start, DWORD cookie)
1531 FIXME("iface %p, start %p, cookie %#x, stub!\n", iface, start, cookie);
1532 return E_NOTIMPL;
1535 static HRESULT WINAPI AviMuxIn_AMStreamControl_StopAt(IAMStreamControl *iface,
1536 const REFERENCE_TIME *stop, BOOL send_extra, DWORD cookie)
1538 FIXME("iface %p, stop %p, send_extra %d, cookie %#x, stub!\n", iface, stop, send_extra, cookie);
1539 return E_NOTIMPL;
1542 static HRESULT WINAPI AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl *iface,
1543 AM_STREAM_INFO *info)
1545 FIXME("iface %p, info %p, stub!\n", iface, info);
1546 return E_NOTIMPL;
1549 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl = {
1550 AviMuxIn_AMStreamControl_QueryInterface,
1551 AviMuxIn_AMStreamControl_AddRef,
1552 AviMuxIn_AMStreamControl_Release,
1553 AviMuxIn_AMStreamControl_StartAt,
1554 AviMuxIn_AMStreamControl_StopAt,
1555 AviMuxIn_AMStreamControl_GetInfo
1558 static inline AviMuxIn* AviMuxIn_from_IMemInputPin(IMemInputPin *iface)
1560 return CONTAINING_RECORD(iface, AviMuxIn, pin.IMemInputPin_iface);
1563 static HRESULT WINAPI AviMuxIn_MemInputPin_QueryInterface(
1564 IMemInputPin *iface, REFIID riid, void **ppv)
1566 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1567 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1570 static ULONG WINAPI AviMuxIn_MemInputPin_AddRef(IMemInputPin *iface)
1572 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1573 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1574 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1577 static ULONG WINAPI AviMuxIn_MemInputPin_Release(IMemInputPin *iface)
1579 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1580 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1581 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1584 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocator(
1585 IMemInputPin *iface, IMemAllocator **ppAllocator)
1587 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1589 TRACE("pin %p, ppAllocator %p.\n", avimuxin, ppAllocator);
1591 if(!ppAllocator)
1592 return E_POINTER;
1594 IMemAllocator_AddRef(avimuxin->pin.pAllocator);
1595 *ppAllocator = avimuxin->pin.pAllocator;
1596 return S_OK;
1599 static HRESULT WINAPI AviMuxIn_MemInputPin_NotifyAllocator(
1600 IMemInputPin *iface, IMemAllocator *pAllocator, BOOL bReadOnly)
1602 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1603 ALLOCATOR_PROPERTIES props;
1604 HRESULT hr;
1606 TRACE("pin %p, pAllocator %p, bReadOnly %d.\n", avimuxin, pAllocator, bReadOnly);
1608 if(!pAllocator)
1609 return E_POINTER;
1611 memset(&props, 0, sizeof(props));
1612 hr = IMemAllocator_GetProperties(pAllocator, &props);
1613 if(FAILED(hr))
1614 return hr;
1616 props.cbAlign = 1;
1617 props.cbPrefix = 8;
1618 return IMemAllocator_SetProperties(avimuxin->pin.pAllocator, &props, &props);
1621 static HRESULT WINAPI AviMuxIn_MemInputPin_GetAllocatorRequirements(
1622 IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps)
1624 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1626 TRACE("pin %p, pProps %p.\n", avimuxin, pProps);
1628 if(!pProps)
1629 return E_POINTER;
1631 pProps->cbAlign = 1;
1632 pProps->cbPrefix = 8;
1633 return S_OK;
1636 static HRESULT WINAPI AviMuxIn_MemInputPin_Receive(
1637 IMemInputPin *iface, IMediaSample *pSample)
1639 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1641 TRACE("pin %p, pSample %p.\n", avimuxin, pSample);
1643 return avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSample);
1646 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin *iface,
1647 IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed)
1649 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1650 HRESULT hr = S_OK;
1652 TRACE("pin %p, pSamples %p, nSamples %d, nSamplesProcessed %p.\n",
1653 avimuxin, pSamples, nSamples, nSamplesProcessed);
1655 for(*nSamplesProcessed=0; *nSamplesProcessed<nSamples; (*nSamplesProcessed)++)
1657 hr = avimuxin->pin.pFuncsTable->pfnReceive(&avimuxin->pin, pSamples[*nSamplesProcessed]);
1658 if(hr != S_OK)
1659 break;
1662 return hr;
1665 static HRESULT WINAPI AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1667 AviMuxIn *avimuxin = AviMuxIn_from_IMemInputPin(iface);
1668 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1669 HRESULT hr;
1671 TRACE("avimuxin %p.\n", avimuxin);
1673 if(!This->source.pMemInputPin)
1674 return S_FALSE;
1676 hr = IMemInputPin_ReceiveCanBlock(This->source.pMemInputPin);
1677 return hr != S_FALSE ? S_OK : S_FALSE;
1680 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl = {
1681 AviMuxIn_MemInputPin_QueryInterface,
1682 AviMuxIn_MemInputPin_AddRef,
1683 AviMuxIn_MemInputPin_Release,
1684 AviMuxIn_MemInputPin_GetAllocator,
1685 AviMuxIn_MemInputPin_NotifyAllocator,
1686 AviMuxIn_MemInputPin_GetAllocatorRequirements,
1687 AviMuxIn_MemInputPin_Receive,
1688 AviMuxIn_MemInputPin_ReceiveMultiple,
1689 AviMuxIn_MemInputPin_ReceiveCanBlock
1692 static inline AviMuxIn* AviMuxIn_from_IPropertyBag(IPropertyBag *iface)
1694 return CONTAINING_RECORD(iface, AviMuxIn, IPropertyBag_iface);
1697 static HRESULT WINAPI AviMuxIn_PropertyBag_QueryInterface(
1698 IPropertyBag *iface, REFIID riid, void **ppv)
1700 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1701 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1704 static ULONG WINAPI AviMuxIn_PropertyBag_AddRef(IPropertyBag *iface)
1706 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1707 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1708 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1711 static ULONG WINAPI AviMuxIn_PropertyBag_Release(IPropertyBag *iface)
1713 AviMuxIn *avimuxin = AviMuxIn_from_IPropertyBag(iface);
1714 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1715 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1718 static HRESULT WINAPI AviMuxIn_PropertyBag_Read(IPropertyBag *iface,
1719 const WCHAR *name, VARIANT *value, IErrorLog *error_log)
1721 FIXME("iface %p, name %s, value %p, error_log %p, stub!\n",
1722 iface, debugstr_w(name), value, error_log);
1723 return E_NOTIMPL;
1726 static HRESULT WINAPI AviMuxIn_PropertyBag_Write(IPropertyBag *iface,
1727 const WCHAR *name, VARIANT *value)
1729 FIXME("iface %p, name %s, value %s, stub!\n",
1730 iface, debugstr_w(name), debugstr_variant(value));
1731 return E_NOTIMPL;
1734 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl = {
1735 AviMuxIn_PropertyBag_QueryInterface,
1736 AviMuxIn_PropertyBag_AddRef,
1737 AviMuxIn_PropertyBag_Release,
1738 AviMuxIn_PropertyBag_Read,
1739 AviMuxIn_PropertyBag_Write
1742 static inline AviMuxIn* AviMuxIn_from_IQualityControl(IQualityControl *iface)
1744 return CONTAINING_RECORD(iface, AviMuxIn, IQualityControl_iface);
1747 static HRESULT WINAPI AviMuxIn_QualityControl_QueryInterface(
1748 IQualityControl *iface, REFIID riid, void **ppv)
1750 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1751 return IPin_QueryInterface(&avimuxin->pin.pin.IPin_iface, riid, ppv);
1754 static ULONG WINAPI AviMuxIn_QualityControl_AddRef(IQualityControl *iface)
1756 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1757 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1758 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
1761 static ULONG WINAPI AviMuxIn_QualityControl_Release(IQualityControl *iface)
1763 AviMuxIn *avimuxin = AviMuxIn_from_IQualityControl(iface);
1764 AviMux *This = impl_from_in_IPin(&avimuxin->pin.pin.IPin_iface);
1765 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
1768 static HRESULT WINAPI AviMuxIn_QualityControl_Notify(IQualityControl *iface,
1769 IBaseFilter *filter, Quality q)
1771 FIXME("iface %p, filter %p, type %u, proportion %d, late %s, timestamp %s, stub!\n",
1772 iface, filter, q.Type, q.Proportion, wine_dbgstr_longlong(q.Late),
1773 wine_dbgstr_longlong(q.TimeStamp));
1774 return E_NOTIMPL;
1777 static HRESULT WINAPI AviMuxIn_QualityControl_SetSink(IQualityControl *iface, IQualityControl *sink)
1779 FIXME("iface %p, sink %p, stub!\n", iface, sink);
1780 return E_NOTIMPL;
1783 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl = {
1784 AviMuxIn_QualityControl_QueryInterface,
1785 AviMuxIn_QualityControl_AddRef,
1786 AviMuxIn_QualityControl_Release,
1787 AviMuxIn_QualityControl_Notify,
1788 AviMuxIn_QualityControl_SetSink
1791 static HRESULT create_input_pin(AviMux *avimux)
1793 WCHAR name[] = {'I','n','p','u','t',' ','0','0',0};
1794 AviMuxIn *object;
1795 HRESULT hr;
1797 if(avimux->input_pin_no >= MAX_PIN_NO-1)
1798 return E_FAIL;
1800 name[7] = '0' + (avimux->input_pin_no+1) % 10;
1801 name[6] = '0' + (avimux->input_pin_no+1) / 10;
1803 if (!(object = heap_alloc_zero(sizeof(*object))))
1804 return E_OUTOFMEMORY;
1806 strmbase_sink_init(&object->pin, &avimux->filter, name, &sink_ops, NULL);
1807 object->pin.IMemInputPin_iface.lpVtbl = &AviMuxIn_MemInputPinVtbl;
1808 object->IAMStreamControl_iface.lpVtbl = &AviMuxIn_AMStreamControlVtbl;
1809 object->IPropertyBag_iface.lpVtbl = &AviMuxIn_PropertyBagVtbl;
1810 object->IQualityControl_iface.lpVtbl = &AviMuxIn_QualityControlVtbl;
1812 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
1813 &IID_IMemAllocator, (void **)&object->samples_allocator);
1814 if (FAILED(hr))
1816 strmbase_sink_cleanup(&object->pin);
1817 heap_free(object);
1818 return hr;
1821 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
1822 &IID_IMemAllocator, (void **)&object->pin.pAllocator);
1823 if (FAILED(hr))
1825 IMemAllocator_Release(object->samples_allocator);
1826 strmbase_sink_cleanup(&object->pin);
1827 heap_free(object);
1828 return hr;
1831 object->indx = (AVISUPERINDEX *)&object->indx_data;
1832 object->ix = (AVISTDINDEX *)object->ix_data;
1834 avimux->in[avimux->input_pin_no++] = object;
1835 return S_OK;
1838 IUnknown * WINAPI QCAP_createAVIMux(IUnknown *outer, HRESULT *phr)
1840 static const WCHAR output_name[] = {'A','V','I',' ','O','u','t',0};
1842 AviMux *avimux;
1843 PIN_INFO info;
1844 HRESULT hr;
1846 avimux = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AviMux));
1847 if(!avimux) {
1848 *phr = E_OUTOFMEMORY;
1849 return NULL;
1852 strmbase_filter_init(&avimux->filter, outer, &CLSID_AviDest, &filter_ops);
1853 avimux->IConfigAviMux_iface.lpVtbl = &ConfigAviMuxVtbl;
1854 avimux->IConfigInterleaving_iface.lpVtbl = &ConfigInterleavingVtbl;
1855 avimux->IMediaSeeking_iface.lpVtbl = &MediaSeekingVtbl;
1856 avimux->IPersistMediaPropertyBag_iface.lpVtbl = &PersistMediaPropertyBagVtbl;
1857 avimux->ISpecifyPropertyPages_iface.lpVtbl = &SpecifyPropertyPagesVtbl;
1859 info.dir = PINDIR_OUTPUT;
1860 info.pFilter = &avimux->filter.IBaseFilter_iface;
1861 lstrcpyW(info.achName, output_name);
1862 strmbase_source_init(&avimux->source, &avimux->filter, output_name, &source_ops);
1863 avimux->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl;
1864 avimux->cur_stream = 0;
1865 avimux->cur_time = 0;
1866 avimux->stream = NULL;
1868 hr = create_input_pin(avimux);
1869 if(FAILED(hr)) {
1870 strmbase_source_cleanup(&avimux->source);
1871 strmbase_filter_cleanup(&avimux->filter);
1872 HeapFree(GetProcessHeap(), 0, avimux);
1873 *phr = hr;
1874 return NULL;
1877 avimux->interleave = 10000000;
1879 ObjectRefCount(TRUE);
1880 *phr = S_OK;
1881 return &avimux->filter.IUnknown_inner;