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"
23 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
25 #define MAX_PIN_NO 128
26 #define AVISUPERINDEX_ENTRIES 2000
27 #define AVISTDINDEX_ENTRIES 4000
28 #define ALIGN(x) ((x+1)/2*2)
31 struct strmbase_sink pin
;
32 IAMStreamControl IAMStreamControl_iface
;
33 IPropertyBag IPropertyBag_iface
;
34 IQualityControl IQualityControl_iface
;
36 REFERENCE_TIME avg_time_per_frame
;
49 BYTE indx_data
[FIELD_OFFSET(AVISUPERINDEX
, aIndex
[AVISUPERINDEX_ENTRIES
])];
54 BYTE ix_data
[FIELD_OFFSET(AVISTDINDEX
, aIndex
[AVISTDINDEX_ENTRIES
])];
56 IMediaSample
*samples_head
;
57 IMemAllocator
*samples_allocator
;
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
;
76 AviMuxIn
*in
[MAX_PIN_NO
-1];
78 REFERENCE_TIME start
, stop
;
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
);
109 return &filter
->source
.pin
;
110 else if (index
<= filter
->input_pin_no
)
111 return &filter
->in
[index
- 1]->pin
.pin
;
115 static void avi_mux_destroy(struct strmbase_filter
*iface
)
117 AviMux
*filter
= impl_from_strmbase_filter(iface
);
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
);
132 strmbase_filter_cleanup(&filter
->filter
);
136 static HRESULT
avi_mux_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
138 AviMux
*filter
= impl_from_strmbase_filter(iface
);
140 if (IsEqualGUID(iid
, &IID_IConfigAviMux
))
141 *out
= &filter
->IConfigAviMux_iface
;
142 else if (IsEqualGUID(iid
, &IID_IConfigInterleaving
))
143 *out
= &filter
->IConfigInterleaving_iface
;
144 else if (IsEqualGUID(iid
, &IID_IMediaSeeking
))
145 *out
= &filter
->IMediaSeeking_iface
;
146 else if (IsEqualGUID(iid
, &IID_IPersistMediaPropertyBag
))
147 *out
= &filter
->IPersistMediaPropertyBag_iface
;
148 else if (IsEqualGUID(iid
, &IID_ISpecifyPropertyPages
))
149 *out
= &filter
->ISpecifyPropertyPages_iface
;
151 return E_NOINTERFACE
;
153 IUnknown_AddRef((IUnknown
*)*out
);
157 static HRESULT
out_flush(AviMux
*This
)
165 hr
= IStream_Write(This
->stream
, This
->buf
, This
->buf_pos
, &written
);
168 if (written
!= This
->buf_pos
)
175 static HRESULT
out_seek(AviMux
*This
, int pos
)
180 hr
= out_flush(This
);
185 hr
= IStream_Seek(This
->stream
, li
, STREAM_SEEK_SET
, NULL
);
190 if(This
->out_pos
> This
->size
)
191 This
->size
= This
->out_pos
;
195 static HRESULT
out_write(AviMux
*This
, const void *data
, int size
)
201 if (size
> sizeof(This
->buf
) - This
->buf_pos
)
202 chunk_size
= sizeof(This
->buf
) - This
->buf_pos
;
206 memcpy(This
->buf
+ This
->buf_pos
, data
, chunk_size
);
208 data
= (const BYTE
*)data
+ chunk_size
;
209 This
->buf_pos
+= chunk_size
;
210 This
->out_pos
+= chunk_size
;
211 if (This
->out_pos
> This
->size
)
212 This
->size
= This
->out_pos
;
216 hr
= out_flush(This
);
224 static inline HRESULT
idx1_add_entry(AviMux
*avimux
, DWORD ckid
, DWORD flags
, DWORD off
, DWORD len
)
226 if(avimux
->idx1_entries
== avimux
->idx1_size
) {
227 AVIINDEXENTRY
*new_idx
= realloc(avimux
->idx1
, sizeof(*avimux
->idx1
) * 2 * avimux
->idx1_size
);
229 return E_OUTOFMEMORY
;
231 avimux
->idx1_size
*= 2;
232 avimux
->idx1
= new_idx
;
235 avimux
->idx1
[avimux
->idx1_entries
].ckid
= ckid
;
236 avimux
->idx1
[avimux
->idx1_entries
].dwFlags
= flags
;
237 avimux
->idx1
[avimux
->idx1_entries
].dwChunkOffset
= off
;
238 avimux
->idx1
[avimux
->idx1_entries
].dwChunkLength
= len
;
239 avimux
->idx1_entries
++;
243 static HRESULT
flush_queue(AviMux
*avimux
, AviMuxIn
*avimuxin
, BOOL closing
)
245 IMediaSample
*sample
, **prev
, **head_prev
;
252 if (avimux
->cur_stream
!= avimuxin
->stream_id
)
255 while(avimuxin
->samples_head
) {
256 hr
= IMediaSample_GetPointer(avimuxin
->samples_head
, (BYTE
**)&head_prev
);
261 hr
= IMediaSample_GetPointer(*head_prev
, (BYTE
**)&prev
);
267 size
= IMediaSample_GetActualDataLength(sample
);
268 hr
= IMediaSample_GetPointer(sample
, &data
);
271 flags
= IMediaSample_IsDiscontinuity(sample
)==S_OK
? AM_SAMPLE_TIMEDISCONTINUITY
: 0;
272 if(IMediaSample_IsSyncPoint(sample
) == S_OK
)
273 flags
|= AM_SAMPLE_SPLICEPOINT
;
275 if (avimuxin
->stream_time
+ (closing
? 0 : avimuxin
->strh
.dwScale
) > avimux
->cur_time
276 && !(flags
& AM_SAMPLE_TIMEDISCONTINUITY
))
281 avimux
->cur_stream
++;
282 if(avimux
->cur_stream
>= avimux
->input_pin_no
-1) {
283 avimux
->cur_time
+= avimux
->interleave
;
284 avimux
->cur_stream
= 0;
286 avimuxin
= avimux
->in
[avimux
->cur_stream
];
290 if(avimuxin
->ix
->nEntriesInUse
== AVISTDINDEX_ENTRIES
) {
291 /* TODO: use output pins Deliver/Receive method */
292 hr
= out_seek(avimux
, avimuxin
->ix_off
);
295 hr
= out_write(avimux
, avimuxin
->ix
, sizeof(avimuxin
->ix_data
));
299 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].qwOffset
= avimuxin
->ix_off
;
300 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].dwSize
= sizeof(avimuxin
->ix_data
);
301 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].dwDuration
= AVISTDINDEX_ENTRIES
;
302 avimuxin
->indx
->nEntriesInUse
++;
304 memset(avimuxin
->ix
->aIndex
, 0, sizeof(avimuxin
->ix
->aIndex
)*avimuxin
->ix
->nEntriesInUse
);
305 avimuxin
->ix
->nEntriesInUse
= 0;
306 avimuxin
->ix
->qwBaseOffset
= 0;
308 avimuxin
->ix_off
= avimux
->size
;
309 avimux
->size
+= sizeof(avimuxin
->ix_data
);
312 if(*head_prev
== avimuxin
->samples_head
)
313 avimuxin
->samples_head
= NULL
;
317 avimuxin
->stream_time
+= avimuxin
->strh
.dwScale
;
318 avimuxin
->strh
.dwLength
++;
319 if(!(flags
& AM_SAMPLE_TIMEDISCONTINUITY
)) {
320 if(!avimuxin
->ix
->qwBaseOffset
)
321 avimuxin
->ix
->qwBaseOffset
= avimux
->size
;
322 avimuxin
->ix
->aIndex
[avimuxin
->ix
->nEntriesInUse
].dwOffset
=
323 avimux
->size
+ sizeof(RIFFCHUNK
) - avimuxin
->ix
->qwBaseOffset
;
325 hr
= out_seek(avimux
, avimux
->size
);
327 IMediaSample_Release(sample
);
331 avimuxin
->ix
->aIndex
[avimuxin
->ix
->nEntriesInUse
].dwSize
= size
|
332 (flags
& AM_SAMPLE_SPLICEPOINT
? 0 : AVISTDINDEX_DELTAFRAME
);
333 avimuxin
->ix
->nEntriesInUse
++;
335 rf
.fcc
= FCC('0'+avimuxin
->stream_id
/10, '0'+avimuxin
->stream_id
%10,
336 'd', flags
& AM_SAMPLE_SPLICEPOINT
? 'b' : 'c');
338 hr
= idx1_add_entry(avimux
, rf
.fcc
, flags
& AM_SAMPLE_SPLICEPOINT
? AVIIF_KEYFRAME
: 0,
339 flags
& AM_SAMPLE_TIMEDISCONTINUITY
?
340 avimux
->idx1
[avimux
->idx1_entries
-1].dwChunkOffset
: avimux
->size
, size
);
342 IMediaSample_Release(sample
);
346 if(!(flags
& AM_SAMPLE_TIMEDISCONTINUITY
)) {
347 hr
= out_write(avimux
, &rf
, sizeof(rf
));
349 IMediaSample_Release(sample
);
352 hr
= out_write(avimux
, data
, size
);
354 IMediaSample_Release(sample
);
358 hr
= out_write(avimux
, &flags
, ALIGN(rf
.cb
)-rf
.cb
);
360 IMediaSample_Release(sample
);
364 IMediaSample_Release(sample
);
369 static HRESULT
queue_sample(AviMux
*avimux
, AviMuxIn
*avimuxin
, IMediaSample
*sample
)
371 IMediaSample
**prev
, **head_prev
;
374 hr
= IMediaSample_GetPointer(sample
, (BYTE
**)&prev
);
379 if(avimuxin
->samples_head
) {
380 hr
= IMediaSample_GetPointer(avimuxin
->samples_head
, (BYTE
**)&head_prev
);
390 avimuxin
->samples_head
= sample
;
391 IMediaSample_AddRef(sample
);
393 return flush_queue(avimux
, avimuxin
, FALSE
);
396 static HRESULT
avi_mux_cleanup_stream(struct strmbase_filter
*iface
)
398 AviMux
*This
= impl_from_strmbase_filter(iface
);
407 int idx1_off
, empty_stream
;
409 empty_stream
= This
->cur_stream
;
410 for(i
=empty_stream
+1; ; i
++) {
411 if(i
>= This
->input_pin_no
-1)
413 if(i
== empty_stream
)
416 This
->cur_stream
= i
;
417 hr
= flush_queue(This
, This
->in
[This
->cur_stream
], TRUE
);
422 idx1_off
= This
->size
;
423 rc
.fcc
= ckidAVIOLDINDEX
;
424 rc
.cb
= This
->idx1_entries
* sizeof(*This
->idx1
);
425 hr
= out_write(This
, &rc
, sizeof(rc
));
428 hr
= out_write(This
, This
->idx1
, This
->idx1_entries
* sizeof(*This
->idx1
));
431 /* native writes 8 '\0' characters after the end of RIFF data */
433 hr
= out_write(This
, &i
, sizeof(i
));
436 hr
= out_write(This
, &i
, sizeof(i
));
440 for(i
=0; i
<This
->input_pin_no
; i
++) {
441 if(!This
->in
[i
]->pin
.pin
.peer
)
444 hr
= out_seek(This
, This
->in
[i
]->ix_off
);
448 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].qwOffset
= This
->in
[i
]->ix_off
;
449 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwSize
= sizeof(This
->in
[i
]->ix_data
);
450 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwDuration
= This
->in
[i
]->strh
.dwLength
;
451 if(This
->in
[i
]->indx
->nEntriesInUse
) {
452 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwDuration
-=
453 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
-1].dwDuration
;
455 This
->in
[i
]->indx
->nEntriesInUse
++;
456 hr
= out_write(This
, This
->in
[i
]->ix
, sizeof(This
->in
[i
]->ix_data
));
461 hr
= out_seek(This
, 0);
465 rl
.fcc
= FCC('R','I','F','F');
466 rl
.cb
= This
->size
- sizeof(RIFFCHUNK
) - 2 * sizeof(int);
467 rl
.fccListType
= FCC('A','V','I',' ');
468 hr
= out_write(This
, &rl
, sizeof(rl
));
472 rl
.fcc
= FCC('L','I','S','T');
473 rl
.cb
= This
->movi_off
- sizeof(RIFFLIST
) - sizeof(RIFFCHUNK
);
474 rl
.fccListType
= FCC('h','d','r','l');
475 hr
= out_write(This
, &rl
, sizeof(rl
));
479 /* FIXME: set This->avih.dwMaxBytesPerSec value */
480 This
->avih
.dwTotalFrames
= (This
->stop
-This
->start
) / 10 / This
->avih
.dwMicroSecPerFrame
;
481 hr
= out_write(This
, &This
->avih
, sizeof(This
->avih
));
485 for(i
=0; i
<This
->input_pin_no
; i
++) {
486 if(!This
->in
[i
]->pin
.pin
.peer
)
489 rl
.cb
= sizeof(FOURCC
) + sizeof(AVISTREAMHEADER
) + sizeof(RIFFCHUNK
) +
490 This
->in
[i
]->strf
->cb
+ sizeof(This
->in
[i
]->indx_data
);
491 rl
.fccListType
= ckidSTREAMLIST
;
492 hr
= out_write(This
, &rl
, sizeof(rl
));
496 hr
= out_write(This
, &This
->in
[i
]->strh
, sizeof(AVISTREAMHEADER
));
500 hr
= out_write(This
, This
->in
[i
]->strf
, sizeof(RIFFCHUNK
) + This
->in
[i
]->strf
->cb
);
504 hr
= out_write(This
, This
->in
[i
]->indx
, sizeof(This
->in
[i
]->indx_data
));
509 rl
.cb
= sizeof(dmlh
) + sizeof(FOURCC
);
510 rl
.fccListType
= ckidODML
;
511 hr
= out_write(This
, &rl
, sizeof(rl
));
515 memset(&dmlh
, 0, sizeof(dmlh
));
516 dmlh
.fcc
= ckidAVIEXTHEADER
;
517 dmlh
.cb
= sizeof(dmlh
) - sizeof(RIFFCHUNK
);
518 dmlh
.dwGrandFrames
= This
->in
[0]->strh
.dwLength
;
519 hr
= out_write(This
, &dmlh
, sizeof(dmlh
));
521 rl
.cb
= idx1_off
- This
->movi_off
- sizeof(RIFFCHUNK
);
522 rl
.fccListType
= FCC('m','o','v','i');
523 out_write(This
, &rl
, sizeof(rl
));
526 IStream_Release(This
->stream
);
533 static HRESULT
avi_mux_init_stream(struct strmbase_filter
*iface
)
535 AviMux
*This
= impl_from_strmbase_filter(iface
);
539 if(This
->mode
!= INTERLEAVE_FULL
) {
540 FIXME("mode not supported (%d)\n", This
->mode
);
544 for(i
=0; i
<This
->input_pin_no
; i
++) {
548 if(!This
->in
[i
]->pin
.pin
.peer
)
551 hr
= IPin_QueryInterface(This
->in
[i
]->pin
.pin
.peer
,
552 &IID_IMediaSeeking
, (void**)&ms
);
556 hr
= IMediaSeeking_GetPositions(ms
, &cur
, &stop
);
558 IMediaSeeking_Release(ms
);
562 FIXME("Use IMediaSeeking to fill stream header\n");
563 IMediaSeeking_Release(ms
);
566 if (This
->source
.pMemInputPin
)
568 hr
= IMemInputPin_QueryInterface(This
->source
.pMemInputPin
,
569 &IID_IStream
, (void **)&This
->stream
);
574 This
->idx1_entries
= 0;
575 if(!This
->idx1_size
) {
576 This
->idx1_size
= 1024;
577 if (!(This
->idx1
= malloc(sizeof(*This
->idx1
) * This
->idx1_size
)))
578 return E_OUTOFMEMORY
;
581 This
->size
= 3*sizeof(RIFFLIST
) + sizeof(AVIMAINHEADER
) + sizeof(AVIEXTHEADER
);
584 memset(&This
->avih
, 0, sizeof(This
->avih
));
585 for(i
=0; i
<This
->input_pin_no
; i
++) {
586 if(!This
->in
[i
]->pin
.pin
.peer
)
589 This
->avih
.dwStreams
++;
590 This
->size
+= sizeof(RIFFLIST
) + sizeof(AVISTREAMHEADER
) + sizeof(RIFFCHUNK
)
591 + This
->in
[i
]->strf
->cb
+ sizeof(This
->in
[i
]->indx_data
);
593 This
->in
[i
]->strh
.dwScale
= MulDiv(This
->in
[i
]->avg_time_per_frame
, This
->interleave
, 10000000);
594 This
->in
[i
]->strh
.dwRate
= This
->interleave
;
596 hr
= IMemAllocator_Commit(This
->in
[i
]->pin
.pAllocator
);
600 IStream_Release(This
->stream
);
607 This
->movi_off
= This
->size
;
608 This
->size
+= sizeof(RIFFLIST
);
610 idx1_add_entry(This
, FCC('7','F','x','x'), 0, This
->movi_off
+ sizeof(RIFFLIST
), 0);
613 for(i
=0; i
<This
->input_pin_no
; i
++) {
614 if(!This
->in
[i
]->pin
.pin
.peer
)
617 This
->in
[i
]->ix_off
= This
->size
;
618 This
->size
+= sizeof(This
->in
[i
]->ix_data
);
619 This
->in
[i
]->ix
->fcc
= FCC('i','x','0'+stream_id
/10,'0'+stream_id
%10);
620 This
->in
[i
]->ix
->cb
= sizeof(This
->in
[i
]->ix_data
) - sizeof(RIFFCHUNK
);
621 This
->in
[i
]->ix
->wLongsPerEntry
= 2;
622 This
->in
[i
]->ix
->bIndexSubType
= 0;
623 This
->in
[i
]->ix
->bIndexType
= AVI_INDEX_OF_CHUNKS
;
624 This
->in
[i
]->ix
->dwChunkId
= FCC('0'+stream_id
/10,'0'+stream_id
%10,'d','b');
625 This
->in
[i
]->ix
->qwBaseOffset
= 0;
627 This
->in
[i
]->indx
->fcc
= ckidAVISUPERINDEX
;
628 This
->in
[i
]->indx
->cb
= sizeof(This
->in
[i
]->indx_data
) - sizeof(RIFFCHUNK
);
629 This
->in
[i
]->indx
->wLongsPerEntry
= 4;
630 This
->in
[i
]->indx
->bIndexSubType
= 0;
631 This
->in
[i
]->indx
->bIndexType
= AVI_INDEX_OF_INDEXES
;
632 This
->in
[i
]->indx
->dwChunkId
= This
->in
[i
]->ix
->dwChunkId
;
633 This
->in
[i
]->stream_id
= stream_id
++;
639 This
->avih
.fcc
= ckidMAINAVIHEADER
;
640 This
->avih
.cb
= sizeof(AVIMAINHEADER
) - sizeof(RIFFCHUNK
);
641 /* TODO: Use first video stream */
642 This
->avih
.dwMicroSecPerFrame
= This
->in
[0]->avg_time_per_frame
/10;
643 This
->avih
.dwPaddingGranularity
= 1;
644 This
->avih
.dwFlags
= AVIF_TRUSTCKTYPE
| AVIF_HASINDEX
;
645 This
->avih
.dwWidth
= ((BITMAPINFOHEADER
*)This
->in
[0]->strf
->data
)->biWidth
;
646 This
->avih
.dwHeight
= ((BITMAPINFOHEADER
*)This
->in
[0]->strf
->data
)->biHeight
;
651 static const struct strmbase_filter_ops filter_ops
=
653 .filter_get_pin
= avi_mux_get_pin
,
654 .filter_destroy
= avi_mux_destroy
,
655 .filter_query_interface
= avi_mux_query_interface
,
656 .filter_init_stream
= avi_mux_init_stream
,
657 .filter_cleanup_stream
= avi_mux_cleanup_stream
,
660 static inline AviMux
* impl_from_IConfigAviMux(IConfigAviMux
*iface
)
662 return CONTAINING_RECORD(iface
, AviMux
, IConfigAviMux_iface
);
665 static HRESULT WINAPI
ConfigAviMux_QueryInterface(
666 IConfigAviMux
*iface
, REFIID riid
, void **ppv
)
668 AviMux
*This
= impl_from_IConfigAviMux(iface
);
669 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
672 static ULONG WINAPI
ConfigAviMux_AddRef(IConfigAviMux
*iface
)
674 AviMux
*This
= impl_from_IConfigAviMux(iface
);
675 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
678 static ULONG WINAPI
ConfigAviMux_Release(IConfigAviMux
*iface
)
680 AviMux
*This
= impl_from_IConfigAviMux(iface
);
681 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
684 static HRESULT WINAPI
ConfigAviMux_SetMasterStream(IConfigAviMux
*iface
, LONG iStream
)
686 AviMux
*This
= impl_from_IConfigAviMux(iface
);
687 FIXME("filter %p, index %ld, stub!\n", This
, iStream
);
691 static HRESULT WINAPI
ConfigAviMux_GetMasterStream(IConfigAviMux
*iface
, LONG
*pStream
)
693 AviMux
*This
= impl_from_IConfigAviMux(iface
);
694 FIXME("(%p)->(%p)\n", This
, pStream
);
698 static HRESULT WINAPI
ConfigAviMux_SetOutputCompatibilityIndex(
699 IConfigAviMux
*iface
, BOOL fOldIndex
)
701 AviMux
*This
= impl_from_IConfigAviMux(iface
);
702 FIXME("(%p)->(%x)\n", This
, fOldIndex
);
706 static HRESULT WINAPI
ConfigAviMux_GetOutputCompatibilityIndex(
707 IConfigAviMux
*iface
, BOOL
*pfOldIndex
)
709 AviMux
*This
= impl_from_IConfigAviMux(iface
);
710 FIXME("(%p)->(%p)\n", This
, pfOldIndex
);
714 static const IConfigAviMuxVtbl ConfigAviMuxVtbl
= {
715 ConfigAviMux_QueryInterface
,
717 ConfigAviMux_Release
,
718 ConfigAviMux_SetMasterStream
,
719 ConfigAviMux_GetMasterStream
,
720 ConfigAviMux_SetOutputCompatibilityIndex
,
721 ConfigAviMux_GetOutputCompatibilityIndex
724 static inline AviMux
* impl_from_IConfigInterleaving(IConfigInterleaving
*iface
)
726 return CONTAINING_RECORD(iface
, AviMux
, IConfigInterleaving_iface
);
729 static HRESULT WINAPI
ConfigInterleaving_QueryInterface(
730 IConfigInterleaving
*iface
, REFIID riid
, void **ppv
)
732 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
733 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
736 static ULONG WINAPI
ConfigInterleaving_AddRef(IConfigInterleaving
*iface
)
738 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
739 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
742 static ULONG WINAPI
ConfigInterleaving_Release(IConfigInterleaving
*iface
)
744 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
745 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
748 static HRESULT WINAPI
ConfigInterleaving_put_Mode(
749 IConfigInterleaving
*iface
, InterleavingMode mode
)
751 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
753 TRACE("(%p)->(%d)\n", This
, mode
);
755 if(mode
>INTERLEAVE_NONE_BUFFERED
)
758 if(This
->mode
!= mode
) {
759 if(This
->source
.pin
.peer
) {
760 HRESULT hr
= IFilterGraph_Reconnect(This
->filter
.graph
, &This
->source
.pin
.IPin_iface
);
771 static HRESULT WINAPI
ConfigInterleaving_get_Mode(
772 IConfigInterleaving
*iface
, InterleavingMode
*pMode
)
774 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
775 FIXME("(%p)->(%p)\n", This
, pMode
);
779 static HRESULT WINAPI
ConfigInterleaving_put_Interleaving(IConfigInterleaving
*iface
,
780 const REFERENCE_TIME
*prtInterleave
, const REFERENCE_TIME
*prtPreroll
)
782 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
784 TRACE("(%p)->(%p %p)\n", This
, prtInterleave
, prtPreroll
);
787 This
->interleave
= *prtInterleave
;
789 This
->preroll
= *prtPreroll
;
793 static HRESULT WINAPI
ConfigInterleaving_get_Interleaving(IConfigInterleaving
*iface
,
794 REFERENCE_TIME
*prtInterleave
, REFERENCE_TIME
*prtPreroll
)
796 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
797 FIXME("(%p)->(%p %p)\n", This
, prtInterleave
, prtPreroll
);
801 static const IConfigInterleavingVtbl ConfigInterleavingVtbl
= {
802 ConfigInterleaving_QueryInterface
,
803 ConfigInterleaving_AddRef
,
804 ConfigInterleaving_Release
,
805 ConfigInterleaving_put_Mode
,
806 ConfigInterleaving_get_Mode
,
807 ConfigInterleaving_put_Interleaving
,
808 ConfigInterleaving_get_Interleaving
811 static inline AviMux
* impl_from_IMediaSeeking(IMediaSeeking
*iface
)
813 return CONTAINING_RECORD(iface
, AviMux
, IMediaSeeking_iface
);
816 static HRESULT WINAPI
MediaSeeking_QueryInterface(
817 IMediaSeeking
*iface
, REFIID riid
, void **ppv
)
819 AviMux
*This
= impl_from_IMediaSeeking(iface
);
820 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
823 static ULONG WINAPI
MediaSeeking_AddRef(IMediaSeeking
*iface
)
825 AviMux
*This
= impl_from_IMediaSeeking(iface
);
826 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
829 static ULONG WINAPI
MediaSeeking_Release(IMediaSeeking
*iface
)
831 AviMux
*This
= impl_from_IMediaSeeking(iface
);
832 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
835 static HRESULT WINAPI
MediaSeeking_GetCapabilities(
836 IMediaSeeking
*iface
, DWORD
*pCapabilities
)
838 AviMux
*This
= impl_from_IMediaSeeking(iface
);
839 FIXME("(%p)->(%p)\n", This
, pCapabilities
);
843 static HRESULT WINAPI
MediaSeeking_CheckCapabilities(
844 IMediaSeeking
*iface
, DWORD
*pCapabilities
)
846 AviMux
*This
= impl_from_IMediaSeeking(iface
);
847 FIXME("(%p)->(%p)\n", This
, pCapabilities
);
851 static HRESULT WINAPI
MediaSeeking_IsFormatSupported(
852 IMediaSeeking
*iface
, const GUID
*pFormat
)
854 AviMux
*This
= impl_from_IMediaSeeking(iface
);
855 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
859 static HRESULT WINAPI
MediaSeeking_QueryPreferredFormat(
860 IMediaSeeking
*iface
, GUID
*pFormat
)
862 AviMux
*This
= impl_from_IMediaSeeking(iface
);
863 FIXME("(%p)->(%p)\n", This
, pFormat
);
867 static HRESULT WINAPI
MediaSeeking_GetTimeFormat(
868 IMediaSeeking
*iface
, GUID
*pFormat
)
870 AviMux
*This
= impl_from_IMediaSeeking(iface
);
871 FIXME("(%p)->(%p)\n", This
, pFormat
);
875 static HRESULT WINAPI
MediaSeeking_IsUsingTimeFormat(
876 IMediaSeeking
*iface
, const GUID
*pFormat
)
878 AviMux
*This
= impl_from_IMediaSeeking(iface
);
879 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
883 static HRESULT WINAPI
MediaSeeking_SetTimeFormat(
884 IMediaSeeking
*iface
, const GUID
*pFormat
)
886 AviMux
*This
= impl_from_IMediaSeeking(iface
);
887 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
891 static HRESULT WINAPI
MediaSeeking_GetDuration(
892 IMediaSeeking
*iface
, LONGLONG
*pDuration
)
894 AviMux
*This
= impl_from_IMediaSeeking(iface
);
895 FIXME("(%p)->(%p)\n", This
, pDuration
);
899 static HRESULT WINAPI
MediaSeeking_GetStopPosition(
900 IMediaSeeking
*iface
, LONGLONG
*pStop
)
902 AviMux
*This
= impl_from_IMediaSeeking(iface
);
903 FIXME("(%p)->(%p)\n", This
, pStop
);
907 static HRESULT WINAPI
MediaSeeking_GetCurrentPosition(
908 IMediaSeeking
*iface
, LONGLONG
*pCurrent
)
910 AviMux
*This
= impl_from_IMediaSeeking(iface
);
911 FIXME("(%p)->(%p)\n", This
, pCurrent
);
915 static HRESULT WINAPI
MediaSeeking_ConvertTimeFormat(IMediaSeeking
*iface
, LONGLONG
*pTarget
,
916 const GUID
*pTargetFormat
, LONGLONG Source
, const GUID
*pSourceFormat
)
918 AviMux
*This
= impl_from_IMediaSeeking(iface
);
919 FIXME("(%p)->(%p %s %s %s)\n", This
, pTarget
, debugstr_guid(pTargetFormat
),
920 wine_dbgstr_longlong(Source
), debugstr_guid(pSourceFormat
));
924 static HRESULT WINAPI
MediaSeeking_SetPositions(IMediaSeeking
*iface
, LONGLONG
*pCurrent
,
925 DWORD dwCurrentFlags
, LONGLONG
*pStop
, DWORD dwStopFlags
)
927 AviMux
*This
= impl_from_IMediaSeeking(iface
);
928 FIXME("(%p)->(%p %#lx %p %#lx)\n", This
, pCurrent
, dwCurrentFlags
, pStop
, dwStopFlags
);
932 static HRESULT WINAPI
MediaSeeking_GetPositions(IMediaSeeking
*iface
,
933 LONGLONG
*pCurrent
, LONGLONG
*pStop
)
935 AviMux
*This
= impl_from_IMediaSeeking(iface
);
936 FIXME("(%p)->(%p %p)\n", This
, pCurrent
, pStop
);
940 static HRESULT WINAPI
MediaSeeking_GetAvailable(IMediaSeeking
*iface
,
941 LONGLONG
*pEarliest
, LONGLONG
*pLatest
)
943 AviMux
*This
= impl_from_IMediaSeeking(iface
);
944 FIXME("(%p)->(%p %p)\n", This
, pEarliest
, pLatest
);
948 static HRESULT WINAPI
MediaSeeking_SetRate(IMediaSeeking
*iface
, double dRate
)
950 AviMux
*This
= impl_from_IMediaSeeking(iface
);
951 FIXME("(%p)->(%lf)\n", This
, dRate
);
955 static HRESULT WINAPI
MediaSeeking_GetRate(IMediaSeeking
*iface
, double *pdRate
)
957 AviMux
*This
= impl_from_IMediaSeeking(iface
);
958 FIXME("(%p)->(%p)\n", This
, pdRate
);
962 static HRESULT WINAPI
MediaSeeking_GetPreroll(IMediaSeeking
*iface
, LONGLONG
*pllPreroll
)
964 AviMux
*This
= impl_from_IMediaSeeking(iface
);
965 FIXME("(%p)->(%p)\n", This
, pllPreroll
);
969 static const IMediaSeekingVtbl MediaSeekingVtbl
= {
970 MediaSeeking_QueryInterface
,
972 MediaSeeking_Release
,
973 MediaSeeking_GetCapabilities
,
974 MediaSeeking_CheckCapabilities
,
975 MediaSeeking_IsFormatSupported
,
976 MediaSeeking_QueryPreferredFormat
,
977 MediaSeeking_GetTimeFormat
,
978 MediaSeeking_IsUsingTimeFormat
,
979 MediaSeeking_SetTimeFormat
,
980 MediaSeeking_GetDuration
,
981 MediaSeeking_GetStopPosition
,
982 MediaSeeking_GetCurrentPosition
,
983 MediaSeeking_ConvertTimeFormat
,
984 MediaSeeking_SetPositions
,
985 MediaSeeking_GetPositions
,
986 MediaSeeking_GetAvailable
,
987 MediaSeeking_SetRate
,
988 MediaSeeking_GetRate
,
989 MediaSeeking_GetPreroll
992 static inline AviMux
* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag
*iface
)
994 return CONTAINING_RECORD(iface
, AviMux
, IPersistMediaPropertyBag_iface
);
997 static HRESULT WINAPI
PersistMediaPropertyBag_QueryInterface(
998 IPersistMediaPropertyBag
*iface
, REFIID riid
, void **ppv
)
1000 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1001 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1004 static ULONG WINAPI
PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag
*iface
)
1006 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1007 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1010 static ULONG WINAPI
PersistMediaPropertyBag_Release(IPersistMediaPropertyBag
*iface
)
1012 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1013 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1016 static HRESULT WINAPI
PersistMediaPropertyBag_GetClassID(
1017 IPersistMediaPropertyBag
*iface
, CLSID
*pClassID
)
1019 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1020 return IBaseFilter_GetClassID(&This
->filter
.IBaseFilter_iface
, pClassID
);
1023 static HRESULT WINAPI
PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag
*iface
)
1025 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1026 FIXME("(%p)->()\n", This
);
1030 static HRESULT WINAPI
PersistMediaPropertyBag_Load(IPersistMediaPropertyBag
*iface
,
1031 IMediaPropertyBag
*pPropBag
, IErrorLog
*pErrorLog
)
1033 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1034 FIXME("(%p)->()\n", This
);
1038 static HRESULT WINAPI
PersistMediaPropertyBag_Save(IPersistMediaPropertyBag
*iface
,
1039 IMediaPropertyBag
*pPropBag
, BOOL fClearDirty
, BOOL fSaveAllProperties
)
1041 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1042 FIXME("(%p)->()\n", This
);
1046 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl
= {
1047 PersistMediaPropertyBag_QueryInterface
,
1048 PersistMediaPropertyBag_AddRef
,
1049 PersistMediaPropertyBag_Release
,
1050 PersistMediaPropertyBag_GetClassID
,
1051 PersistMediaPropertyBag_InitNew
,
1052 PersistMediaPropertyBag_Load
,
1053 PersistMediaPropertyBag_Save
1056 static inline AviMux
* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages
*iface
)
1058 return CONTAINING_RECORD(iface
, AviMux
, ISpecifyPropertyPages_iface
);
1061 static HRESULT WINAPI
SpecifyPropertyPages_QueryInterface(
1062 ISpecifyPropertyPages
*iface
, REFIID riid
, void **ppv
)
1064 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1065 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1068 static ULONG WINAPI
SpecifyPropertyPages_AddRef(ISpecifyPropertyPages
*iface
)
1070 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1071 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1074 static ULONG WINAPI
SpecifyPropertyPages_Release(ISpecifyPropertyPages
*iface
)
1076 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1077 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1080 static HRESULT WINAPI
SpecifyPropertyPages_GetPages(
1081 ISpecifyPropertyPages
*iface
, CAUUID
*pPages
)
1083 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1084 FIXME("(%p)->(%p)\n", This
, pPages
);
1088 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl
= {
1089 SpecifyPropertyPages_QueryInterface
,
1090 SpecifyPropertyPages_AddRef
,
1091 SpecifyPropertyPages_Release
,
1092 SpecifyPropertyPages_GetPages
1095 static inline AviMux
*impl_from_source_pin(struct strmbase_pin
*iface
)
1097 return CONTAINING_RECORD(iface
, AviMux
, source
.pin
);
1100 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
1102 AviMux
*filter
= impl_from_source_pin(iface
);
1104 if (IsEqualGUID(iid
, &IID_IQualityControl
))
1105 *out
= &filter
->IQualityControl_iface
;
1107 return E_NOINTERFACE
;
1109 IUnknown_AddRef((IUnknown
*)*out
);
1113 static HRESULT
source_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
1115 if (!IsEqualGUID(&mt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Stream
))
1117 if (!IsEqualGUID(&mt
->subtype
, &GUID_NULL
) && !IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_Avi
))
1122 static HRESULT WINAPI
AviMuxOut_AttemptConnection(struct strmbase_source
*iface
,
1123 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1125 AviMux
*filter
= impl_from_source_pin(&iface
->pin
);
1130 hr
= IPin_QueryDirection(pReceivePin
, &dir
);
1131 if(hr
==S_OK
&& dir
!=PINDIR_INPUT
)
1132 return VFW_E_INVALID_DIRECTION
;
1134 if (FAILED(hr
= BaseOutputPinImpl_AttemptConnection(iface
, pReceivePin
, pmt
)))
1137 for (i
= 0; i
< filter
->input_pin_no
; ++i
)
1139 if (!filter
->in
[i
]->pin
.pin
.peer
)
1142 hr
= IFilterGraph_Reconnect(filter
->filter
.graph
, &filter
->in
[i
]->pin
.pin
.IPin_iface
);
1145 IPin_Disconnect(&iface
->pin
.IPin_iface
);
1153 static HRESULT
source_get_media_type(struct strmbase_pin
*base
, unsigned int iPosition
, AM_MEDIA_TYPE
*amt
)
1155 TRACE("(%p)->(%d %p)\n", base
, iPosition
, amt
);
1158 return VFW_S_NO_MORE_ITEMS
;
1160 amt
->majortype
= MEDIATYPE_Stream
;
1161 amt
->subtype
= MEDIASUBTYPE_Avi
;
1162 amt
->bFixedSizeSamples
= TRUE
;
1163 amt
->bTemporalCompression
= FALSE
;
1164 amt
->lSampleSize
= 1;
1165 amt
->formattype
= GUID_NULL
;
1168 amt
->pbFormat
= NULL
;
1172 static HRESULT WINAPI
AviMuxOut_DecideAllocator(struct strmbase_source
*base
,
1173 IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
1175 ALLOCATOR_PROPERTIES req
, actual
;
1178 TRACE("(%p)->(%p %p)\n", base
, pPin
, pAlloc
);
1180 if (FAILED(hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
,
1181 CLSCTX_INPROC_SERVER
, &IID_IMemAllocator
, (void **)pAlloc
)))
1183 ERR("Failed to create allocator, hr %#lx.\n", hr
);
1187 hr
= IMemInputPin_GetAllocatorRequirements(pPin
, &req
);
1194 hr
= IMemAllocator_SetProperties(*pAlloc
, &req
, &actual
);
1198 return IMemInputPin_NotifyAllocator(pPin
, *pAlloc
, TRUE
);
1201 static const struct strmbase_source_ops source_ops
=
1203 .base
.pin_query_interface
= source_query_interface
,
1204 .base
.pin_query_accept
= source_query_accept
,
1205 .base
.pin_get_media_type
= source_get_media_type
,
1206 .pfnAttemptConnection
= AviMuxOut_AttemptConnection
,
1207 .pfnDecideAllocator
= AviMuxOut_DecideAllocator
,
1210 static inline AviMux
* impl_from_out_IQualityControl(IQualityControl
*iface
)
1212 return CONTAINING_RECORD(iface
, AviMux
, IQualityControl_iface
);
1215 static HRESULT WINAPI
AviMuxOut_QualityControl_QueryInterface(
1216 IQualityControl
*iface
, REFIID riid
, void **ppv
)
1218 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1219 return IPin_QueryInterface(&This
->source
.pin
.IPin_iface
, riid
, ppv
);
1222 static ULONG WINAPI
AviMuxOut_QualityControl_AddRef(IQualityControl
*iface
)
1224 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1225 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1228 static ULONG WINAPI
AviMuxOut_QualityControl_Release(IQualityControl
*iface
)
1230 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1231 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1234 static HRESULT WINAPI
AviMuxOut_QualityControl_Notify(IQualityControl
*iface
,
1235 IBaseFilter
*sender
, Quality q
)
1237 AviMux
*filter
= impl_from_out_IQualityControl(iface
);
1239 FIXME("filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s, stub!\n",
1240 filter
, sender
, q
.Type
, q
.Proportion
,
1241 wine_dbgstr_longlong(q
.Late
), wine_dbgstr_longlong(q
.TimeStamp
));
1246 static HRESULT WINAPI
AviMuxOut_QualityControl_SetSink(
1247 IQualityControl
*iface
, IQualityControl
*piqc
)
1249 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1250 FIXME("(%p)->(%p)\n", This
, piqc
);
1254 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl
= {
1255 AviMuxOut_QualityControl_QueryInterface
,
1256 AviMuxOut_QualityControl_AddRef
,
1257 AviMuxOut_QualityControl_Release
,
1258 AviMuxOut_QualityControl_Notify
,
1259 AviMuxOut_QualityControl_SetSink
1262 static inline AviMuxIn
*impl_sink_from_strmbase_pin(struct strmbase_pin
*iface
)
1264 return CONTAINING_RECORD(iface
, AviMuxIn
, pin
.pin
);
1267 static HRESULT
sink_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
1269 AviMuxIn
*pin
= impl_sink_from_strmbase_pin(iface
);
1271 if (IsEqualGUID(iid
, &IID_IAMStreamControl
))
1272 *out
= &pin
->IAMStreamControl_iface
;
1273 else if (IsEqualGUID(iid
, &IID_IMemInputPin
))
1274 *out
= &pin
->pin
.IMemInputPin_iface
;
1275 else if (IsEqualGUID(iid
, &IID_IPropertyBag
))
1276 *out
= &pin
->IPropertyBag_iface
;
1277 else if (IsEqualGUID(iid
, &IID_IQualityControl
))
1278 *out
= &pin
->IQualityControl_iface
;
1280 return E_NOINTERFACE
;
1282 IUnknown_AddRef((IUnknown
*)*out
);
1286 static HRESULT
sink_query_accept(struct strmbase_pin
*base
, const AM_MEDIA_TYPE
*pmt
)
1288 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
) &&
1289 IsEqualIID(&pmt
->formattype
, &FORMAT_WaveFormatEx
))
1291 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Interleaved
) &&
1292 IsEqualIID(&pmt
->formattype
, &FORMAT_DvInfo
))
1294 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
) &&
1295 (IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
) ||
1296 IsEqualIID(&pmt
->formattype
, &FORMAT_DvInfo
)))
1301 static HRESULT WINAPI
AviMuxIn_Receive(struct strmbase_sink
*base
, IMediaSample
*pSample
)
1303 AviMux
*avimux
= impl_from_strmbase_filter(base
->pin
.filter
);
1304 AviMuxIn
*avimuxin
= CONTAINING_RECORD(base
, AviMuxIn
, pin
);
1305 REFERENCE_TIME start
, stop
;
1306 IMediaSample
*sample
;
1310 DWORD max_size
, size
;
1314 TRACE("pin %p, pSample %p.\n", avimuxin
, pSample
);
1316 hr
= IMediaSample_QueryInterface(pSample
, &IID_IMediaSample2
, (void**)&ms2
);
1318 AM_SAMPLE2_PROPERTIES props
;
1320 memset(&props
, 0, sizeof(props
));
1321 hr
= IMediaSample2_GetProperties(ms2
, sizeof(props
), (BYTE
*)&props
);
1322 IMediaSample2_Release(ms2
);
1326 flags
= props
.dwSampleFlags
;
1327 frame
= props
.pbBuffer
;
1328 size
= props
.lActual
;
1330 flags
= IMediaSample_IsSyncPoint(pSample
) == S_OK
? AM_SAMPLE_SPLICEPOINT
: 0;
1331 hr
= IMediaSample_GetPointer(pSample
, &frame
);
1334 size
= IMediaSample_GetActualDataLength(pSample
);
1337 if(!avimuxin
->pin
.pin
.mt
.bTemporalCompression
)
1338 flags
|= AM_SAMPLE_SPLICEPOINT
;
1340 hr
= IMediaSample_GetTime(pSample
, &start
, &stop
);
1344 if(avimuxin
->stop
>stop
)
1345 return VFW_E_START_TIME_AFTER_END
;
1347 if(avimux
->start
== -1)
1348 avimux
->start
= start
;
1349 if(avimux
->stop
< stop
)
1350 avimux
->stop
= stop
;
1352 if(avimux
->avih
.dwSuggestedBufferSize
< ALIGN(size
)+sizeof(RIFFCHUNK
))
1353 avimux
->avih
.dwSuggestedBufferSize
= ALIGN(size
) + sizeof(RIFFCHUNK
);
1354 if(avimuxin
->strh
.dwSuggestedBufferSize
< ALIGN(size
)+sizeof(RIFFCHUNK
))
1355 avimuxin
->strh
.dwSuggestedBufferSize
= ALIGN(size
) + sizeof(RIFFCHUNK
);
1358 if(avimuxin
->stop
!=-1 && start
> avimuxin
->stop
) {
1359 frames_no
+= (double)(start
- avimuxin
->stop
) / 10000000
1360 * avimuxin
->strh
.dwRate
/ avimuxin
->strh
.dwScale
+ 0.5;
1362 avimuxin
->stop
= stop
;
1364 while(--frames_no
) {
1365 /* TODO: store all control frames in one buffer */
1366 hr
= IMemAllocator_GetBuffer(avimuxin
->samples_allocator
, &sample
, NULL
, NULL
, 0);
1369 hr
= IMediaSample_SetActualDataLength(sample
, 0);
1371 hr
= IMediaSample_SetDiscontinuity(sample
, TRUE
);
1373 hr
= IMediaSample_SetSyncPoint(sample
, FALSE
);
1375 hr
= queue_sample(avimux
, avimuxin
, sample
);
1376 IMediaSample_Release(sample
);
1381 hr
= IMemAllocator_GetBuffer(avimuxin
->samples_allocator
, &sample
, NULL
, NULL
, 0);
1384 max_size
= IMediaSample_GetSize(sample
);
1387 hr
= IMediaSample_SetActualDataLength(sample
, size
);
1389 hr
= IMediaSample_SetDiscontinuity(sample
, FALSE
);
1391 hr
= IMediaSample_SetSyncPoint(sample
, flags
& AM_SAMPLE_SPLICEPOINT
);
1392 /* TODO: avoid unnecessary copying */
1394 hr
= IMediaSample_GetPointer(sample
, &buf
);
1396 memcpy(buf
, frame
, size
);
1397 hr
= queue_sample(avimux
, avimuxin
, sample
);
1399 IMediaSample_Release(sample
);
1404 static HRESULT
avi_mux_sink_connect(struct strmbase_sink
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*pmt
)
1406 AviMuxIn
*avimuxin
= impl_sink_from_strmbase_pin(&iface
->pin
);
1407 AviMux
*This
= impl_from_strmbase_filter(iface
->pin
.filter
);
1413 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
) &&
1414 IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
)) {
1415 ALLOCATOR_PROPERTIES req
, act
;
1416 VIDEOINFOHEADER
*vih
;
1419 vih
= (VIDEOINFOHEADER
*)pmt
->pbFormat
;
1420 avimuxin
->strh
.fcc
= ckidSTREAMHEADER
;
1421 avimuxin
->strh
.cb
= sizeof(AVISTREAMHEADER
) - FIELD_OFFSET(AVISTREAMHEADER
, fccType
);
1422 avimuxin
->strh
.fccType
= streamtypeVIDEO
;
1423 /* FIXME: fccHandler should be set differently */
1424 avimuxin
->strh
.fccHandler
= vih
->bmiHeader
.biCompression
?
1425 vih
->bmiHeader
.biCompression
: FCC('D','I','B',' ');
1426 avimuxin
->avg_time_per_frame
= vih
->AvgTimePerFrame
;
1427 avimuxin
->stop
= -1;
1430 req
.cbBuffer
= vih
->bmiHeader
.biSizeImage
;
1432 req
.cbPrefix
= sizeof(void*);
1433 hr
= IMemAllocator_SetProperties(avimuxin
->samples_allocator
, &req
, &act
);
1435 hr
= IMemAllocator_Commit(avimuxin
->samples_allocator
);
1439 size
= pmt
->cbFormat
- FIELD_OFFSET(VIDEOINFOHEADER
, bmiHeader
);
1440 avimuxin
->strf
= malloc(sizeof(RIFFCHUNK
) + ALIGN(FIELD_OFFSET(BITMAPINFO
, bmiColors
[vih
->bmiHeader
.biClrUsed
])));
1441 avimuxin
->strf
->fcc
= ckidSTREAMFORMAT
;
1442 avimuxin
->strf
->cb
= FIELD_OFFSET(BITMAPINFO
, bmiColors
[vih
->bmiHeader
.biClrUsed
]);
1443 if(size
> avimuxin
->strf
->cb
)
1444 size
= avimuxin
->strf
->cb
;
1445 memcpy(avimuxin
->strf
->data
, &vih
->bmiHeader
, size
);
1447 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt
->majortype
),
1448 debugstr_guid(&pmt
->formattype
));
1452 return create_input_pin(This
);
1455 static void avi_mux_sink_disconnect(struct strmbase_sink
*iface
)
1457 AviMuxIn
*avimuxin
= impl_sink_from_strmbase_pin(&iface
->pin
);
1458 IMediaSample
**prev
, *cur
;
1460 IMemAllocator_Decommit(avimuxin
->samples_allocator
);
1461 while(avimuxin
->samples_head
) {
1462 cur
= avimuxin
->samples_head
;
1463 if (FAILED(IMediaSample_GetPointer(cur
, (BYTE
**)&prev
)))
1467 cur
= avimuxin
->samples_head
;
1468 avimuxin
->samples_head
= *prev
;
1469 IMediaSample_Release(cur
);
1471 if(cur
== avimuxin
->samples_head
)
1472 avimuxin
->samples_head
= NULL
;
1474 free(avimuxin
->strf
);
1475 avimuxin
->strf
= NULL
;
1478 static const struct strmbase_sink_ops sink_ops
=
1480 .base
.pin_query_interface
= sink_query_interface
,
1481 .base
.pin_query_accept
= sink_query_accept
,
1482 .pfnReceive
= AviMuxIn_Receive
,
1483 .sink_connect
= avi_mux_sink_connect
,
1484 .sink_disconnect
= avi_mux_sink_disconnect
,
1487 static inline AviMux
* impl_from_in_IPin(IPin
*iface
)
1489 struct strmbase_pin
*pin
= CONTAINING_RECORD(iface
, struct strmbase_pin
, IPin_iface
);
1490 return impl_from_strmbase_filter(pin
->filter
);
1493 static inline AviMuxIn
* AviMuxIn_from_IAMStreamControl(IAMStreamControl
*iface
)
1495 return CONTAINING_RECORD(iface
, AviMuxIn
, IAMStreamControl_iface
);
1498 static HRESULT WINAPI
AviMuxIn_AMStreamControl_QueryInterface(
1499 IAMStreamControl
*iface
, REFIID riid
, void **ppv
)
1501 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1502 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1505 static ULONG WINAPI
AviMuxIn_AMStreamControl_AddRef(IAMStreamControl
*iface
)
1507 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1508 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1509 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1512 static ULONG WINAPI
AviMuxIn_AMStreamControl_Release(IAMStreamControl
*iface
)
1514 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1515 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1516 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1519 static HRESULT WINAPI
AviMuxIn_AMStreamControl_StartAt(IAMStreamControl
*iface
,
1520 const REFERENCE_TIME
*start
, DWORD cookie
)
1522 FIXME("iface %p, start %p, cookie %#lx, stub!\n", iface
, start
, cookie
);
1526 static HRESULT WINAPI
AviMuxIn_AMStreamControl_StopAt(IAMStreamControl
*iface
,
1527 const REFERENCE_TIME
*stop
, BOOL send_extra
, DWORD cookie
)
1529 FIXME("iface %p, stop %p, send_extra %d, cookie %#lx, stub!\n", iface
, stop
, send_extra
, cookie
);
1533 static HRESULT WINAPI
AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl
*iface
,
1534 AM_STREAM_INFO
*info
)
1536 FIXME("iface %p, info %p, stub!\n", iface
, info
);
1540 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl
= {
1541 AviMuxIn_AMStreamControl_QueryInterface
,
1542 AviMuxIn_AMStreamControl_AddRef
,
1543 AviMuxIn_AMStreamControl_Release
,
1544 AviMuxIn_AMStreamControl_StartAt
,
1545 AviMuxIn_AMStreamControl_StopAt
,
1546 AviMuxIn_AMStreamControl_GetInfo
1549 static inline AviMuxIn
* AviMuxIn_from_IMemInputPin(IMemInputPin
*iface
)
1551 return CONTAINING_RECORD(iface
, AviMuxIn
, pin
.IMemInputPin_iface
);
1554 static HRESULT WINAPI
AviMuxIn_MemInputPin_QueryInterface(
1555 IMemInputPin
*iface
, REFIID riid
, void **ppv
)
1557 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1558 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1561 static ULONG WINAPI
AviMuxIn_MemInputPin_AddRef(IMemInputPin
*iface
)
1563 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1564 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1565 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1568 static ULONG WINAPI
AviMuxIn_MemInputPin_Release(IMemInputPin
*iface
)
1570 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1571 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1572 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1575 static HRESULT WINAPI
AviMuxIn_MemInputPin_GetAllocator(
1576 IMemInputPin
*iface
, IMemAllocator
**ppAllocator
)
1578 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1580 TRACE("pin %p, ppAllocator %p.\n", avimuxin
, ppAllocator
);
1585 IMemAllocator_AddRef(avimuxin
->pin
.pAllocator
);
1586 *ppAllocator
= avimuxin
->pin
.pAllocator
;
1590 static HRESULT WINAPI
AviMuxIn_MemInputPin_NotifyAllocator(
1591 IMemInputPin
*iface
, IMemAllocator
*pAllocator
, BOOL bReadOnly
)
1593 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1594 ALLOCATOR_PROPERTIES props
;
1597 TRACE("pin %p, pAllocator %p, bReadOnly %d.\n", avimuxin
, pAllocator
, bReadOnly
);
1602 memset(&props
, 0, sizeof(props
));
1603 hr
= IMemAllocator_GetProperties(pAllocator
, &props
);
1609 return IMemAllocator_SetProperties(avimuxin
->pin
.pAllocator
, &props
, &props
);
1612 static HRESULT WINAPI
AviMuxIn_MemInputPin_GetAllocatorRequirements(
1613 IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*pProps
)
1615 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1617 TRACE("pin %p, pProps %p.\n", avimuxin
, pProps
);
1622 pProps
->cbAlign
= 1;
1623 pProps
->cbPrefix
= 8;
1627 static HRESULT WINAPI
AviMuxIn_MemInputPin_Receive(
1628 IMemInputPin
*iface
, IMediaSample
*pSample
)
1630 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1632 TRACE("pin %p, pSample %p.\n", avimuxin
, pSample
);
1634 return avimuxin
->pin
.pFuncsTable
->pfnReceive(&avimuxin
->pin
, pSample
);
1637 static HRESULT WINAPI
AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin
*iface
,
1638 IMediaSample
**pSamples
, LONG nSamples
, LONG
*nSamplesProcessed
)
1640 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1643 TRACE("pin %p, pSamples %p, nSamples %ld, nSamplesProcessed %p.\n",
1644 avimuxin
, pSamples
, nSamples
, nSamplesProcessed
);
1646 for(*nSamplesProcessed
=0; *nSamplesProcessed
<nSamples
; (*nSamplesProcessed
)++)
1648 hr
= avimuxin
->pin
.pFuncsTable
->pfnReceive(&avimuxin
->pin
, pSamples
[*nSamplesProcessed
]);
1656 static HRESULT WINAPI
AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
1658 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1659 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1662 TRACE("avimuxin %p.\n", avimuxin
);
1664 if(!This
->source
.pMemInputPin
)
1667 hr
= IMemInputPin_ReceiveCanBlock(This
->source
.pMemInputPin
);
1668 return hr
!= S_FALSE
? S_OK
: S_FALSE
;
1671 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl
= {
1672 AviMuxIn_MemInputPin_QueryInterface
,
1673 AviMuxIn_MemInputPin_AddRef
,
1674 AviMuxIn_MemInputPin_Release
,
1675 AviMuxIn_MemInputPin_GetAllocator
,
1676 AviMuxIn_MemInputPin_NotifyAllocator
,
1677 AviMuxIn_MemInputPin_GetAllocatorRequirements
,
1678 AviMuxIn_MemInputPin_Receive
,
1679 AviMuxIn_MemInputPin_ReceiveMultiple
,
1680 AviMuxIn_MemInputPin_ReceiveCanBlock
1683 static inline AviMuxIn
* AviMuxIn_from_IPropertyBag(IPropertyBag
*iface
)
1685 return CONTAINING_RECORD(iface
, AviMuxIn
, IPropertyBag_iface
);
1688 static HRESULT WINAPI
AviMuxIn_PropertyBag_QueryInterface(
1689 IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1691 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1692 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1695 static ULONG WINAPI
AviMuxIn_PropertyBag_AddRef(IPropertyBag
*iface
)
1697 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1698 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1699 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1702 static ULONG WINAPI
AviMuxIn_PropertyBag_Release(IPropertyBag
*iface
)
1704 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1705 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1706 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1709 static HRESULT WINAPI
AviMuxIn_PropertyBag_Read(IPropertyBag
*iface
,
1710 const WCHAR
*name
, VARIANT
*value
, IErrorLog
*error_log
)
1712 FIXME("iface %p, name %s, value %p, error_log %p, stub!\n",
1713 iface
, debugstr_w(name
), value
, error_log
);
1717 static HRESULT WINAPI
AviMuxIn_PropertyBag_Write(IPropertyBag
*iface
,
1718 const WCHAR
*name
, VARIANT
*value
)
1720 FIXME("iface %p, name %s, value %s, stub!\n",
1721 iface
, debugstr_w(name
), debugstr_variant(value
));
1725 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl
= {
1726 AviMuxIn_PropertyBag_QueryInterface
,
1727 AviMuxIn_PropertyBag_AddRef
,
1728 AviMuxIn_PropertyBag_Release
,
1729 AviMuxIn_PropertyBag_Read
,
1730 AviMuxIn_PropertyBag_Write
1733 static inline AviMuxIn
* AviMuxIn_from_IQualityControl(IQualityControl
*iface
)
1735 return CONTAINING_RECORD(iface
, AviMuxIn
, IQualityControl_iface
);
1738 static HRESULT WINAPI
AviMuxIn_QualityControl_QueryInterface(
1739 IQualityControl
*iface
, REFIID riid
, void **ppv
)
1741 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1742 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1745 static ULONG WINAPI
AviMuxIn_QualityControl_AddRef(IQualityControl
*iface
)
1747 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1748 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1749 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1752 static ULONG WINAPI
AviMuxIn_QualityControl_Release(IQualityControl
*iface
)
1754 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1755 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1756 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1759 static HRESULT WINAPI
AviMuxIn_QualityControl_Notify(IQualityControl
*iface
,
1760 IBaseFilter
*filter
, Quality q
)
1762 FIXME("iface %p, filter %p, type %u, proportion %ld, late %s, timestamp %s, stub!\n",
1763 iface
, filter
, q
.Type
, q
.Proportion
, wine_dbgstr_longlong(q
.Late
),
1764 wine_dbgstr_longlong(q
.TimeStamp
));
1768 static HRESULT WINAPI
AviMuxIn_QualityControl_SetSink(IQualityControl
*iface
, IQualityControl
*sink
)
1770 FIXME("iface %p, sink %p, stub!\n", iface
, sink
);
1774 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl
= {
1775 AviMuxIn_QualityControl_QueryInterface
,
1776 AviMuxIn_QualityControl_AddRef
,
1777 AviMuxIn_QualityControl_Release
,
1778 AviMuxIn_QualityControl_Notify
,
1779 AviMuxIn_QualityControl_SetSink
1782 static HRESULT
create_input_pin(AviMux
*avimux
)
1788 if(avimux
->input_pin_no
>= MAX_PIN_NO
-1)
1791 swprintf(name
, ARRAY_SIZE(name
), L
"Input %02u", avimux
->input_pin_no
+ 1);
1793 if (!(object
= calloc(1, sizeof(*object
))))
1794 return E_OUTOFMEMORY
;
1796 strmbase_sink_init(&object
->pin
, &avimux
->filter
, name
, &sink_ops
, NULL
);
1797 object
->pin
.IMemInputPin_iface
.lpVtbl
= &AviMuxIn_MemInputPinVtbl
;
1798 object
->IAMStreamControl_iface
.lpVtbl
= &AviMuxIn_AMStreamControlVtbl
;
1799 object
->IPropertyBag_iface
.lpVtbl
= &AviMuxIn_PropertyBagVtbl
;
1800 object
->IQualityControl_iface
.lpVtbl
= &AviMuxIn_QualityControlVtbl
;
1802 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1803 &IID_IMemAllocator
, (void **)&object
->samples_allocator
);
1806 strmbase_sink_cleanup(&object
->pin
);
1811 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1812 &IID_IMemAllocator
, (void **)&object
->pin
.pAllocator
);
1815 IMemAllocator_Release(object
->samples_allocator
);
1816 strmbase_sink_cleanup(&object
->pin
);
1821 object
->indx
= (AVISUPERINDEX
*)&object
->indx_data
;
1822 object
->ix
= (AVISTDINDEX
*)object
->ix_data
;
1824 avimux
->in
[avimux
->input_pin_no
++] = object
;
1828 HRESULT
avi_mux_create(IUnknown
*outer
, IUnknown
**out
)
1833 if (!(avimux
= calloc(1, sizeof(AviMux
))))
1834 return E_OUTOFMEMORY
;
1836 strmbase_filter_init(&avimux
->filter
, outer
, &CLSID_AviDest
, &filter_ops
);
1837 avimux
->IConfigAviMux_iface
.lpVtbl
= &ConfigAviMuxVtbl
;
1838 avimux
->IConfigInterleaving_iface
.lpVtbl
= &ConfigInterleavingVtbl
;
1839 avimux
->IMediaSeeking_iface
.lpVtbl
= &MediaSeekingVtbl
;
1840 avimux
->IPersistMediaPropertyBag_iface
.lpVtbl
= &PersistMediaPropertyBagVtbl
;
1841 avimux
->ISpecifyPropertyPages_iface
.lpVtbl
= &SpecifyPropertyPagesVtbl
;
1843 strmbase_source_init(&avimux
->source
, &avimux
->filter
, L
"AVI Out", &source_ops
);
1844 avimux
->IQualityControl_iface
.lpVtbl
= &AviMuxOut_QualityControlVtbl
;
1845 avimux
->cur_stream
= 0;
1846 avimux
->cur_time
= 0;
1847 avimux
->stream
= NULL
;
1849 hr
= create_input_pin(avimux
);
1851 strmbase_source_cleanup(&avimux
->source
);
1852 strmbase_filter_cleanup(&avimux
->filter
);
1857 avimux
->interleave
= 10000000;
1859 TRACE("Created AVI mux %p.\n", avimux
);
1860 *out
= &avimux
->filter
.IUnknown_inner
;