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