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
31 #include "qcap_main.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(qcap
);
37 #define MAX_PIN_NO 128
38 #define AVISUPERINDEX_ENTRIES 2000
39 #define AVISTDINDEX_ENTRIES 4000
40 #define ALIGN(x) ((x+1)/2*2)
43 struct strmbase_sink pin
;
44 IAMStreamControl IAMStreamControl_iface
;
45 IPropertyBag IPropertyBag_iface
;
46 IQualityControl IQualityControl_iface
;
48 REFERENCE_TIME avg_time_per_frame
;
61 BYTE indx_data
[FIELD_OFFSET(AVISUPERINDEX
, aIndex
[AVISUPERINDEX_ENTRIES
])];
66 BYTE ix_data
[FIELD_OFFSET(AVISTDINDEX
, aIndex
[AVISTDINDEX_ENTRIES
])];
68 IMediaSample
*samples_head
;
69 IMemAllocator
*samples_allocator
;
73 struct strmbase_filter filter
;
74 IConfigAviMux IConfigAviMux_iface
;
75 IConfigInterleaving IConfigInterleaving_iface
;
76 IMediaSeeking IMediaSeeking_iface
;
77 IPersistMediaPropertyBag IPersistMediaPropertyBag_iface
;
78 ISpecifyPropertyPages ISpecifyPropertyPages_iface
;
80 InterleavingMode mode
;
81 REFERENCE_TIME interleave
;
82 REFERENCE_TIME preroll
;
84 struct strmbase_source source
;
85 IQualityControl IQualityControl_iface
;
88 AviMuxIn
*in
[MAX_PIN_NO
-1];
90 REFERENCE_TIME start
, stop
;
109 static HRESULT
create_input_pin(AviMux
*);
111 static inline AviMux
* impl_from_strmbase_filter(struct strmbase_filter
*filter
)
113 return CONTAINING_RECORD(filter
, AviMux
, filter
);
116 static struct strmbase_pin
*avi_mux_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
118 AviMux
*filter
= impl_from_strmbase_filter(iface
);
121 return &filter
->source
.pin
;
122 else if (index
<= filter
->input_pin_no
)
123 return &filter
->in
[index
- 1]->pin
.pin
;
127 static void avi_mux_destroy(struct strmbase_filter
*iface
)
129 AviMux
*filter
= impl_from_strmbase_filter(iface
);
132 strmbase_source_cleanup(&filter
->source
);
134 for (i
= 0; i
< filter
->input_pin_no
; ++i
)
136 IPin_Disconnect(&filter
->in
[i
]->pin
.pin
.IPin_iface
);
137 IMemAllocator_Release(filter
->in
[i
]->samples_allocator
);
138 filter
->in
[i
]->samples_allocator
= NULL
;
139 strmbase_sink_cleanup(&filter
->in
[i
]->pin
);
140 heap_free(filter
->in
[i
]);
143 heap_free(filter
->idx1
);
144 strmbase_filter_cleanup(&filter
->filter
);
146 ObjectRefCount(FALSE
);
149 static HRESULT
avi_mux_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
151 AviMux
*filter
= impl_from_strmbase_filter(iface
);
153 if (IsEqualGUID(iid
, &IID_IConfigAviMux
))
154 *out
= &filter
->IConfigAviMux_iface
;
155 else if (IsEqualGUID(iid
, &IID_IConfigInterleaving
))
156 *out
= &filter
->IConfigInterleaving_iface
;
157 else if (IsEqualGUID(iid
, &IID_IMediaSeeking
))
158 *out
= &filter
->IMediaSeeking_iface
;
159 else if (IsEqualGUID(iid
, &IID_IPersistMediaPropertyBag
))
160 *out
= &filter
->IPersistMediaPropertyBag_iface
;
161 else if (IsEqualGUID(iid
, &IID_ISpecifyPropertyPages
))
162 *out
= &filter
->ISpecifyPropertyPages_iface
;
164 return E_NOINTERFACE
;
166 IUnknown_AddRef((IUnknown
*)*out
);
170 static HRESULT
out_flush(AviMux
*This
)
178 hr
= IStream_Write(This
->stream
, This
->buf
, This
->buf_pos
, &written
);
181 if (written
!= This
->buf_pos
)
188 static HRESULT
out_seek(AviMux
*This
, int pos
)
193 hr
= out_flush(This
);
198 hr
= IStream_Seek(This
->stream
, li
, STREAM_SEEK_SET
, NULL
);
203 if(This
->out_pos
> This
->size
)
204 This
->size
= This
->out_pos
;
208 static HRESULT
out_write(AviMux
*This
, const void *data
, int size
)
214 if (size
> sizeof(This
->buf
) - This
->buf_pos
)
215 chunk_size
= sizeof(This
->buf
) - This
->buf_pos
;
219 memcpy(This
->buf
+ This
->buf_pos
, data
, chunk_size
);
221 data
= (const BYTE
*)data
+ chunk_size
;
222 This
->buf_pos
+= chunk_size
;
223 This
->out_pos
+= chunk_size
;
224 if (This
->out_pos
> This
->size
)
225 This
->size
= This
->out_pos
;
229 hr
= out_flush(This
);
237 static inline HRESULT
idx1_add_entry(AviMux
*avimux
, DWORD ckid
, DWORD flags
, DWORD off
, DWORD len
)
239 if(avimux
->idx1_entries
== avimux
->idx1_size
) {
240 AVIINDEXENTRY
*new_idx
= HeapReAlloc(GetProcessHeap(), 0, avimux
->idx1
,
241 sizeof(*avimux
->idx1
)*2*avimux
->idx1_size
);
243 return E_OUTOFMEMORY
;
245 avimux
->idx1_size
*= 2;
246 avimux
->idx1
= new_idx
;
249 avimux
->idx1
[avimux
->idx1_entries
].ckid
= ckid
;
250 avimux
->idx1
[avimux
->idx1_entries
].dwFlags
= flags
;
251 avimux
->idx1
[avimux
->idx1_entries
].dwChunkOffset
= off
;
252 avimux
->idx1
[avimux
->idx1_entries
].dwChunkLength
= len
;
253 avimux
->idx1_entries
++;
257 static HRESULT
flush_queue(AviMux
*avimux
, AviMuxIn
*avimuxin
, BOOL closing
)
259 IMediaSample
*sample
, **prev
, **head_prev
;
266 if (avimux
->cur_stream
!= avimuxin
->stream_id
)
269 while(avimuxin
->samples_head
) {
270 hr
= IMediaSample_GetPointer(avimuxin
->samples_head
, (BYTE
**)&head_prev
);
275 hr
= IMediaSample_GetPointer(*head_prev
, (BYTE
**)&prev
);
281 size
= IMediaSample_GetActualDataLength(sample
);
282 hr
= IMediaSample_GetPointer(sample
, &data
);
285 flags
= IMediaSample_IsDiscontinuity(sample
)==S_OK
? AM_SAMPLE_TIMEDISCONTINUITY
: 0;
286 if(IMediaSample_IsSyncPoint(sample
) == S_OK
)
287 flags
|= AM_SAMPLE_SPLICEPOINT
;
289 if (avimuxin
->stream_time
+ (closing
? 0 : avimuxin
->strh
.dwScale
) > avimux
->cur_time
290 && !(flags
& AM_SAMPLE_TIMEDISCONTINUITY
))
295 avimux
->cur_stream
++;
296 if(avimux
->cur_stream
>= avimux
->input_pin_no
-1) {
297 avimux
->cur_time
+= avimux
->interleave
;
298 avimux
->cur_stream
= 0;
300 avimuxin
= avimux
->in
[avimux
->cur_stream
];
304 if(avimuxin
->ix
->nEntriesInUse
== AVISTDINDEX_ENTRIES
) {
305 /* TODO: use output pins Deliver/Receive method */
306 hr
= out_seek(avimux
, avimuxin
->ix_off
);
309 hr
= out_write(avimux
, avimuxin
->ix
, sizeof(avimuxin
->ix_data
));
313 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].qwOffset
= avimuxin
->ix_off
;
314 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].dwSize
= sizeof(avimuxin
->ix_data
);
315 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].dwDuration
= AVISTDINDEX_ENTRIES
;
316 avimuxin
->indx
->nEntriesInUse
++;
318 memset(avimuxin
->ix
->aIndex
, 0, sizeof(avimuxin
->ix
->aIndex
)*avimuxin
->ix
->nEntriesInUse
);
319 avimuxin
->ix
->nEntriesInUse
= 0;
320 avimuxin
->ix
->qwBaseOffset
= 0;
322 avimuxin
->ix_off
= avimux
->size
;
323 avimux
->size
+= sizeof(avimuxin
->ix_data
);
326 if(*head_prev
== avimuxin
->samples_head
)
327 avimuxin
->samples_head
= NULL
;
331 avimuxin
->stream_time
+= avimuxin
->strh
.dwScale
;
332 avimuxin
->strh
.dwLength
++;
333 if(!(flags
& AM_SAMPLE_TIMEDISCONTINUITY
)) {
334 if(!avimuxin
->ix
->qwBaseOffset
)
335 avimuxin
->ix
->qwBaseOffset
= avimux
->size
;
336 avimuxin
->ix
->aIndex
[avimuxin
->ix
->nEntriesInUse
].dwOffset
=
337 avimux
->size
+ sizeof(RIFFCHUNK
) - avimuxin
->ix
->qwBaseOffset
;
339 hr
= out_seek(avimux
, avimux
->size
);
341 IMediaSample_Release(sample
);
345 avimuxin
->ix
->aIndex
[avimuxin
->ix
->nEntriesInUse
].dwSize
= size
|
346 (flags
& AM_SAMPLE_SPLICEPOINT
? 0 : AVISTDINDEX_DELTAFRAME
);
347 avimuxin
->ix
->nEntriesInUse
++;
349 rf
.fcc
= FCC('0'+avimuxin
->stream_id
/10, '0'+avimuxin
->stream_id
%10,
350 'd', flags
& AM_SAMPLE_SPLICEPOINT
? 'b' : 'c');
352 hr
= idx1_add_entry(avimux
, rf
.fcc
, flags
& AM_SAMPLE_SPLICEPOINT
? AVIIF_KEYFRAME
: 0,
353 flags
& AM_SAMPLE_TIMEDISCONTINUITY
?
354 avimux
->idx1
[avimux
->idx1_entries
-1].dwChunkOffset
: avimux
->size
, size
);
356 IMediaSample_Release(sample
);
360 if(!(flags
& AM_SAMPLE_TIMEDISCONTINUITY
)) {
361 hr
= out_write(avimux
, &rf
, sizeof(rf
));
363 IMediaSample_Release(sample
);
366 hr
= out_write(avimux
, data
, size
);
368 IMediaSample_Release(sample
);
372 hr
= out_write(avimux
, &flags
, ALIGN(rf
.cb
)-rf
.cb
);
374 IMediaSample_Release(sample
);
378 IMediaSample_Release(sample
);
383 static HRESULT
queue_sample(AviMux
*avimux
, AviMuxIn
*avimuxin
, IMediaSample
*sample
)
385 IMediaSample
**prev
, **head_prev
;
388 hr
= IMediaSample_GetPointer(sample
, (BYTE
**)&prev
);
393 if(avimuxin
->samples_head
) {
394 hr
= IMediaSample_GetPointer(avimuxin
->samples_head
, (BYTE
**)&head_prev
);
404 avimuxin
->samples_head
= sample
;
405 IMediaSample_AddRef(sample
);
407 return flush_queue(avimux
, avimuxin
, FALSE
);
410 static HRESULT
avi_mux_cleanup_stream(struct strmbase_filter
*iface
)
412 AviMux
*This
= impl_from_strmbase_filter(iface
);
421 int idx1_off
, empty_stream
;
423 empty_stream
= This
->cur_stream
;
424 for(i
=empty_stream
+1; ; i
++) {
425 if(i
>= This
->input_pin_no
-1)
427 if(i
== empty_stream
)
430 This
->cur_stream
= i
;
431 hr
= flush_queue(This
, This
->in
[This
->cur_stream
], TRUE
);
436 idx1_off
= This
->size
;
437 rc
.fcc
= ckidAVIOLDINDEX
;
438 rc
.cb
= This
->idx1_entries
* sizeof(*This
->idx1
);
439 hr
= out_write(This
, &rc
, sizeof(rc
));
442 hr
= out_write(This
, This
->idx1
, This
->idx1_entries
* sizeof(*This
->idx1
));
445 /* native writes 8 '\0' characters after the end of RIFF data */
447 hr
= out_write(This
, &i
, sizeof(i
));
450 hr
= out_write(This
, &i
, sizeof(i
));
454 for(i
=0; i
<This
->input_pin_no
; i
++) {
455 if(!This
->in
[i
]->pin
.pin
.peer
)
458 hr
= out_seek(This
, This
->in
[i
]->ix_off
);
462 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].qwOffset
= This
->in
[i
]->ix_off
;
463 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwSize
= sizeof(This
->in
[i
]->ix_data
);
464 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwDuration
= This
->in
[i
]->strh
.dwLength
;
465 if(This
->in
[i
]->indx
->nEntriesInUse
) {
466 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwDuration
-=
467 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
-1].dwDuration
;
469 This
->in
[i
]->indx
->nEntriesInUse
++;
470 hr
= out_write(This
, This
->in
[i
]->ix
, sizeof(This
->in
[i
]->ix_data
));
475 hr
= out_seek(This
, 0);
479 rl
.fcc
= FCC('R','I','F','F');
480 rl
.cb
= This
->size
- sizeof(RIFFCHUNK
) - 2 * sizeof(int);
481 rl
.fccListType
= FCC('A','V','I',' ');
482 hr
= out_write(This
, &rl
, sizeof(rl
));
486 rl
.fcc
= FCC('L','I','S','T');
487 rl
.cb
= This
->movi_off
- sizeof(RIFFLIST
) - sizeof(RIFFCHUNK
);
488 rl
.fccListType
= FCC('h','d','r','l');
489 hr
= out_write(This
, &rl
, sizeof(rl
));
493 /* FIXME: set This->avih.dwMaxBytesPerSec value */
494 This
->avih
.dwTotalFrames
= (This
->stop
-This
->start
) / 10 / This
->avih
.dwMicroSecPerFrame
;
495 hr
= out_write(This
, &This
->avih
, sizeof(This
->avih
));
499 for(i
=0; i
<This
->input_pin_no
; i
++) {
500 if(!This
->in
[i
]->pin
.pin
.peer
)
503 rl
.cb
= sizeof(FOURCC
) + sizeof(AVISTREAMHEADER
) + sizeof(RIFFCHUNK
) +
504 This
->in
[i
]->strf
->cb
+ sizeof(This
->in
[i
]->indx_data
);
505 rl
.fccListType
= ckidSTREAMLIST
;
506 hr
= out_write(This
, &rl
, sizeof(rl
));
510 hr
= out_write(This
, &This
->in
[i
]->strh
, sizeof(AVISTREAMHEADER
));
514 hr
= out_write(This
, This
->in
[i
]->strf
, sizeof(RIFFCHUNK
) + This
->in
[i
]->strf
->cb
);
518 hr
= out_write(This
, This
->in
[i
]->indx
, sizeof(This
->in
[i
]->indx_data
));
523 rl
.cb
= sizeof(dmlh
) + sizeof(FOURCC
);
524 rl
.fccListType
= ckidODML
;
525 hr
= out_write(This
, &rl
, sizeof(rl
));
529 memset(&dmlh
, 0, sizeof(dmlh
));
530 dmlh
.fcc
= ckidAVIEXTHEADER
;
531 dmlh
.cb
= sizeof(dmlh
) - sizeof(RIFFCHUNK
);
532 dmlh
.dwGrandFrames
= This
->in
[0]->strh
.dwLength
;
533 hr
= out_write(This
, &dmlh
, sizeof(dmlh
));
535 rl
.cb
= idx1_off
- This
->movi_off
- sizeof(RIFFCHUNK
);
536 rl
.fccListType
= FCC('m','o','v','i');
537 out_write(This
, &rl
, sizeof(rl
));
540 IStream_Release(This
->stream
);
547 static HRESULT
avi_mux_init_stream(struct strmbase_filter
*iface
)
549 AviMux
*This
= impl_from_strmbase_filter(iface
);
553 if(This
->mode
!= INTERLEAVE_FULL
) {
554 FIXME("mode not supported (%d)\n", This
->mode
);
558 for(i
=0; i
<This
->input_pin_no
; i
++) {
562 if(!This
->in
[i
]->pin
.pin
.peer
)
565 hr
= IPin_QueryInterface(This
->in
[i
]->pin
.pin
.peer
,
566 &IID_IMediaSeeking
, (void**)&ms
);
570 hr
= IMediaSeeking_GetPositions(ms
, &cur
, &stop
);
572 IMediaSeeking_Release(ms
);
576 FIXME("Use IMediaSeeking to fill stream header\n");
577 IMediaSeeking_Release(ms
);
580 if (This
->source
.pMemInputPin
)
582 hr
= IMemInputPin_QueryInterface(This
->source
.pMemInputPin
,
583 &IID_IStream
, (void **)&This
->stream
);
588 This
->idx1_entries
= 0;
589 if(!This
->idx1_size
) {
590 This
->idx1_size
= 1024;
591 This
->idx1
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->idx1
)*This
->idx1_size
);
593 return E_OUTOFMEMORY
;
596 This
->size
= 3*sizeof(RIFFLIST
) + sizeof(AVIMAINHEADER
) + sizeof(AVIEXTHEADER
);
599 memset(&This
->avih
, 0, sizeof(This
->avih
));
600 for(i
=0; i
<This
->input_pin_no
; i
++) {
601 if(!This
->in
[i
]->pin
.pin
.peer
)
604 This
->avih
.dwStreams
++;
605 This
->size
+= sizeof(RIFFLIST
) + sizeof(AVISTREAMHEADER
) + sizeof(RIFFCHUNK
)
606 + This
->in
[i
]->strf
->cb
+ sizeof(This
->in
[i
]->indx_data
);
608 This
->in
[i
]->strh
.dwScale
= MulDiv(This
->in
[i
]->avg_time_per_frame
, This
->interleave
, 10000000);
609 This
->in
[i
]->strh
.dwRate
= This
->interleave
;
611 hr
= IMemAllocator_Commit(This
->in
[i
]->pin
.pAllocator
);
615 IStream_Release(This
->stream
);
622 This
->movi_off
= This
->size
;
623 This
->size
+= sizeof(RIFFLIST
);
625 idx1_add_entry(This
, FCC('7','F','x','x'), 0, This
->movi_off
+ sizeof(RIFFLIST
), 0);
628 for(i
=0; i
<This
->input_pin_no
; i
++) {
629 if(!This
->in
[i
]->pin
.pin
.peer
)
632 This
->in
[i
]->ix_off
= This
->size
;
633 This
->size
+= sizeof(This
->in
[i
]->ix_data
);
634 This
->in
[i
]->ix
->fcc
= FCC('i','x','0'+stream_id
/10,'0'+stream_id
%10);
635 This
->in
[i
]->ix
->cb
= sizeof(This
->in
[i
]->ix_data
) - sizeof(RIFFCHUNK
);
636 This
->in
[i
]->ix
->wLongsPerEntry
= 2;
637 This
->in
[i
]->ix
->bIndexSubType
= 0;
638 This
->in
[i
]->ix
->bIndexType
= AVI_INDEX_OF_CHUNKS
;
639 This
->in
[i
]->ix
->dwChunkId
= FCC('0'+stream_id
/10,'0'+stream_id
%10,'d','b');
640 This
->in
[i
]->ix
->qwBaseOffset
= 0;
642 This
->in
[i
]->indx
->fcc
= ckidAVISUPERINDEX
;
643 This
->in
[i
]->indx
->cb
= sizeof(This
->in
[i
]->indx_data
) - sizeof(RIFFCHUNK
);
644 This
->in
[i
]->indx
->wLongsPerEntry
= 4;
645 This
->in
[i
]->indx
->bIndexSubType
= 0;
646 This
->in
[i
]->indx
->bIndexType
= AVI_INDEX_OF_INDEXES
;
647 This
->in
[i
]->indx
->dwChunkId
= This
->in
[i
]->ix
->dwChunkId
;
648 This
->in
[i
]->stream_id
= stream_id
++;
654 This
->avih
.fcc
= ckidMAINAVIHEADER
;
655 This
->avih
.cb
= sizeof(AVIMAINHEADER
) - sizeof(RIFFCHUNK
);
656 /* TODO: Use first video stream */
657 This
->avih
.dwMicroSecPerFrame
= This
->in
[0]->avg_time_per_frame
/10;
658 This
->avih
.dwPaddingGranularity
= 1;
659 This
->avih
.dwFlags
= AVIF_TRUSTCKTYPE
| AVIF_HASINDEX
;
660 This
->avih
.dwWidth
= ((BITMAPINFOHEADER
*)This
->in
[0]->strf
->data
)->biWidth
;
661 This
->avih
.dwHeight
= ((BITMAPINFOHEADER
*)This
->in
[0]->strf
->data
)->biHeight
;
666 static const struct strmbase_filter_ops filter_ops
=
668 .filter_get_pin
= avi_mux_get_pin
,
669 .filter_destroy
= avi_mux_destroy
,
670 .filter_query_interface
= avi_mux_query_interface
,
671 .filter_init_stream
= avi_mux_init_stream
,
672 .filter_cleanup_stream
= avi_mux_cleanup_stream
,
675 static inline AviMux
* impl_from_IConfigAviMux(IConfigAviMux
*iface
)
677 return CONTAINING_RECORD(iface
, AviMux
, IConfigAviMux_iface
);
680 static HRESULT WINAPI
ConfigAviMux_QueryInterface(
681 IConfigAviMux
*iface
, REFIID riid
, void **ppv
)
683 AviMux
*This
= impl_from_IConfigAviMux(iface
);
684 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
687 static ULONG WINAPI
ConfigAviMux_AddRef(IConfigAviMux
*iface
)
689 AviMux
*This
= impl_from_IConfigAviMux(iface
);
690 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
693 static ULONG WINAPI
ConfigAviMux_Release(IConfigAviMux
*iface
)
695 AviMux
*This
= impl_from_IConfigAviMux(iface
);
696 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
699 static HRESULT WINAPI
ConfigAviMux_SetMasterStream(IConfigAviMux
*iface
, LONG iStream
)
701 AviMux
*This
= impl_from_IConfigAviMux(iface
);
702 FIXME("(%p)->(%d)\n", This
, iStream
);
706 static HRESULT WINAPI
ConfigAviMux_GetMasterStream(IConfigAviMux
*iface
, LONG
*pStream
)
708 AviMux
*This
= impl_from_IConfigAviMux(iface
);
709 FIXME("(%p)->(%p)\n", This
, pStream
);
713 static HRESULT WINAPI
ConfigAviMux_SetOutputCompatibilityIndex(
714 IConfigAviMux
*iface
, BOOL fOldIndex
)
716 AviMux
*This
= impl_from_IConfigAviMux(iface
);
717 FIXME("(%p)->(%x)\n", This
, fOldIndex
);
721 static HRESULT WINAPI
ConfigAviMux_GetOutputCompatibilityIndex(
722 IConfigAviMux
*iface
, BOOL
*pfOldIndex
)
724 AviMux
*This
= impl_from_IConfigAviMux(iface
);
725 FIXME("(%p)->(%p)\n", This
, pfOldIndex
);
729 static const IConfigAviMuxVtbl ConfigAviMuxVtbl
= {
730 ConfigAviMux_QueryInterface
,
732 ConfigAviMux_Release
,
733 ConfigAviMux_SetMasterStream
,
734 ConfigAviMux_GetMasterStream
,
735 ConfigAviMux_SetOutputCompatibilityIndex
,
736 ConfigAviMux_GetOutputCompatibilityIndex
739 static inline AviMux
* impl_from_IConfigInterleaving(IConfigInterleaving
*iface
)
741 return CONTAINING_RECORD(iface
, AviMux
, IConfigInterleaving_iface
);
744 static HRESULT WINAPI
ConfigInterleaving_QueryInterface(
745 IConfigInterleaving
*iface
, REFIID riid
, void **ppv
)
747 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
748 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
751 static ULONG WINAPI
ConfigInterleaving_AddRef(IConfigInterleaving
*iface
)
753 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
754 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
757 static ULONG WINAPI
ConfigInterleaving_Release(IConfigInterleaving
*iface
)
759 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
760 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
763 static HRESULT WINAPI
ConfigInterleaving_put_Mode(
764 IConfigInterleaving
*iface
, InterleavingMode mode
)
766 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
768 TRACE("(%p)->(%d)\n", This
, mode
);
770 if(mode
>INTERLEAVE_NONE_BUFFERED
)
773 if(This
->mode
!= mode
) {
774 if(This
->source
.pin
.peer
) {
775 HRESULT hr
= IFilterGraph_Reconnect(This
->filter
.graph
, &This
->source
.pin
.IPin_iface
);
786 static HRESULT WINAPI
ConfigInterleaving_get_Mode(
787 IConfigInterleaving
*iface
, InterleavingMode
*pMode
)
789 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
790 FIXME("(%p)->(%p)\n", This
, pMode
);
794 static HRESULT WINAPI
ConfigInterleaving_put_Interleaving(IConfigInterleaving
*iface
,
795 const REFERENCE_TIME
*prtInterleave
, const REFERENCE_TIME
*prtPreroll
)
797 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
799 TRACE("(%p)->(%p %p)\n", This
, prtInterleave
, prtPreroll
);
802 This
->interleave
= *prtInterleave
;
804 This
->preroll
= *prtPreroll
;
808 static HRESULT WINAPI
ConfigInterleaving_get_Interleaving(IConfigInterleaving
*iface
,
809 REFERENCE_TIME
*prtInterleave
, REFERENCE_TIME
*prtPreroll
)
811 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
812 FIXME("(%p)->(%p %p)\n", This
, prtInterleave
, prtPreroll
);
816 static const IConfigInterleavingVtbl ConfigInterleavingVtbl
= {
817 ConfigInterleaving_QueryInterface
,
818 ConfigInterleaving_AddRef
,
819 ConfigInterleaving_Release
,
820 ConfigInterleaving_put_Mode
,
821 ConfigInterleaving_get_Mode
,
822 ConfigInterleaving_put_Interleaving
,
823 ConfigInterleaving_get_Interleaving
826 static inline AviMux
* impl_from_IMediaSeeking(IMediaSeeking
*iface
)
828 return CONTAINING_RECORD(iface
, AviMux
, IMediaSeeking_iface
);
831 static HRESULT WINAPI
MediaSeeking_QueryInterface(
832 IMediaSeeking
*iface
, REFIID riid
, void **ppv
)
834 AviMux
*This
= impl_from_IMediaSeeking(iface
);
835 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
838 static ULONG WINAPI
MediaSeeking_AddRef(IMediaSeeking
*iface
)
840 AviMux
*This
= impl_from_IMediaSeeking(iface
);
841 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
844 static ULONG WINAPI
MediaSeeking_Release(IMediaSeeking
*iface
)
846 AviMux
*This
= impl_from_IMediaSeeking(iface
);
847 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
850 static HRESULT WINAPI
MediaSeeking_GetCapabilities(
851 IMediaSeeking
*iface
, DWORD
*pCapabilities
)
853 AviMux
*This
= impl_from_IMediaSeeking(iface
);
854 FIXME("(%p)->(%p)\n", This
, pCapabilities
);
858 static HRESULT WINAPI
MediaSeeking_CheckCapabilities(
859 IMediaSeeking
*iface
, DWORD
*pCapabilities
)
861 AviMux
*This
= impl_from_IMediaSeeking(iface
);
862 FIXME("(%p)->(%p)\n", This
, pCapabilities
);
866 static HRESULT WINAPI
MediaSeeking_IsFormatSupported(
867 IMediaSeeking
*iface
, const GUID
*pFormat
)
869 AviMux
*This
= impl_from_IMediaSeeking(iface
);
870 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
874 static HRESULT WINAPI
MediaSeeking_QueryPreferredFormat(
875 IMediaSeeking
*iface
, GUID
*pFormat
)
877 AviMux
*This
= impl_from_IMediaSeeking(iface
);
878 FIXME("(%p)->(%p)\n", This
, pFormat
);
882 static HRESULT WINAPI
MediaSeeking_GetTimeFormat(
883 IMediaSeeking
*iface
, GUID
*pFormat
)
885 AviMux
*This
= impl_from_IMediaSeeking(iface
);
886 FIXME("(%p)->(%p)\n", This
, pFormat
);
890 static HRESULT WINAPI
MediaSeeking_IsUsingTimeFormat(
891 IMediaSeeking
*iface
, const GUID
*pFormat
)
893 AviMux
*This
= impl_from_IMediaSeeking(iface
);
894 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
898 static HRESULT WINAPI
MediaSeeking_SetTimeFormat(
899 IMediaSeeking
*iface
, const GUID
*pFormat
)
901 AviMux
*This
= impl_from_IMediaSeeking(iface
);
902 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
906 static HRESULT WINAPI
MediaSeeking_GetDuration(
907 IMediaSeeking
*iface
, LONGLONG
*pDuration
)
909 AviMux
*This
= impl_from_IMediaSeeking(iface
);
910 FIXME("(%p)->(%p)\n", This
, pDuration
);
914 static HRESULT WINAPI
MediaSeeking_GetStopPosition(
915 IMediaSeeking
*iface
, LONGLONG
*pStop
)
917 AviMux
*This
= impl_from_IMediaSeeking(iface
);
918 FIXME("(%p)->(%p)\n", This
, pStop
);
922 static HRESULT WINAPI
MediaSeeking_GetCurrentPosition(
923 IMediaSeeking
*iface
, LONGLONG
*pCurrent
)
925 AviMux
*This
= impl_from_IMediaSeeking(iface
);
926 FIXME("(%p)->(%p)\n", This
, pCurrent
);
930 static HRESULT WINAPI
MediaSeeking_ConvertTimeFormat(IMediaSeeking
*iface
, LONGLONG
*pTarget
,
931 const GUID
*pTargetFormat
, LONGLONG Source
, const GUID
*pSourceFormat
)
933 AviMux
*This
= impl_from_IMediaSeeking(iface
);
934 FIXME("(%p)->(%p %s %s %s)\n", This
, pTarget
, debugstr_guid(pTargetFormat
),
935 wine_dbgstr_longlong(Source
), debugstr_guid(pSourceFormat
));
939 static HRESULT WINAPI
MediaSeeking_SetPositions(IMediaSeeking
*iface
, LONGLONG
*pCurrent
,
940 DWORD dwCurrentFlags
, LONGLONG
*pStop
, DWORD dwStopFlags
)
942 AviMux
*This
= impl_from_IMediaSeeking(iface
);
943 FIXME("(%p)->(%p %x %p %x)\n", This
, pCurrent
, dwCurrentFlags
, pStop
, dwStopFlags
);
947 static HRESULT WINAPI
MediaSeeking_GetPositions(IMediaSeeking
*iface
,
948 LONGLONG
*pCurrent
, LONGLONG
*pStop
)
950 AviMux
*This
= impl_from_IMediaSeeking(iface
);
951 FIXME("(%p)->(%p %p)\n", This
, pCurrent
, pStop
);
955 static HRESULT WINAPI
MediaSeeking_GetAvailable(IMediaSeeking
*iface
,
956 LONGLONG
*pEarliest
, LONGLONG
*pLatest
)
958 AviMux
*This
= impl_from_IMediaSeeking(iface
);
959 FIXME("(%p)->(%p %p)\n", This
, pEarliest
, pLatest
);
963 static HRESULT WINAPI
MediaSeeking_SetRate(IMediaSeeking
*iface
, double dRate
)
965 AviMux
*This
= impl_from_IMediaSeeking(iface
);
966 FIXME("(%p)->(%lf)\n", This
, dRate
);
970 static HRESULT WINAPI
MediaSeeking_GetRate(IMediaSeeking
*iface
, double *pdRate
)
972 AviMux
*This
= impl_from_IMediaSeeking(iface
);
973 FIXME("(%p)->(%p)\n", This
, pdRate
);
977 static HRESULT WINAPI
MediaSeeking_GetPreroll(IMediaSeeking
*iface
, LONGLONG
*pllPreroll
)
979 AviMux
*This
= impl_from_IMediaSeeking(iface
);
980 FIXME("(%p)->(%p)\n", This
, pllPreroll
);
984 static const IMediaSeekingVtbl MediaSeekingVtbl
= {
985 MediaSeeking_QueryInterface
,
987 MediaSeeking_Release
,
988 MediaSeeking_GetCapabilities
,
989 MediaSeeking_CheckCapabilities
,
990 MediaSeeking_IsFormatSupported
,
991 MediaSeeking_QueryPreferredFormat
,
992 MediaSeeking_GetTimeFormat
,
993 MediaSeeking_IsUsingTimeFormat
,
994 MediaSeeking_SetTimeFormat
,
995 MediaSeeking_GetDuration
,
996 MediaSeeking_GetStopPosition
,
997 MediaSeeking_GetCurrentPosition
,
998 MediaSeeking_ConvertTimeFormat
,
999 MediaSeeking_SetPositions
,
1000 MediaSeeking_GetPositions
,
1001 MediaSeeking_GetAvailable
,
1002 MediaSeeking_SetRate
,
1003 MediaSeeking_GetRate
,
1004 MediaSeeking_GetPreroll
1007 static inline AviMux
* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag
*iface
)
1009 return CONTAINING_RECORD(iface
, AviMux
, IPersistMediaPropertyBag_iface
);
1012 static HRESULT WINAPI
PersistMediaPropertyBag_QueryInterface(
1013 IPersistMediaPropertyBag
*iface
, REFIID riid
, void **ppv
)
1015 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1016 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1019 static ULONG WINAPI
PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag
*iface
)
1021 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1022 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1025 static ULONG WINAPI
PersistMediaPropertyBag_Release(IPersistMediaPropertyBag
*iface
)
1027 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1028 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1031 static HRESULT WINAPI
PersistMediaPropertyBag_GetClassID(
1032 IPersistMediaPropertyBag
*iface
, CLSID
*pClassID
)
1034 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1035 return IBaseFilter_GetClassID(&This
->filter
.IBaseFilter_iface
, pClassID
);
1038 static HRESULT WINAPI
PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag
*iface
)
1040 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1041 FIXME("(%p)->()\n", This
);
1045 static HRESULT WINAPI
PersistMediaPropertyBag_Load(IPersistMediaPropertyBag
*iface
,
1046 IMediaPropertyBag
*pPropBag
, IErrorLog
*pErrorLog
)
1048 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1049 FIXME("(%p)->()\n", This
);
1053 static HRESULT WINAPI
PersistMediaPropertyBag_Save(IPersistMediaPropertyBag
*iface
,
1054 IMediaPropertyBag
*pPropBag
, BOOL fClearDirty
, BOOL fSaveAllProperties
)
1056 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1057 FIXME("(%p)->()\n", This
);
1061 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl
= {
1062 PersistMediaPropertyBag_QueryInterface
,
1063 PersistMediaPropertyBag_AddRef
,
1064 PersistMediaPropertyBag_Release
,
1065 PersistMediaPropertyBag_GetClassID
,
1066 PersistMediaPropertyBag_InitNew
,
1067 PersistMediaPropertyBag_Load
,
1068 PersistMediaPropertyBag_Save
1071 static inline AviMux
* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages
*iface
)
1073 return CONTAINING_RECORD(iface
, AviMux
, ISpecifyPropertyPages_iface
);
1076 static HRESULT WINAPI
SpecifyPropertyPages_QueryInterface(
1077 ISpecifyPropertyPages
*iface
, REFIID riid
, void **ppv
)
1079 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1080 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1083 static ULONG WINAPI
SpecifyPropertyPages_AddRef(ISpecifyPropertyPages
*iface
)
1085 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1086 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1089 static ULONG WINAPI
SpecifyPropertyPages_Release(ISpecifyPropertyPages
*iface
)
1091 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1092 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1095 static HRESULT WINAPI
SpecifyPropertyPages_GetPages(
1096 ISpecifyPropertyPages
*iface
, CAUUID
*pPages
)
1098 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1099 FIXME("(%p)->(%p)\n", This
, pPages
);
1103 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl
= {
1104 SpecifyPropertyPages_QueryInterface
,
1105 SpecifyPropertyPages_AddRef
,
1106 SpecifyPropertyPages_Release
,
1107 SpecifyPropertyPages_GetPages
1110 static inline AviMux
*impl_from_source_pin(struct strmbase_pin
*iface
)
1112 return CONTAINING_RECORD(iface
, AviMux
, source
.pin
);
1115 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
1117 AviMux
*filter
= impl_from_source_pin(iface
);
1119 if (IsEqualGUID(iid
, &IID_IQualityControl
))
1120 *out
= &filter
->IQualityControl_iface
;
1122 return E_NOINTERFACE
;
1124 IUnknown_AddRef((IUnknown
*)*out
);
1128 static HRESULT
source_query_accept(struct strmbase_pin
*base
, const AM_MEDIA_TYPE
*amt
)
1130 FIXME("(%p) stub\n", base
);
1134 static HRESULT WINAPI
AviMuxOut_AttemptConnection(struct strmbase_source
*iface
,
1135 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1137 AviMux
*filter
= impl_from_source_pin(&iface
->pin
);
1142 hr
= IPin_QueryDirection(pReceivePin
, &dir
);
1143 if(hr
==S_OK
&& dir
!=PINDIR_INPUT
)
1144 return VFW_E_INVALID_DIRECTION
;
1146 if (FAILED(hr
= BaseOutputPinImpl_AttemptConnection(iface
, pReceivePin
, pmt
)))
1149 for (i
= 0; i
< filter
->input_pin_no
; ++i
)
1151 if (!filter
->in
[i
]->pin
.pin
.peer
)
1154 hr
= IFilterGraph_Reconnect(filter
->filter
.graph
, &filter
->in
[i
]->pin
.pin
.IPin_iface
);
1157 IPin_Disconnect(&iface
->pin
.IPin_iface
);
1165 static HRESULT
source_get_media_type(struct strmbase_pin
*base
, unsigned int iPosition
, AM_MEDIA_TYPE
*amt
)
1167 TRACE("(%p)->(%d %p)\n", base
, iPosition
, amt
);
1170 return VFW_S_NO_MORE_ITEMS
;
1172 amt
->majortype
= MEDIATYPE_Stream
;
1173 amt
->subtype
= MEDIASUBTYPE_Avi
;
1174 amt
->bFixedSizeSamples
= TRUE
;
1175 amt
->bTemporalCompression
= FALSE
;
1176 amt
->lSampleSize
= 1;
1177 amt
->formattype
= GUID_NULL
;
1180 amt
->pbFormat
= NULL
;
1184 static HRESULT WINAPI
AviMuxOut_DecideAllocator(struct strmbase_source
*base
,
1185 IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
1187 ALLOCATOR_PROPERTIES req
, actual
;
1190 TRACE("(%p)->(%p %p)\n", base
, pPin
, pAlloc
);
1192 hr
= BaseOutputPinImpl_InitAllocator(base
, pAlloc
);
1196 hr
= IMemInputPin_GetAllocatorRequirements(pPin
, &req
);
1203 hr
= IMemAllocator_SetProperties(*pAlloc
, &req
, &actual
);
1207 return IMemInputPin_NotifyAllocator(pPin
, *pAlloc
, TRUE
);
1210 static const struct strmbase_source_ops source_ops
=
1212 .base
.pin_query_interface
= source_query_interface
,
1213 .base
.pin_query_accept
= source_query_accept
,
1214 .base
.pin_get_media_type
= source_get_media_type
,
1215 .pfnAttemptConnection
= AviMuxOut_AttemptConnection
,
1216 .pfnDecideAllocator
= AviMuxOut_DecideAllocator
,
1219 static inline AviMux
* impl_from_out_IQualityControl(IQualityControl
*iface
)
1221 return CONTAINING_RECORD(iface
, AviMux
, IQualityControl_iface
);
1224 static HRESULT WINAPI
AviMuxOut_QualityControl_QueryInterface(
1225 IQualityControl
*iface
, REFIID riid
, void **ppv
)
1227 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1228 return IPin_QueryInterface(&This
->source
.pin
.IPin_iface
, riid
, ppv
);
1231 static ULONG WINAPI
AviMuxOut_QualityControl_AddRef(IQualityControl
*iface
)
1233 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1234 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1237 static ULONG WINAPI
AviMuxOut_QualityControl_Release(IQualityControl
*iface
)
1239 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1240 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1243 static HRESULT WINAPI
AviMuxOut_QualityControl_Notify(IQualityControl
*iface
,
1244 IBaseFilter
*pSelf
, Quality q
)
1246 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1247 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This
, pSelf
,
1248 q
.Type
, q
.Proportion
,
1249 wine_dbgstr_longlong(q
.Late
),
1250 wine_dbgstr_longlong(q
.TimeStamp
));
1254 static HRESULT WINAPI
AviMuxOut_QualityControl_SetSink(
1255 IQualityControl
*iface
, IQualityControl
*piqc
)
1257 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1258 FIXME("(%p)->(%p)\n", This
, piqc
);
1262 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl
= {
1263 AviMuxOut_QualityControl_QueryInterface
,
1264 AviMuxOut_QualityControl_AddRef
,
1265 AviMuxOut_QualityControl_Release
,
1266 AviMuxOut_QualityControl_Notify
,
1267 AviMuxOut_QualityControl_SetSink
1270 static inline AviMuxIn
*impl_sink_from_strmbase_pin(struct strmbase_pin
*iface
)
1272 return CONTAINING_RECORD(iface
, AviMuxIn
, pin
.pin
.IPin_iface
);
1275 static HRESULT
sink_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
1277 AviMuxIn
*pin
= impl_sink_from_strmbase_pin(iface
);
1279 if (IsEqualGUID(iid
, &IID_IAMStreamControl
))
1280 *out
= &pin
->IAMStreamControl_iface
;
1281 else if (IsEqualGUID(iid
, &IID_IMemInputPin
))
1282 *out
= &pin
->pin
.IMemInputPin_iface
;
1283 else if (IsEqualGUID(iid
, &IID_IPropertyBag
))
1284 *out
= &pin
->IPropertyBag_iface
;
1285 else if (IsEqualGUID(iid
, &IID_IQualityControl
))
1286 *out
= &pin
->IQualityControl_iface
;
1288 return E_NOINTERFACE
;
1290 IUnknown_AddRef((IUnknown
*)*out
);
1294 static HRESULT
sink_query_accept(struct strmbase_pin
*base
, const AM_MEDIA_TYPE
*pmt
)
1296 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
) &&
1297 IsEqualIID(&pmt
->formattype
, &FORMAT_WaveFormatEx
))
1299 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Interleaved
) &&
1300 IsEqualIID(&pmt
->formattype
, &FORMAT_DvInfo
))
1302 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
) &&
1303 (IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
) ||
1304 IsEqualIID(&pmt
->formattype
, &FORMAT_DvInfo
)))
1309 static HRESULT WINAPI
AviMuxIn_Receive(struct strmbase_sink
*base
, IMediaSample
*pSample
)
1311 AviMux
*avimux
= impl_from_strmbase_filter(base
->pin
.filter
);
1312 AviMuxIn
*avimuxin
= CONTAINING_RECORD(base
, AviMuxIn
, pin
);
1313 REFERENCE_TIME start
, stop
;
1314 IMediaSample
*sample
;
1318 DWORD max_size
, size
;
1322 TRACE("pin %p, pSample %p.\n", avimuxin
, pSample
);
1324 hr
= IMediaSample_QueryInterface(pSample
, &IID_IMediaSample2
, (void**)&ms2
);
1326 AM_SAMPLE2_PROPERTIES props
;
1328 memset(&props
, 0, sizeof(props
));
1329 hr
= IMediaSample2_GetProperties(ms2
, sizeof(props
), (BYTE
*)&props
);
1330 IMediaSample2_Release(ms2
);
1334 flags
= props
.dwSampleFlags
;
1335 frame
= props
.pbBuffer
;
1336 size
= props
.lActual
;
1338 flags
= IMediaSample_IsSyncPoint(pSample
) == S_OK
? AM_SAMPLE_SPLICEPOINT
: 0;
1339 hr
= IMediaSample_GetPointer(pSample
, &frame
);
1342 size
= IMediaSample_GetActualDataLength(pSample
);
1345 if(!avimuxin
->pin
.pin
.mt
.bTemporalCompression
)
1346 flags
|= AM_SAMPLE_SPLICEPOINT
;
1348 hr
= IMediaSample_GetTime(pSample
, &start
, &stop
);
1352 if(avimuxin
->stop
>stop
)
1353 return VFW_E_START_TIME_AFTER_END
;
1355 if(avimux
->start
== -1)
1356 avimux
->start
= start
;
1357 if(avimux
->stop
< stop
)
1358 avimux
->stop
= stop
;
1360 if(avimux
->avih
.dwSuggestedBufferSize
< ALIGN(size
)+sizeof(RIFFCHUNK
))
1361 avimux
->avih
.dwSuggestedBufferSize
= ALIGN(size
) + sizeof(RIFFCHUNK
);
1362 if(avimuxin
->strh
.dwSuggestedBufferSize
< ALIGN(size
)+sizeof(RIFFCHUNK
))
1363 avimuxin
->strh
.dwSuggestedBufferSize
= ALIGN(size
) + sizeof(RIFFCHUNK
);
1366 if(avimuxin
->stop
!=-1 && start
> avimuxin
->stop
) {
1367 frames_no
+= (double)(start
- avimuxin
->stop
) / 10000000
1368 * avimuxin
->strh
.dwRate
/ avimuxin
->strh
.dwScale
+ 0.5;
1370 avimuxin
->stop
= stop
;
1372 while(--frames_no
) {
1373 /* TODO: store all control frames in one buffer */
1374 hr
= IMemAllocator_GetBuffer(avimuxin
->samples_allocator
, &sample
, NULL
, NULL
, 0);
1377 hr
= IMediaSample_SetActualDataLength(sample
, 0);
1379 hr
= IMediaSample_SetDiscontinuity(sample
, TRUE
);
1381 hr
= IMediaSample_SetSyncPoint(sample
, FALSE
);
1383 hr
= queue_sample(avimux
, avimuxin
, sample
);
1384 IMediaSample_Release(sample
);
1389 hr
= IMemAllocator_GetBuffer(avimuxin
->samples_allocator
, &sample
, NULL
, NULL
, 0);
1392 max_size
= IMediaSample_GetSize(sample
);
1395 hr
= IMediaSample_SetActualDataLength(sample
, size
);
1397 hr
= IMediaSample_SetDiscontinuity(sample
, FALSE
);
1399 hr
= IMediaSample_SetSyncPoint(sample
, flags
& AM_SAMPLE_SPLICEPOINT
);
1400 /* TODO: avoid unnecessary copying */
1402 hr
= IMediaSample_GetPointer(sample
, &buf
);
1404 memcpy(buf
, frame
, size
);
1405 hr
= queue_sample(avimux
, avimuxin
, sample
);
1407 IMediaSample_Release(sample
);
1412 static HRESULT
avi_mux_sink_connect(struct strmbase_sink
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*pmt
)
1414 AviMuxIn
*avimuxin
= impl_sink_from_strmbase_pin(&iface
->pin
);
1415 AviMux
*This
= impl_from_strmbase_filter(iface
->pin
.filter
);
1421 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
) &&
1422 IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
)) {
1423 ALLOCATOR_PROPERTIES req
, act
;
1424 VIDEOINFOHEADER
*vih
;
1427 vih
= (VIDEOINFOHEADER
*)pmt
->pbFormat
;
1428 avimuxin
->strh
.fcc
= ckidSTREAMHEADER
;
1429 avimuxin
->strh
.cb
= sizeof(AVISTREAMHEADER
) - FIELD_OFFSET(AVISTREAMHEADER
, fccType
);
1430 avimuxin
->strh
.fccType
= streamtypeVIDEO
;
1431 /* FIXME: fccHandler should be set differently */
1432 avimuxin
->strh
.fccHandler
= vih
->bmiHeader
.biCompression
?
1433 vih
->bmiHeader
.biCompression
: FCC('D','I','B',' ');
1434 avimuxin
->avg_time_per_frame
= vih
->AvgTimePerFrame
;
1435 avimuxin
->stop
= -1;
1438 req
.cbBuffer
= vih
->bmiHeader
.biSizeImage
;
1440 req
.cbPrefix
= sizeof(void*);
1441 hr
= IMemAllocator_SetProperties(avimuxin
->samples_allocator
, &req
, &act
);
1443 hr
= IMemAllocator_Commit(avimuxin
->samples_allocator
);
1447 size
= pmt
->cbFormat
- FIELD_OFFSET(VIDEOINFOHEADER
, bmiHeader
);
1448 avimuxin
->strf
= CoTaskMemAlloc(sizeof(RIFFCHUNK
) + ALIGN(FIELD_OFFSET(BITMAPINFO
, bmiColors
[vih
->bmiHeader
.biClrUsed
])));
1449 avimuxin
->strf
->fcc
= ckidSTREAMFORMAT
;
1450 avimuxin
->strf
->cb
= FIELD_OFFSET(BITMAPINFO
, bmiColors
[vih
->bmiHeader
.biClrUsed
]);
1451 if(size
> avimuxin
->strf
->cb
)
1452 size
= avimuxin
->strf
->cb
;
1453 memcpy(avimuxin
->strf
->data
, &vih
->bmiHeader
, size
);
1455 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt
->majortype
),
1456 debugstr_guid(&pmt
->formattype
));
1460 return create_input_pin(This
);
1463 static void avi_mux_sink_disconnect(struct strmbase_sink
*iface
)
1465 AviMuxIn
*avimuxin
= impl_sink_from_strmbase_pin(&iface
->pin
);
1466 IMediaSample
**prev
, *cur
;
1468 IMemAllocator_Decommit(avimuxin
->samples_allocator
);
1469 while(avimuxin
->samples_head
) {
1470 cur
= avimuxin
->samples_head
;
1471 if (FAILED(IMediaSample_GetPointer(cur
, (BYTE
**)&prev
)))
1475 cur
= avimuxin
->samples_head
;
1476 avimuxin
->samples_head
= *prev
;
1477 IMediaSample_Release(cur
);
1479 if(cur
== avimuxin
->samples_head
)
1480 avimuxin
->samples_head
= NULL
;
1482 CoTaskMemFree(avimuxin
->strf
);
1483 avimuxin
->strf
= NULL
;
1486 static const struct strmbase_sink_ops sink_ops
=
1488 .base
.pin_query_interface
= sink_query_interface
,
1489 .base
.pin_query_accept
= sink_query_accept
,
1490 .base
.pin_get_media_type
= strmbase_pin_get_media_type
,
1491 .pfnReceive
= AviMuxIn_Receive
,
1492 .sink_connect
= avi_mux_sink_connect
,
1493 .sink_disconnect
= avi_mux_sink_disconnect
,
1496 static inline AviMux
* impl_from_in_IPin(IPin
*iface
)
1498 struct strmbase_pin
*pin
= CONTAINING_RECORD(iface
, struct strmbase_pin
, IPin_iface
);
1499 return impl_from_strmbase_filter(pin
->filter
);
1502 static inline AviMuxIn
* AviMuxIn_from_IAMStreamControl(IAMStreamControl
*iface
)
1504 return CONTAINING_RECORD(iface
, AviMuxIn
, IAMStreamControl_iface
);
1507 static HRESULT WINAPI
AviMuxIn_AMStreamControl_QueryInterface(
1508 IAMStreamControl
*iface
, REFIID riid
, void **ppv
)
1510 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1511 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1514 static ULONG WINAPI
AviMuxIn_AMStreamControl_AddRef(IAMStreamControl
*iface
)
1516 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1517 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1518 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1521 static ULONG WINAPI
AviMuxIn_AMStreamControl_Release(IAMStreamControl
*iface
)
1523 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1524 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1525 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1528 static HRESULT WINAPI
AviMuxIn_AMStreamControl_StartAt(IAMStreamControl
*iface
,
1529 const REFERENCE_TIME
*start
, DWORD cookie
)
1531 FIXME("iface %p, start %p, cookie %#x, stub!\n", iface
, start
, cookie
);
1535 static HRESULT WINAPI
AviMuxIn_AMStreamControl_StopAt(IAMStreamControl
*iface
,
1536 const REFERENCE_TIME
*stop
, BOOL send_extra
, DWORD cookie
)
1538 FIXME("iface %p, stop %p, send_extra %d, cookie %#x, stub!\n", iface
, stop
, send_extra
, cookie
);
1542 static HRESULT WINAPI
AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl
*iface
,
1543 AM_STREAM_INFO
*info
)
1545 FIXME("iface %p, info %p, stub!\n", iface
, info
);
1549 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl
= {
1550 AviMuxIn_AMStreamControl_QueryInterface
,
1551 AviMuxIn_AMStreamControl_AddRef
,
1552 AviMuxIn_AMStreamControl_Release
,
1553 AviMuxIn_AMStreamControl_StartAt
,
1554 AviMuxIn_AMStreamControl_StopAt
,
1555 AviMuxIn_AMStreamControl_GetInfo
1558 static inline AviMuxIn
* AviMuxIn_from_IMemInputPin(IMemInputPin
*iface
)
1560 return CONTAINING_RECORD(iface
, AviMuxIn
, pin
.IMemInputPin_iface
);
1563 static HRESULT WINAPI
AviMuxIn_MemInputPin_QueryInterface(
1564 IMemInputPin
*iface
, REFIID riid
, void **ppv
)
1566 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1567 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1570 static ULONG WINAPI
AviMuxIn_MemInputPin_AddRef(IMemInputPin
*iface
)
1572 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1573 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1574 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1577 static ULONG WINAPI
AviMuxIn_MemInputPin_Release(IMemInputPin
*iface
)
1579 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1580 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1581 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1584 static HRESULT WINAPI
AviMuxIn_MemInputPin_GetAllocator(
1585 IMemInputPin
*iface
, IMemAllocator
**ppAllocator
)
1587 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1589 TRACE("pin %p, ppAllocator %p.\n", avimuxin
, ppAllocator
);
1594 IMemAllocator_AddRef(avimuxin
->pin
.pAllocator
);
1595 *ppAllocator
= avimuxin
->pin
.pAllocator
;
1599 static HRESULT WINAPI
AviMuxIn_MemInputPin_NotifyAllocator(
1600 IMemInputPin
*iface
, IMemAllocator
*pAllocator
, BOOL bReadOnly
)
1602 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1603 ALLOCATOR_PROPERTIES props
;
1606 TRACE("pin %p, pAllocator %p, bReadOnly %d.\n", avimuxin
, pAllocator
, bReadOnly
);
1611 memset(&props
, 0, sizeof(props
));
1612 hr
= IMemAllocator_GetProperties(pAllocator
, &props
);
1618 return IMemAllocator_SetProperties(avimuxin
->pin
.pAllocator
, &props
, &props
);
1621 static HRESULT WINAPI
AviMuxIn_MemInputPin_GetAllocatorRequirements(
1622 IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*pProps
)
1624 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1626 TRACE("pin %p, pProps %p.\n", avimuxin
, pProps
);
1631 pProps
->cbAlign
= 1;
1632 pProps
->cbPrefix
= 8;
1636 static HRESULT WINAPI
AviMuxIn_MemInputPin_Receive(
1637 IMemInputPin
*iface
, IMediaSample
*pSample
)
1639 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1641 TRACE("pin %p, pSample %p.\n", avimuxin
, pSample
);
1643 return avimuxin
->pin
.pFuncsTable
->pfnReceive(&avimuxin
->pin
, pSample
);
1646 static HRESULT WINAPI
AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin
*iface
,
1647 IMediaSample
**pSamples
, LONG nSamples
, LONG
*nSamplesProcessed
)
1649 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1652 TRACE("pin %p, pSamples %p, nSamples %d, nSamplesProcessed %p.\n",
1653 avimuxin
, pSamples
, nSamples
, nSamplesProcessed
);
1655 for(*nSamplesProcessed
=0; *nSamplesProcessed
<nSamples
; (*nSamplesProcessed
)++)
1657 hr
= avimuxin
->pin
.pFuncsTable
->pfnReceive(&avimuxin
->pin
, pSamples
[*nSamplesProcessed
]);
1665 static HRESULT WINAPI
AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
1667 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1668 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1671 TRACE("avimuxin %p.\n", avimuxin
);
1673 if(!This
->source
.pMemInputPin
)
1676 hr
= IMemInputPin_ReceiveCanBlock(This
->source
.pMemInputPin
);
1677 return hr
!= S_FALSE
? S_OK
: S_FALSE
;
1680 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl
= {
1681 AviMuxIn_MemInputPin_QueryInterface
,
1682 AviMuxIn_MemInputPin_AddRef
,
1683 AviMuxIn_MemInputPin_Release
,
1684 AviMuxIn_MemInputPin_GetAllocator
,
1685 AviMuxIn_MemInputPin_NotifyAllocator
,
1686 AviMuxIn_MemInputPin_GetAllocatorRequirements
,
1687 AviMuxIn_MemInputPin_Receive
,
1688 AviMuxIn_MemInputPin_ReceiveMultiple
,
1689 AviMuxIn_MemInputPin_ReceiveCanBlock
1692 static inline AviMuxIn
* AviMuxIn_from_IPropertyBag(IPropertyBag
*iface
)
1694 return CONTAINING_RECORD(iface
, AviMuxIn
, IPropertyBag_iface
);
1697 static HRESULT WINAPI
AviMuxIn_PropertyBag_QueryInterface(
1698 IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1700 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1701 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1704 static ULONG WINAPI
AviMuxIn_PropertyBag_AddRef(IPropertyBag
*iface
)
1706 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1707 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1708 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1711 static ULONG WINAPI
AviMuxIn_PropertyBag_Release(IPropertyBag
*iface
)
1713 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1714 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1715 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1718 static HRESULT WINAPI
AviMuxIn_PropertyBag_Read(IPropertyBag
*iface
,
1719 const WCHAR
*name
, VARIANT
*value
, IErrorLog
*error_log
)
1721 FIXME("iface %p, name %s, value %p, error_log %p, stub!\n",
1722 iface
, debugstr_w(name
), value
, error_log
);
1726 static HRESULT WINAPI
AviMuxIn_PropertyBag_Write(IPropertyBag
*iface
,
1727 const WCHAR
*name
, VARIANT
*value
)
1729 FIXME("iface %p, name %s, value %s, stub!\n",
1730 iface
, debugstr_w(name
), debugstr_variant(value
));
1734 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl
= {
1735 AviMuxIn_PropertyBag_QueryInterface
,
1736 AviMuxIn_PropertyBag_AddRef
,
1737 AviMuxIn_PropertyBag_Release
,
1738 AviMuxIn_PropertyBag_Read
,
1739 AviMuxIn_PropertyBag_Write
1742 static inline AviMuxIn
* AviMuxIn_from_IQualityControl(IQualityControl
*iface
)
1744 return CONTAINING_RECORD(iface
, AviMuxIn
, IQualityControl_iface
);
1747 static HRESULT WINAPI
AviMuxIn_QualityControl_QueryInterface(
1748 IQualityControl
*iface
, REFIID riid
, void **ppv
)
1750 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1751 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1754 static ULONG WINAPI
AviMuxIn_QualityControl_AddRef(IQualityControl
*iface
)
1756 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1757 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1758 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1761 static ULONG WINAPI
AviMuxIn_QualityControl_Release(IQualityControl
*iface
)
1763 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1764 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1765 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1768 static HRESULT WINAPI
AviMuxIn_QualityControl_Notify(IQualityControl
*iface
,
1769 IBaseFilter
*filter
, Quality q
)
1771 FIXME("iface %p, filter %p, type %u, proportion %d, late %s, timestamp %s, stub!\n",
1772 iface
, filter
, q
.Type
, q
.Proportion
, wine_dbgstr_longlong(q
.Late
),
1773 wine_dbgstr_longlong(q
.TimeStamp
));
1777 static HRESULT WINAPI
AviMuxIn_QualityControl_SetSink(IQualityControl
*iface
, IQualityControl
*sink
)
1779 FIXME("iface %p, sink %p, stub!\n", iface
, sink
);
1783 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl
= {
1784 AviMuxIn_QualityControl_QueryInterface
,
1785 AviMuxIn_QualityControl_AddRef
,
1786 AviMuxIn_QualityControl_Release
,
1787 AviMuxIn_QualityControl_Notify
,
1788 AviMuxIn_QualityControl_SetSink
1791 static HRESULT
create_input_pin(AviMux
*avimux
)
1793 WCHAR name
[] = {'I','n','p','u','t',' ','0','0',0};
1797 if(avimux
->input_pin_no
>= MAX_PIN_NO
-1)
1800 name
[7] = '0' + (avimux
->input_pin_no
+1) % 10;
1801 name
[6] = '0' + (avimux
->input_pin_no
+1) / 10;
1803 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1804 return E_OUTOFMEMORY
;
1806 strmbase_sink_init(&object
->pin
, &avimux
->filter
, name
, &sink_ops
, NULL
);
1807 object
->pin
.IMemInputPin_iface
.lpVtbl
= &AviMuxIn_MemInputPinVtbl
;
1808 object
->IAMStreamControl_iface
.lpVtbl
= &AviMuxIn_AMStreamControlVtbl
;
1809 object
->IPropertyBag_iface
.lpVtbl
= &AviMuxIn_PropertyBagVtbl
;
1810 object
->IQualityControl_iface
.lpVtbl
= &AviMuxIn_QualityControlVtbl
;
1812 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1813 &IID_IMemAllocator
, (void **)&object
->samples_allocator
);
1816 strmbase_sink_cleanup(&object
->pin
);
1821 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1822 &IID_IMemAllocator
, (void **)&object
->pin
.pAllocator
);
1825 IMemAllocator_Release(object
->samples_allocator
);
1826 strmbase_sink_cleanup(&object
->pin
);
1831 object
->indx
= (AVISUPERINDEX
*)&object
->indx_data
;
1832 object
->ix
= (AVISTDINDEX
*)object
->ix_data
;
1834 avimux
->in
[avimux
->input_pin_no
++] = object
;
1838 IUnknown
* WINAPI
QCAP_createAVIMux(IUnknown
*outer
, HRESULT
*phr
)
1840 static const WCHAR output_name
[] = {'A','V','I',' ','O','u','t',0};
1846 avimux
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AviMux
));
1848 *phr
= E_OUTOFMEMORY
;
1852 strmbase_filter_init(&avimux
->filter
, outer
, &CLSID_AviDest
, &filter_ops
);
1853 avimux
->IConfigAviMux_iface
.lpVtbl
= &ConfigAviMuxVtbl
;
1854 avimux
->IConfigInterleaving_iface
.lpVtbl
= &ConfigInterleavingVtbl
;
1855 avimux
->IMediaSeeking_iface
.lpVtbl
= &MediaSeekingVtbl
;
1856 avimux
->IPersistMediaPropertyBag_iface
.lpVtbl
= &PersistMediaPropertyBagVtbl
;
1857 avimux
->ISpecifyPropertyPages_iface
.lpVtbl
= &SpecifyPropertyPagesVtbl
;
1859 info
.dir
= PINDIR_OUTPUT
;
1860 info
.pFilter
= &avimux
->filter
.IBaseFilter_iface
;
1861 lstrcpyW(info
.achName
, output_name
);
1862 strmbase_source_init(&avimux
->source
, &avimux
->filter
, output_name
, &source_ops
);
1863 avimux
->IQualityControl_iface
.lpVtbl
= &AviMuxOut_QualityControlVtbl
;
1864 avimux
->cur_stream
= 0;
1865 avimux
->cur_time
= 0;
1866 avimux
->stream
= NULL
;
1868 hr
= create_input_pin(avimux
);
1870 strmbase_source_cleanup(&avimux
->source
);
1871 strmbase_filter_cleanup(&avimux
->filter
);
1872 HeapFree(GetProcessHeap(), 0, avimux
);
1877 avimux
->interleave
= 10000000;
1879 ObjectRefCount(TRUE
);
1881 return &avimux
->filter
.IUnknown_inner
;