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
);
128 heap_free(filter
->in
[i
]);
131 heap_free(filter
->idx1
);
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
= HeapReAlloc(GetProcessHeap(), 0, avimux
->idx1
,
229 sizeof(*avimux
->idx1
)*2*avimux
->idx1_size
);
231 return E_OUTOFMEMORY
;
233 avimux
->idx1_size
*= 2;
234 avimux
->idx1
= new_idx
;
237 avimux
->idx1
[avimux
->idx1_entries
].ckid
= ckid
;
238 avimux
->idx1
[avimux
->idx1_entries
].dwFlags
= flags
;
239 avimux
->idx1
[avimux
->idx1_entries
].dwChunkOffset
= off
;
240 avimux
->idx1
[avimux
->idx1_entries
].dwChunkLength
= len
;
241 avimux
->idx1_entries
++;
245 static HRESULT
flush_queue(AviMux
*avimux
, AviMuxIn
*avimuxin
, BOOL closing
)
247 IMediaSample
*sample
, **prev
, **head_prev
;
254 if (avimux
->cur_stream
!= avimuxin
->stream_id
)
257 while(avimuxin
->samples_head
) {
258 hr
= IMediaSample_GetPointer(avimuxin
->samples_head
, (BYTE
**)&head_prev
);
263 hr
= IMediaSample_GetPointer(*head_prev
, (BYTE
**)&prev
);
269 size
= IMediaSample_GetActualDataLength(sample
);
270 hr
= IMediaSample_GetPointer(sample
, &data
);
273 flags
= IMediaSample_IsDiscontinuity(sample
)==S_OK
? AM_SAMPLE_TIMEDISCONTINUITY
: 0;
274 if(IMediaSample_IsSyncPoint(sample
) == S_OK
)
275 flags
|= AM_SAMPLE_SPLICEPOINT
;
277 if (avimuxin
->stream_time
+ (closing
? 0 : avimuxin
->strh
.dwScale
) > avimux
->cur_time
278 && !(flags
& AM_SAMPLE_TIMEDISCONTINUITY
))
283 avimux
->cur_stream
++;
284 if(avimux
->cur_stream
>= avimux
->input_pin_no
-1) {
285 avimux
->cur_time
+= avimux
->interleave
;
286 avimux
->cur_stream
= 0;
288 avimuxin
= avimux
->in
[avimux
->cur_stream
];
292 if(avimuxin
->ix
->nEntriesInUse
== AVISTDINDEX_ENTRIES
) {
293 /* TODO: use output pins Deliver/Receive method */
294 hr
= out_seek(avimux
, avimuxin
->ix_off
);
297 hr
= out_write(avimux
, avimuxin
->ix
, sizeof(avimuxin
->ix_data
));
301 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].qwOffset
= avimuxin
->ix_off
;
302 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].dwSize
= sizeof(avimuxin
->ix_data
);
303 avimuxin
->indx
->aIndex
[avimuxin
->indx
->nEntriesInUse
].dwDuration
= AVISTDINDEX_ENTRIES
;
304 avimuxin
->indx
->nEntriesInUse
++;
306 memset(avimuxin
->ix
->aIndex
, 0, sizeof(avimuxin
->ix
->aIndex
)*avimuxin
->ix
->nEntriesInUse
);
307 avimuxin
->ix
->nEntriesInUse
= 0;
308 avimuxin
->ix
->qwBaseOffset
= 0;
310 avimuxin
->ix_off
= avimux
->size
;
311 avimux
->size
+= sizeof(avimuxin
->ix_data
);
314 if(*head_prev
== avimuxin
->samples_head
)
315 avimuxin
->samples_head
= NULL
;
319 avimuxin
->stream_time
+= avimuxin
->strh
.dwScale
;
320 avimuxin
->strh
.dwLength
++;
321 if(!(flags
& AM_SAMPLE_TIMEDISCONTINUITY
)) {
322 if(!avimuxin
->ix
->qwBaseOffset
)
323 avimuxin
->ix
->qwBaseOffset
= avimux
->size
;
324 avimuxin
->ix
->aIndex
[avimuxin
->ix
->nEntriesInUse
].dwOffset
=
325 avimux
->size
+ sizeof(RIFFCHUNK
) - avimuxin
->ix
->qwBaseOffset
;
327 hr
= out_seek(avimux
, avimux
->size
);
329 IMediaSample_Release(sample
);
333 avimuxin
->ix
->aIndex
[avimuxin
->ix
->nEntriesInUse
].dwSize
= size
|
334 (flags
& AM_SAMPLE_SPLICEPOINT
? 0 : AVISTDINDEX_DELTAFRAME
);
335 avimuxin
->ix
->nEntriesInUse
++;
337 rf
.fcc
= FCC('0'+avimuxin
->stream_id
/10, '0'+avimuxin
->stream_id
%10,
338 'd', flags
& AM_SAMPLE_SPLICEPOINT
? 'b' : 'c');
340 hr
= idx1_add_entry(avimux
, rf
.fcc
, flags
& AM_SAMPLE_SPLICEPOINT
? AVIIF_KEYFRAME
: 0,
341 flags
& AM_SAMPLE_TIMEDISCONTINUITY
?
342 avimux
->idx1
[avimux
->idx1_entries
-1].dwChunkOffset
: avimux
->size
, size
);
344 IMediaSample_Release(sample
);
348 if(!(flags
& AM_SAMPLE_TIMEDISCONTINUITY
)) {
349 hr
= out_write(avimux
, &rf
, sizeof(rf
));
351 IMediaSample_Release(sample
);
354 hr
= out_write(avimux
, data
, size
);
356 IMediaSample_Release(sample
);
360 hr
= out_write(avimux
, &flags
, ALIGN(rf
.cb
)-rf
.cb
);
362 IMediaSample_Release(sample
);
366 IMediaSample_Release(sample
);
371 static HRESULT
queue_sample(AviMux
*avimux
, AviMuxIn
*avimuxin
, IMediaSample
*sample
)
373 IMediaSample
**prev
, **head_prev
;
376 hr
= IMediaSample_GetPointer(sample
, (BYTE
**)&prev
);
381 if(avimuxin
->samples_head
) {
382 hr
= IMediaSample_GetPointer(avimuxin
->samples_head
, (BYTE
**)&head_prev
);
392 avimuxin
->samples_head
= sample
;
393 IMediaSample_AddRef(sample
);
395 return flush_queue(avimux
, avimuxin
, FALSE
);
398 static HRESULT
avi_mux_cleanup_stream(struct strmbase_filter
*iface
)
400 AviMux
*This
= impl_from_strmbase_filter(iface
);
409 int idx1_off
, empty_stream
;
411 empty_stream
= This
->cur_stream
;
412 for(i
=empty_stream
+1; ; i
++) {
413 if(i
>= This
->input_pin_no
-1)
415 if(i
== empty_stream
)
418 This
->cur_stream
= i
;
419 hr
= flush_queue(This
, This
->in
[This
->cur_stream
], TRUE
);
424 idx1_off
= This
->size
;
425 rc
.fcc
= ckidAVIOLDINDEX
;
426 rc
.cb
= This
->idx1_entries
* sizeof(*This
->idx1
);
427 hr
= out_write(This
, &rc
, sizeof(rc
));
430 hr
= out_write(This
, This
->idx1
, This
->idx1_entries
* sizeof(*This
->idx1
));
433 /* native writes 8 '\0' characters after the end of RIFF data */
435 hr
= out_write(This
, &i
, sizeof(i
));
438 hr
= out_write(This
, &i
, sizeof(i
));
442 for(i
=0; i
<This
->input_pin_no
; i
++) {
443 if(!This
->in
[i
]->pin
.pin
.peer
)
446 hr
= out_seek(This
, This
->in
[i
]->ix_off
);
450 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].qwOffset
= This
->in
[i
]->ix_off
;
451 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwSize
= sizeof(This
->in
[i
]->ix_data
);
452 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwDuration
= This
->in
[i
]->strh
.dwLength
;
453 if(This
->in
[i
]->indx
->nEntriesInUse
) {
454 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
].dwDuration
-=
455 This
->in
[i
]->indx
->aIndex
[This
->in
[i
]->indx
->nEntriesInUse
-1].dwDuration
;
457 This
->in
[i
]->indx
->nEntriesInUse
++;
458 hr
= out_write(This
, This
->in
[i
]->ix
, sizeof(This
->in
[i
]->ix_data
));
463 hr
= out_seek(This
, 0);
467 rl
.fcc
= FCC('R','I','F','F');
468 rl
.cb
= This
->size
- sizeof(RIFFCHUNK
) - 2 * sizeof(int);
469 rl
.fccListType
= FCC('A','V','I',' ');
470 hr
= out_write(This
, &rl
, sizeof(rl
));
474 rl
.fcc
= FCC('L','I','S','T');
475 rl
.cb
= This
->movi_off
- sizeof(RIFFLIST
) - sizeof(RIFFCHUNK
);
476 rl
.fccListType
= FCC('h','d','r','l');
477 hr
= out_write(This
, &rl
, sizeof(rl
));
481 /* FIXME: set This->avih.dwMaxBytesPerSec value */
482 This
->avih
.dwTotalFrames
= (This
->stop
-This
->start
) / 10 / This
->avih
.dwMicroSecPerFrame
;
483 hr
= out_write(This
, &This
->avih
, sizeof(This
->avih
));
487 for(i
=0; i
<This
->input_pin_no
; i
++) {
488 if(!This
->in
[i
]->pin
.pin
.peer
)
491 rl
.cb
= sizeof(FOURCC
) + sizeof(AVISTREAMHEADER
) + sizeof(RIFFCHUNK
) +
492 This
->in
[i
]->strf
->cb
+ sizeof(This
->in
[i
]->indx_data
);
493 rl
.fccListType
= ckidSTREAMLIST
;
494 hr
= out_write(This
, &rl
, sizeof(rl
));
498 hr
= out_write(This
, &This
->in
[i
]->strh
, sizeof(AVISTREAMHEADER
));
502 hr
= out_write(This
, This
->in
[i
]->strf
, sizeof(RIFFCHUNK
) + This
->in
[i
]->strf
->cb
);
506 hr
= out_write(This
, This
->in
[i
]->indx
, sizeof(This
->in
[i
]->indx_data
));
511 rl
.cb
= sizeof(dmlh
) + sizeof(FOURCC
);
512 rl
.fccListType
= ckidODML
;
513 hr
= out_write(This
, &rl
, sizeof(rl
));
517 memset(&dmlh
, 0, sizeof(dmlh
));
518 dmlh
.fcc
= ckidAVIEXTHEADER
;
519 dmlh
.cb
= sizeof(dmlh
) - sizeof(RIFFCHUNK
);
520 dmlh
.dwGrandFrames
= This
->in
[0]->strh
.dwLength
;
521 hr
= out_write(This
, &dmlh
, sizeof(dmlh
));
523 rl
.cb
= idx1_off
- This
->movi_off
- sizeof(RIFFCHUNK
);
524 rl
.fccListType
= FCC('m','o','v','i');
525 out_write(This
, &rl
, sizeof(rl
));
528 IStream_Release(This
->stream
);
535 static HRESULT
avi_mux_init_stream(struct strmbase_filter
*iface
)
537 AviMux
*This
= impl_from_strmbase_filter(iface
);
541 if(This
->mode
!= INTERLEAVE_FULL
) {
542 FIXME("mode not supported (%d)\n", This
->mode
);
546 for(i
=0; i
<This
->input_pin_no
; i
++) {
550 if(!This
->in
[i
]->pin
.pin
.peer
)
553 hr
= IPin_QueryInterface(This
->in
[i
]->pin
.pin
.peer
,
554 &IID_IMediaSeeking
, (void**)&ms
);
558 hr
= IMediaSeeking_GetPositions(ms
, &cur
, &stop
);
560 IMediaSeeking_Release(ms
);
564 FIXME("Use IMediaSeeking to fill stream header\n");
565 IMediaSeeking_Release(ms
);
568 if (This
->source
.pMemInputPin
)
570 hr
= IMemInputPin_QueryInterface(This
->source
.pMemInputPin
,
571 &IID_IStream
, (void **)&This
->stream
);
576 This
->idx1_entries
= 0;
577 if(!This
->idx1_size
) {
578 This
->idx1_size
= 1024;
579 This
->idx1
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->idx1
)*This
->idx1_size
);
581 return E_OUTOFMEMORY
;
584 This
->size
= 3*sizeof(RIFFLIST
) + sizeof(AVIMAINHEADER
) + sizeof(AVIEXTHEADER
);
587 memset(&This
->avih
, 0, sizeof(This
->avih
));
588 for(i
=0; i
<This
->input_pin_no
; i
++) {
589 if(!This
->in
[i
]->pin
.pin
.peer
)
592 This
->avih
.dwStreams
++;
593 This
->size
+= sizeof(RIFFLIST
) + sizeof(AVISTREAMHEADER
) + sizeof(RIFFCHUNK
)
594 + This
->in
[i
]->strf
->cb
+ sizeof(This
->in
[i
]->indx_data
);
596 This
->in
[i
]->strh
.dwScale
= MulDiv(This
->in
[i
]->avg_time_per_frame
, This
->interleave
, 10000000);
597 This
->in
[i
]->strh
.dwRate
= This
->interleave
;
599 hr
= IMemAllocator_Commit(This
->in
[i
]->pin
.pAllocator
);
603 IStream_Release(This
->stream
);
610 This
->movi_off
= This
->size
;
611 This
->size
+= sizeof(RIFFLIST
);
613 idx1_add_entry(This
, FCC('7','F','x','x'), 0, This
->movi_off
+ sizeof(RIFFLIST
), 0);
616 for(i
=0; i
<This
->input_pin_no
; i
++) {
617 if(!This
->in
[i
]->pin
.pin
.peer
)
620 This
->in
[i
]->ix_off
= This
->size
;
621 This
->size
+= sizeof(This
->in
[i
]->ix_data
);
622 This
->in
[i
]->ix
->fcc
= FCC('i','x','0'+stream_id
/10,'0'+stream_id
%10);
623 This
->in
[i
]->ix
->cb
= sizeof(This
->in
[i
]->ix_data
) - sizeof(RIFFCHUNK
);
624 This
->in
[i
]->ix
->wLongsPerEntry
= 2;
625 This
->in
[i
]->ix
->bIndexSubType
= 0;
626 This
->in
[i
]->ix
->bIndexType
= AVI_INDEX_OF_CHUNKS
;
627 This
->in
[i
]->ix
->dwChunkId
= FCC('0'+stream_id
/10,'0'+stream_id
%10,'d','b');
628 This
->in
[i
]->ix
->qwBaseOffset
= 0;
630 This
->in
[i
]->indx
->fcc
= ckidAVISUPERINDEX
;
631 This
->in
[i
]->indx
->cb
= sizeof(This
->in
[i
]->indx_data
) - sizeof(RIFFCHUNK
);
632 This
->in
[i
]->indx
->wLongsPerEntry
= 4;
633 This
->in
[i
]->indx
->bIndexSubType
= 0;
634 This
->in
[i
]->indx
->bIndexType
= AVI_INDEX_OF_INDEXES
;
635 This
->in
[i
]->indx
->dwChunkId
= This
->in
[i
]->ix
->dwChunkId
;
636 This
->in
[i
]->stream_id
= stream_id
++;
642 This
->avih
.fcc
= ckidMAINAVIHEADER
;
643 This
->avih
.cb
= sizeof(AVIMAINHEADER
) - sizeof(RIFFCHUNK
);
644 /* TODO: Use first video stream */
645 This
->avih
.dwMicroSecPerFrame
= This
->in
[0]->avg_time_per_frame
/10;
646 This
->avih
.dwPaddingGranularity
= 1;
647 This
->avih
.dwFlags
= AVIF_TRUSTCKTYPE
| AVIF_HASINDEX
;
648 This
->avih
.dwWidth
= ((BITMAPINFOHEADER
*)This
->in
[0]->strf
->data
)->biWidth
;
649 This
->avih
.dwHeight
= ((BITMAPINFOHEADER
*)This
->in
[0]->strf
->data
)->biHeight
;
654 static const struct strmbase_filter_ops filter_ops
=
656 .filter_get_pin
= avi_mux_get_pin
,
657 .filter_destroy
= avi_mux_destroy
,
658 .filter_query_interface
= avi_mux_query_interface
,
659 .filter_init_stream
= avi_mux_init_stream
,
660 .filter_cleanup_stream
= avi_mux_cleanup_stream
,
663 static inline AviMux
* impl_from_IConfigAviMux(IConfigAviMux
*iface
)
665 return CONTAINING_RECORD(iface
, AviMux
, IConfigAviMux_iface
);
668 static HRESULT WINAPI
ConfigAviMux_QueryInterface(
669 IConfigAviMux
*iface
, REFIID riid
, void **ppv
)
671 AviMux
*This
= impl_from_IConfigAviMux(iface
);
672 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
675 static ULONG WINAPI
ConfigAviMux_AddRef(IConfigAviMux
*iface
)
677 AviMux
*This
= impl_from_IConfigAviMux(iface
);
678 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
681 static ULONG WINAPI
ConfigAviMux_Release(IConfigAviMux
*iface
)
683 AviMux
*This
= impl_from_IConfigAviMux(iface
);
684 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
687 static HRESULT WINAPI
ConfigAviMux_SetMasterStream(IConfigAviMux
*iface
, LONG iStream
)
689 AviMux
*This
= impl_from_IConfigAviMux(iface
);
690 FIXME("(%p)->(%d)\n", This
, iStream
);
694 static HRESULT WINAPI
ConfigAviMux_GetMasterStream(IConfigAviMux
*iface
, LONG
*pStream
)
696 AviMux
*This
= impl_from_IConfigAviMux(iface
);
697 FIXME("(%p)->(%p)\n", This
, pStream
);
701 static HRESULT WINAPI
ConfigAviMux_SetOutputCompatibilityIndex(
702 IConfigAviMux
*iface
, BOOL fOldIndex
)
704 AviMux
*This
= impl_from_IConfigAviMux(iface
);
705 FIXME("(%p)->(%x)\n", This
, fOldIndex
);
709 static HRESULT WINAPI
ConfigAviMux_GetOutputCompatibilityIndex(
710 IConfigAviMux
*iface
, BOOL
*pfOldIndex
)
712 AviMux
*This
= impl_from_IConfigAviMux(iface
);
713 FIXME("(%p)->(%p)\n", This
, pfOldIndex
);
717 static const IConfigAviMuxVtbl ConfigAviMuxVtbl
= {
718 ConfigAviMux_QueryInterface
,
720 ConfigAviMux_Release
,
721 ConfigAviMux_SetMasterStream
,
722 ConfigAviMux_GetMasterStream
,
723 ConfigAviMux_SetOutputCompatibilityIndex
,
724 ConfigAviMux_GetOutputCompatibilityIndex
727 static inline AviMux
* impl_from_IConfigInterleaving(IConfigInterleaving
*iface
)
729 return CONTAINING_RECORD(iface
, AviMux
, IConfigInterleaving_iface
);
732 static HRESULT WINAPI
ConfigInterleaving_QueryInterface(
733 IConfigInterleaving
*iface
, REFIID riid
, void **ppv
)
735 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
736 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
739 static ULONG WINAPI
ConfigInterleaving_AddRef(IConfigInterleaving
*iface
)
741 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
742 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
745 static ULONG WINAPI
ConfigInterleaving_Release(IConfigInterleaving
*iface
)
747 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
748 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
751 static HRESULT WINAPI
ConfigInterleaving_put_Mode(
752 IConfigInterleaving
*iface
, InterleavingMode mode
)
754 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
756 TRACE("(%p)->(%d)\n", This
, mode
);
758 if(mode
>INTERLEAVE_NONE_BUFFERED
)
761 if(This
->mode
!= mode
) {
762 if(This
->source
.pin
.peer
) {
763 HRESULT hr
= IFilterGraph_Reconnect(This
->filter
.graph
, &This
->source
.pin
.IPin_iface
);
774 static HRESULT WINAPI
ConfigInterleaving_get_Mode(
775 IConfigInterleaving
*iface
, InterleavingMode
*pMode
)
777 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
778 FIXME("(%p)->(%p)\n", This
, pMode
);
782 static HRESULT WINAPI
ConfigInterleaving_put_Interleaving(IConfigInterleaving
*iface
,
783 const REFERENCE_TIME
*prtInterleave
, const REFERENCE_TIME
*prtPreroll
)
785 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
787 TRACE("(%p)->(%p %p)\n", This
, prtInterleave
, prtPreroll
);
790 This
->interleave
= *prtInterleave
;
792 This
->preroll
= *prtPreroll
;
796 static HRESULT WINAPI
ConfigInterleaving_get_Interleaving(IConfigInterleaving
*iface
,
797 REFERENCE_TIME
*prtInterleave
, REFERENCE_TIME
*prtPreroll
)
799 AviMux
*This
= impl_from_IConfigInterleaving(iface
);
800 FIXME("(%p)->(%p %p)\n", This
, prtInterleave
, prtPreroll
);
804 static const IConfigInterleavingVtbl ConfigInterleavingVtbl
= {
805 ConfigInterleaving_QueryInterface
,
806 ConfigInterleaving_AddRef
,
807 ConfigInterleaving_Release
,
808 ConfigInterleaving_put_Mode
,
809 ConfigInterleaving_get_Mode
,
810 ConfigInterleaving_put_Interleaving
,
811 ConfigInterleaving_get_Interleaving
814 static inline AviMux
* impl_from_IMediaSeeking(IMediaSeeking
*iface
)
816 return CONTAINING_RECORD(iface
, AviMux
, IMediaSeeking_iface
);
819 static HRESULT WINAPI
MediaSeeking_QueryInterface(
820 IMediaSeeking
*iface
, REFIID riid
, void **ppv
)
822 AviMux
*This
= impl_from_IMediaSeeking(iface
);
823 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
826 static ULONG WINAPI
MediaSeeking_AddRef(IMediaSeeking
*iface
)
828 AviMux
*This
= impl_from_IMediaSeeking(iface
);
829 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
832 static ULONG WINAPI
MediaSeeking_Release(IMediaSeeking
*iface
)
834 AviMux
*This
= impl_from_IMediaSeeking(iface
);
835 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
838 static HRESULT WINAPI
MediaSeeking_GetCapabilities(
839 IMediaSeeking
*iface
, DWORD
*pCapabilities
)
841 AviMux
*This
= impl_from_IMediaSeeking(iface
);
842 FIXME("(%p)->(%p)\n", This
, pCapabilities
);
846 static HRESULT WINAPI
MediaSeeking_CheckCapabilities(
847 IMediaSeeking
*iface
, DWORD
*pCapabilities
)
849 AviMux
*This
= impl_from_IMediaSeeking(iface
);
850 FIXME("(%p)->(%p)\n", This
, pCapabilities
);
854 static HRESULT WINAPI
MediaSeeking_IsFormatSupported(
855 IMediaSeeking
*iface
, const GUID
*pFormat
)
857 AviMux
*This
= impl_from_IMediaSeeking(iface
);
858 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
862 static HRESULT WINAPI
MediaSeeking_QueryPreferredFormat(
863 IMediaSeeking
*iface
, GUID
*pFormat
)
865 AviMux
*This
= impl_from_IMediaSeeking(iface
);
866 FIXME("(%p)->(%p)\n", This
, pFormat
);
870 static HRESULT WINAPI
MediaSeeking_GetTimeFormat(
871 IMediaSeeking
*iface
, GUID
*pFormat
)
873 AviMux
*This
= impl_from_IMediaSeeking(iface
);
874 FIXME("(%p)->(%p)\n", This
, pFormat
);
878 static HRESULT WINAPI
MediaSeeking_IsUsingTimeFormat(
879 IMediaSeeking
*iface
, const GUID
*pFormat
)
881 AviMux
*This
= impl_from_IMediaSeeking(iface
);
882 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
886 static HRESULT WINAPI
MediaSeeking_SetTimeFormat(
887 IMediaSeeking
*iface
, const GUID
*pFormat
)
889 AviMux
*This
= impl_from_IMediaSeeking(iface
);
890 FIXME("(%p)->(%s)\n", This
, debugstr_guid(pFormat
));
894 static HRESULT WINAPI
MediaSeeking_GetDuration(
895 IMediaSeeking
*iface
, LONGLONG
*pDuration
)
897 AviMux
*This
= impl_from_IMediaSeeking(iface
);
898 FIXME("(%p)->(%p)\n", This
, pDuration
);
902 static HRESULT WINAPI
MediaSeeking_GetStopPosition(
903 IMediaSeeking
*iface
, LONGLONG
*pStop
)
905 AviMux
*This
= impl_from_IMediaSeeking(iface
);
906 FIXME("(%p)->(%p)\n", This
, pStop
);
910 static HRESULT WINAPI
MediaSeeking_GetCurrentPosition(
911 IMediaSeeking
*iface
, LONGLONG
*pCurrent
)
913 AviMux
*This
= impl_from_IMediaSeeking(iface
);
914 FIXME("(%p)->(%p)\n", This
, pCurrent
);
918 static HRESULT WINAPI
MediaSeeking_ConvertTimeFormat(IMediaSeeking
*iface
, LONGLONG
*pTarget
,
919 const GUID
*pTargetFormat
, LONGLONG Source
, const GUID
*pSourceFormat
)
921 AviMux
*This
= impl_from_IMediaSeeking(iface
);
922 FIXME("(%p)->(%p %s %s %s)\n", This
, pTarget
, debugstr_guid(pTargetFormat
),
923 wine_dbgstr_longlong(Source
), debugstr_guid(pSourceFormat
));
927 static HRESULT WINAPI
MediaSeeking_SetPositions(IMediaSeeking
*iface
, LONGLONG
*pCurrent
,
928 DWORD dwCurrentFlags
, LONGLONG
*pStop
, DWORD dwStopFlags
)
930 AviMux
*This
= impl_from_IMediaSeeking(iface
);
931 FIXME("(%p)->(%p %x %p %x)\n", This
, pCurrent
, dwCurrentFlags
, pStop
, dwStopFlags
);
935 static HRESULT WINAPI
MediaSeeking_GetPositions(IMediaSeeking
*iface
,
936 LONGLONG
*pCurrent
, LONGLONG
*pStop
)
938 AviMux
*This
= impl_from_IMediaSeeking(iface
);
939 FIXME("(%p)->(%p %p)\n", This
, pCurrent
, pStop
);
943 static HRESULT WINAPI
MediaSeeking_GetAvailable(IMediaSeeking
*iface
,
944 LONGLONG
*pEarliest
, LONGLONG
*pLatest
)
946 AviMux
*This
= impl_from_IMediaSeeking(iface
);
947 FIXME("(%p)->(%p %p)\n", This
, pEarliest
, pLatest
);
951 static HRESULT WINAPI
MediaSeeking_SetRate(IMediaSeeking
*iface
, double dRate
)
953 AviMux
*This
= impl_from_IMediaSeeking(iface
);
954 FIXME("(%p)->(%lf)\n", This
, dRate
);
958 static HRESULT WINAPI
MediaSeeking_GetRate(IMediaSeeking
*iface
, double *pdRate
)
960 AviMux
*This
= impl_from_IMediaSeeking(iface
);
961 FIXME("(%p)->(%p)\n", This
, pdRate
);
965 static HRESULT WINAPI
MediaSeeking_GetPreroll(IMediaSeeking
*iface
, LONGLONG
*pllPreroll
)
967 AviMux
*This
= impl_from_IMediaSeeking(iface
);
968 FIXME("(%p)->(%p)\n", This
, pllPreroll
);
972 static const IMediaSeekingVtbl MediaSeekingVtbl
= {
973 MediaSeeking_QueryInterface
,
975 MediaSeeking_Release
,
976 MediaSeeking_GetCapabilities
,
977 MediaSeeking_CheckCapabilities
,
978 MediaSeeking_IsFormatSupported
,
979 MediaSeeking_QueryPreferredFormat
,
980 MediaSeeking_GetTimeFormat
,
981 MediaSeeking_IsUsingTimeFormat
,
982 MediaSeeking_SetTimeFormat
,
983 MediaSeeking_GetDuration
,
984 MediaSeeking_GetStopPosition
,
985 MediaSeeking_GetCurrentPosition
,
986 MediaSeeking_ConvertTimeFormat
,
987 MediaSeeking_SetPositions
,
988 MediaSeeking_GetPositions
,
989 MediaSeeking_GetAvailable
,
990 MediaSeeking_SetRate
,
991 MediaSeeking_GetRate
,
992 MediaSeeking_GetPreroll
995 static inline AviMux
* impl_from_IPersistMediaPropertyBag(IPersistMediaPropertyBag
*iface
)
997 return CONTAINING_RECORD(iface
, AviMux
, IPersistMediaPropertyBag_iface
);
1000 static HRESULT WINAPI
PersistMediaPropertyBag_QueryInterface(
1001 IPersistMediaPropertyBag
*iface
, REFIID riid
, void **ppv
)
1003 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1004 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1007 static ULONG WINAPI
PersistMediaPropertyBag_AddRef(IPersistMediaPropertyBag
*iface
)
1009 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1010 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1013 static ULONG WINAPI
PersistMediaPropertyBag_Release(IPersistMediaPropertyBag
*iface
)
1015 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1016 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1019 static HRESULT WINAPI
PersistMediaPropertyBag_GetClassID(
1020 IPersistMediaPropertyBag
*iface
, CLSID
*pClassID
)
1022 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1023 return IBaseFilter_GetClassID(&This
->filter
.IBaseFilter_iface
, pClassID
);
1026 static HRESULT WINAPI
PersistMediaPropertyBag_InitNew(IPersistMediaPropertyBag
*iface
)
1028 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1029 FIXME("(%p)->()\n", This
);
1033 static HRESULT WINAPI
PersistMediaPropertyBag_Load(IPersistMediaPropertyBag
*iface
,
1034 IMediaPropertyBag
*pPropBag
, IErrorLog
*pErrorLog
)
1036 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1037 FIXME("(%p)->()\n", This
);
1041 static HRESULT WINAPI
PersistMediaPropertyBag_Save(IPersistMediaPropertyBag
*iface
,
1042 IMediaPropertyBag
*pPropBag
, BOOL fClearDirty
, BOOL fSaveAllProperties
)
1044 AviMux
*This
= impl_from_IPersistMediaPropertyBag(iface
);
1045 FIXME("(%p)->()\n", This
);
1049 static const IPersistMediaPropertyBagVtbl PersistMediaPropertyBagVtbl
= {
1050 PersistMediaPropertyBag_QueryInterface
,
1051 PersistMediaPropertyBag_AddRef
,
1052 PersistMediaPropertyBag_Release
,
1053 PersistMediaPropertyBag_GetClassID
,
1054 PersistMediaPropertyBag_InitNew
,
1055 PersistMediaPropertyBag_Load
,
1056 PersistMediaPropertyBag_Save
1059 static inline AviMux
* impl_from_ISpecifyPropertyPages(ISpecifyPropertyPages
*iface
)
1061 return CONTAINING_RECORD(iface
, AviMux
, ISpecifyPropertyPages_iface
);
1064 static HRESULT WINAPI
SpecifyPropertyPages_QueryInterface(
1065 ISpecifyPropertyPages
*iface
, REFIID riid
, void **ppv
)
1067 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1068 return IBaseFilter_QueryInterface(&This
->filter
.IBaseFilter_iface
, riid
, ppv
);
1071 static ULONG WINAPI
SpecifyPropertyPages_AddRef(ISpecifyPropertyPages
*iface
)
1073 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1074 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1077 static ULONG WINAPI
SpecifyPropertyPages_Release(ISpecifyPropertyPages
*iface
)
1079 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1080 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1083 static HRESULT WINAPI
SpecifyPropertyPages_GetPages(
1084 ISpecifyPropertyPages
*iface
, CAUUID
*pPages
)
1086 AviMux
*This
= impl_from_ISpecifyPropertyPages(iface
);
1087 FIXME("(%p)->(%p)\n", This
, pPages
);
1091 static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl
= {
1092 SpecifyPropertyPages_QueryInterface
,
1093 SpecifyPropertyPages_AddRef
,
1094 SpecifyPropertyPages_Release
,
1095 SpecifyPropertyPages_GetPages
1098 static inline AviMux
*impl_from_source_pin(struct strmbase_pin
*iface
)
1100 return CONTAINING_RECORD(iface
, AviMux
, source
.pin
);
1103 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
1105 AviMux
*filter
= impl_from_source_pin(iface
);
1107 if (IsEqualGUID(iid
, &IID_IQualityControl
))
1108 *out
= &filter
->IQualityControl_iface
;
1110 return E_NOINTERFACE
;
1112 IUnknown_AddRef((IUnknown
*)*out
);
1116 static HRESULT
source_query_accept(struct strmbase_pin
*base
, const AM_MEDIA_TYPE
*amt
)
1118 FIXME("(%p) stub\n", base
);
1122 static HRESULT WINAPI
AviMuxOut_AttemptConnection(struct strmbase_source
*iface
,
1123 IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1125 AviMux
*filter
= impl_from_source_pin(&iface
->pin
);
1130 hr
= IPin_QueryDirection(pReceivePin
, &dir
);
1131 if(hr
==S_OK
&& dir
!=PINDIR_INPUT
)
1132 return VFW_E_INVALID_DIRECTION
;
1134 if (FAILED(hr
= BaseOutputPinImpl_AttemptConnection(iface
, pReceivePin
, pmt
)))
1137 for (i
= 0; i
< filter
->input_pin_no
; ++i
)
1139 if (!filter
->in
[i
]->pin
.pin
.peer
)
1142 hr
= IFilterGraph_Reconnect(filter
->filter
.graph
, &filter
->in
[i
]->pin
.pin
.IPin_iface
);
1145 IPin_Disconnect(&iface
->pin
.IPin_iface
);
1153 static HRESULT
source_get_media_type(struct strmbase_pin
*base
, unsigned int iPosition
, AM_MEDIA_TYPE
*amt
)
1155 TRACE("(%p)->(%d %p)\n", base
, iPosition
, amt
);
1158 return VFW_S_NO_MORE_ITEMS
;
1160 amt
->majortype
= MEDIATYPE_Stream
;
1161 amt
->subtype
= MEDIASUBTYPE_Avi
;
1162 amt
->bFixedSizeSamples
= TRUE
;
1163 amt
->bTemporalCompression
= FALSE
;
1164 amt
->lSampleSize
= 1;
1165 amt
->formattype
= GUID_NULL
;
1168 amt
->pbFormat
= NULL
;
1172 static HRESULT WINAPI
AviMuxOut_DecideAllocator(struct strmbase_source
*base
,
1173 IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
1175 ALLOCATOR_PROPERTIES req
, actual
;
1178 TRACE("(%p)->(%p %p)\n", base
, pPin
, pAlloc
);
1180 hr
= BaseOutputPinImpl_InitAllocator(base
, pAlloc
);
1184 hr
= IMemInputPin_GetAllocatorRequirements(pPin
, &req
);
1191 hr
= IMemAllocator_SetProperties(*pAlloc
, &req
, &actual
);
1195 return IMemInputPin_NotifyAllocator(pPin
, *pAlloc
, TRUE
);
1198 static const struct strmbase_source_ops source_ops
=
1200 .base
.pin_query_interface
= source_query_interface
,
1201 .base
.pin_query_accept
= source_query_accept
,
1202 .base
.pin_get_media_type
= source_get_media_type
,
1203 .pfnAttemptConnection
= AviMuxOut_AttemptConnection
,
1204 .pfnDecideAllocator
= AviMuxOut_DecideAllocator
,
1207 static inline AviMux
* impl_from_out_IQualityControl(IQualityControl
*iface
)
1209 return CONTAINING_RECORD(iface
, AviMux
, IQualityControl_iface
);
1212 static HRESULT WINAPI
AviMuxOut_QualityControl_QueryInterface(
1213 IQualityControl
*iface
, REFIID riid
, void **ppv
)
1215 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1216 return IPin_QueryInterface(&This
->source
.pin
.IPin_iface
, riid
, ppv
);
1219 static ULONG WINAPI
AviMuxOut_QualityControl_AddRef(IQualityControl
*iface
)
1221 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1222 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1225 static ULONG WINAPI
AviMuxOut_QualityControl_Release(IQualityControl
*iface
)
1227 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1228 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1231 static HRESULT WINAPI
AviMuxOut_QualityControl_Notify(IQualityControl
*iface
,
1232 IBaseFilter
*pSelf
, Quality q
)
1234 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1235 FIXME("(%p)->(%p { 0x%x %u %s %s })\n", This
, pSelf
,
1236 q
.Type
, q
.Proportion
,
1237 wine_dbgstr_longlong(q
.Late
),
1238 wine_dbgstr_longlong(q
.TimeStamp
));
1242 static HRESULT WINAPI
AviMuxOut_QualityControl_SetSink(
1243 IQualityControl
*iface
, IQualityControl
*piqc
)
1245 AviMux
*This
= impl_from_out_IQualityControl(iface
);
1246 FIXME("(%p)->(%p)\n", This
, piqc
);
1250 static const IQualityControlVtbl AviMuxOut_QualityControlVtbl
= {
1251 AviMuxOut_QualityControl_QueryInterface
,
1252 AviMuxOut_QualityControl_AddRef
,
1253 AviMuxOut_QualityControl_Release
,
1254 AviMuxOut_QualityControl_Notify
,
1255 AviMuxOut_QualityControl_SetSink
1258 static inline AviMuxIn
*impl_sink_from_strmbase_pin(struct strmbase_pin
*iface
)
1260 return CONTAINING_RECORD(iface
, AviMuxIn
, pin
.pin
);
1263 static HRESULT
sink_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
1265 AviMuxIn
*pin
= impl_sink_from_strmbase_pin(iface
);
1267 if (IsEqualGUID(iid
, &IID_IAMStreamControl
))
1268 *out
= &pin
->IAMStreamControl_iface
;
1269 else if (IsEqualGUID(iid
, &IID_IMemInputPin
))
1270 *out
= &pin
->pin
.IMemInputPin_iface
;
1271 else if (IsEqualGUID(iid
, &IID_IPropertyBag
))
1272 *out
= &pin
->IPropertyBag_iface
;
1273 else if (IsEqualGUID(iid
, &IID_IQualityControl
))
1274 *out
= &pin
->IQualityControl_iface
;
1276 return E_NOINTERFACE
;
1278 IUnknown_AddRef((IUnknown
*)*out
);
1282 static HRESULT
sink_query_accept(struct strmbase_pin
*base
, const AM_MEDIA_TYPE
*pmt
)
1284 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
) &&
1285 IsEqualIID(&pmt
->formattype
, &FORMAT_WaveFormatEx
))
1287 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Interleaved
) &&
1288 IsEqualIID(&pmt
->formattype
, &FORMAT_DvInfo
))
1290 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
) &&
1291 (IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
) ||
1292 IsEqualIID(&pmt
->formattype
, &FORMAT_DvInfo
)))
1297 static HRESULT WINAPI
AviMuxIn_Receive(struct strmbase_sink
*base
, IMediaSample
*pSample
)
1299 AviMux
*avimux
= impl_from_strmbase_filter(base
->pin
.filter
);
1300 AviMuxIn
*avimuxin
= CONTAINING_RECORD(base
, AviMuxIn
, pin
);
1301 REFERENCE_TIME start
, stop
;
1302 IMediaSample
*sample
;
1306 DWORD max_size
, size
;
1310 TRACE("pin %p, pSample %p.\n", avimuxin
, pSample
);
1312 hr
= IMediaSample_QueryInterface(pSample
, &IID_IMediaSample2
, (void**)&ms2
);
1314 AM_SAMPLE2_PROPERTIES props
;
1316 memset(&props
, 0, sizeof(props
));
1317 hr
= IMediaSample2_GetProperties(ms2
, sizeof(props
), (BYTE
*)&props
);
1318 IMediaSample2_Release(ms2
);
1322 flags
= props
.dwSampleFlags
;
1323 frame
= props
.pbBuffer
;
1324 size
= props
.lActual
;
1326 flags
= IMediaSample_IsSyncPoint(pSample
) == S_OK
? AM_SAMPLE_SPLICEPOINT
: 0;
1327 hr
= IMediaSample_GetPointer(pSample
, &frame
);
1330 size
= IMediaSample_GetActualDataLength(pSample
);
1333 if(!avimuxin
->pin
.pin
.mt
.bTemporalCompression
)
1334 flags
|= AM_SAMPLE_SPLICEPOINT
;
1336 hr
= IMediaSample_GetTime(pSample
, &start
, &stop
);
1340 if(avimuxin
->stop
>stop
)
1341 return VFW_E_START_TIME_AFTER_END
;
1343 if(avimux
->start
== -1)
1344 avimux
->start
= start
;
1345 if(avimux
->stop
< stop
)
1346 avimux
->stop
= stop
;
1348 if(avimux
->avih
.dwSuggestedBufferSize
< ALIGN(size
)+sizeof(RIFFCHUNK
))
1349 avimux
->avih
.dwSuggestedBufferSize
= ALIGN(size
) + sizeof(RIFFCHUNK
);
1350 if(avimuxin
->strh
.dwSuggestedBufferSize
< ALIGN(size
)+sizeof(RIFFCHUNK
))
1351 avimuxin
->strh
.dwSuggestedBufferSize
= ALIGN(size
) + sizeof(RIFFCHUNK
);
1354 if(avimuxin
->stop
!=-1 && start
> avimuxin
->stop
) {
1355 frames_no
+= (double)(start
- avimuxin
->stop
) / 10000000
1356 * avimuxin
->strh
.dwRate
/ avimuxin
->strh
.dwScale
+ 0.5;
1358 avimuxin
->stop
= stop
;
1360 while(--frames_no
) {
1361 /* TODO: store all control frames in one buffer */
1362 hr
= IMemAllocator_GetBuffer(avimuxin
->samples_allocator
, &sample
, NULL
, NULL
, 0);
1365 hr
= IMediaSample_SetActualDataLength(sample
, 0);
1367 hr
= IMediaSample_SetDiscontinuity(sample
, TRUE
);
1369 hr
= IMediaSample_SetSyncPoint(sample
, FALSE
);
1371 hr
= queue_sample(avimux
, avimuxin
, sample
);
1372 IMediaSample_Release(sample
);
1377 hr
= IMemAllocator_GetBuffer(avimuxin
->samples_allocator
, &sample
, NULL
, NULL
, 0);
1380 max_size
= IMediaSample_GetSize(sample
);
1383 hr
= IMediaSample_SetActualDataLength(sample
, size
);
1385 hr
= IMediaSample_SetDiscontinuity(sample
, FALSE
);
1387 hr
= IMediaSample_SetSyncPoint(sample
, flags
& AM_SAMPLE_SPLICEPOINT
);
1388 /* TODO: avoid unnecessary copying */
1390 hr
= IMediaSample_GetPointer(sample
, &buf
);
1392 memcpy(buf
, frame
, size
);
1393 hr
= queue_sample(avimux
, avimuxin
, sample
);
1395 IMediaSample_Release(sample
);
1400 static HRESULT
avi_mux_sink_connect(struct strmbase_sink
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*pmt
)
1402 AviMuxIn
*avimuxin
= impl_sink_from_strmbase_pin(&iface
->pin
);
1403 AviMux
*This
= impl_from_strmbase_filter(iface
->pin
.filter
);
1409 if(IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Video
) &&
1410 IsEqualIID(&pmt
->formattype
, &FORMAT_VideoInfo
)) {
1411 ALLOCATOR_PROPERTIES req
, act
;
1412 VIDEOINFOHEADER
*vih
;
1415 vih
= (VIDEOINFOHEADER
*)pmt
->pbFormat
;
1416 avimuxin
->strh
.fcc
= ckidSTREAMHEADER
;
1417 avimuxin
->strh
.cb
= sizeof(AVISTREAMHEADER
) - FIELD_OFFSET(AVISTREAMHEADER
, fccType
);
1418 avimuxin
->strh
.fccType
= streamtypeVIDEO
;
1419 /* FIXME: fccHandler should be set differently */
1420 avimuxin
->strh
.fccHandler
= vih
->bmiHeader
.biCompression
?
1421 vih
->bmiHeader
.biCompression
: FCC('D','I','B',' ');
1422 avimuxin
->avg_time_per_frame
= vih
->AvgTimePerFrame
;
1423 avimuxin
->stop
= -1;
1426 req
.cbBuffer
= vih
->bmiHeader
.biSizeImage
;
1428 req
.cbPrefix
= sizeof(void*);
1429 hr
= IMemAllocator_SetProperties(avimuxin
->samples_allocator
, &req
, &act
);
1431 hr
= IMemAllocator_Commit(avimuxin
->samples_allocator
);
1435 size
= pmt
->cbFormat
- FIELD_OFFSET(VIDEOINFOHEADER
, bmiHeader
);
1436 avimuxin
->strf
= CoTaskMemAlloc(sizeof(RIFFCHUNK
) + ALIGN(FIELD_OFFSET(BITMAPINFO
, bmiColors
[vih
->bmiHeader
.biClrUsed
])));
1437 avimuxin
->strf
->fcc
= ckidSTREAMFORMAT
;
1438 avimuxin
->strf
->cb
= FIELD_OFFSET(BITMAPINFO
, bmiColors
[vih
->bmiHeader
.biClrUsed
]);
1439 if(size
> avimuxin
->strf
->cb
)
1440 size
= avimuxin
->strf
->cb
;
1441 memcpy(avimuxin
->strf
->data
, &vih
->bmiHeader
, size
);
1443 FIXME("format not supported: %s %s\n", debugstr_guid(&pmt
->majortype
),
1444 debugstr_guid(&pmt
->formattype
));
1448 return create_input_pin(This
);
1451 static void avi_mux_sink_disconnect(struct strmbase_sink
*iface
)
1453 AviMuxIn
*avimuxin
= impl_sink_from_strmbase_pin(&iface
->pin
);
1454 IMediaSample
**prev
, *cur
;
1456 IMemAllocator_Decommit(avimuxin
->samples_allocator
);
1457 while(avimuxin
->samples_head
) {
1458 cur
= avimuxin
->samples_head
;
1459 if (FAILED(IMediaSample_GetPointer(cur
, (BYTE
**)&prev
)))
1463 cur
= avimuxin
->samples_head
;
1464 avimuxin
->samples_head
= *prev
;
1465 IMediaSample_Release(cur
);
1467 if(cur
== avimuxin
->samples_head
)
1468 avimuxin
->samples_head
= NULL
;
1470 CoTaskMemFree(avimuxin
->strf
);
1471 avimuxin
->strf
= NULL
;
1474 static const struct strmbase_sink_ops sink_ops
=
1476 .base
.pin_query_interface
= sink_query_interface
,
1477 .base
.pin_query_accept
= sink_query_accept
,
1478 .base
.pin_get_media_type
= strmbase_pin_get_media_type
,
1479 .pfnReceive
= AviMuxIn_Receive
,
1480 .sink_connect
= avi_mux_sink_connect
,
1481 .sink_disconnect
= avi_mux_sink_disconnect
,
1484 static inline AviMux
* impl_from_in_IPin(IPin
*iface
)
1486 struct strmbase_pin
*pin
= CONTAINING_RECORD(iface
, struct strmbase_pin
, IPin_iface
);
1487 return impl_from_strmbase_filter(pin
->filter
);
1490 static inline AviMuxIn
* AviMuxIn_from_IAMStreamControl(IAMStreamControl
*iface
)
1492 return CONTAINING_RECORD(iface
, AviMuxIn
, IAMStreamControl_iface
);
1495 static HRESULT WINAPI
AviMuxIn_AMStreamControl_QueryInterface(
1496 IAMStreamControl
*iface
, REFIID riid
, void **ppv
)
1498 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1499 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1502 static ULONG WINAPI
AviMuxIn_AMStreamControl_AddRef(IAMStreamControl
*iface
)
1504 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1505 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1506 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1509 static ULONG WINAPI
AviMuxIn_AMStreamControl_Release(IAMStreamControl
*iface
)
1511 AviMuxIn
*avimuxin
= AviMuxIn_from_IAMStreamControl(iface
);
1512 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1513 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1516 static HRESULT WINAPI
AviMuxIn_AMStreamControl_StartAt(IAMStreamControl
*iface
,
1517 const REFERENCE_TIME
*start
, DWORD cookie
)
1519 FIXME("iface %p, start %p, cookie %#x, stub!\n", iface
, start
, cookie
);
1523 static HRESULT WINAPI
AviMuxIn_AMStreamControl_StopAt(IAMStreamControl
*iface
,
1524 const REFERENCE_TIME
*stop
, BOOL send_extra
, DWORD cookie
)
1526 FIXME("iface %p, stop %p, send_extra %d, cookie %#x, stub!\n", iface
, stop
, send_extra
, cookie
);
1530 static HRESULT WINAPI
AviMuxIn_AMStreamControl_GetInfo(IAMStreamControl
*iface
,
1531 AM_STREAM_INFO
*info
)
1533 FIXME("iface %p, info %p, stub!\n", iface
, info
);
1537 static const IAMStreamControlVtbl AviMuxIn_AMStreamControlVtbl
= {
1538 AviMuxIn_AMStreamControl_QueryInterface
,
1539 AviMuxIn_AMStreamControl_AddRef
,
1540 AviMuxIn_AMStreamControl_Release
,
1541 AviMuxIn_AMStreamControl_StartAt
,
1542 AviMuxIn_AMStreamControl_StopAt
,
1543 AviMuxIn_AMStreamControl_GetInfo
1546 static inline AviMuxIn
* AviMuxIn_from_IMemInputPin(IMemInputPin
*iface
)
1548 return CONTAINING_RECORD(iface
, AviMuxIn
, pin
.IMemInputPin_iface
);
1551 static HRESULT WINAPI
AviMuxIn_MemInputPin_QueryInterface(
1552 IMemInputPin
*iface
, REFIID riid
, void **ppv
)
1554 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1555 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1558 static ULONG WINAPI
AviMuxIn_MemInputPin_AddRef(IMemInputPin
*iface
)
1560 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1561 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1562 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1565 static ULONG WINAPI
AviMuxIn_MemInputPin_Release(IMemInputPin
*iface
)
1567 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1568 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1569 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1572 static HRESULT WINAPI
AviMuxIn_MemInputPin_GetAllocator(
1573 IMemInputPin
*iface
, IMemAllocator
**ppAllocator
)
1575 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1577 TRACE("pin %p, ppAllocator %p.\n", avimuxin
, ppAllocator
);
1582 IMemAllocator_AddRef(avimuxin
->pin
.pAllocator
);
1583 *ppAllocator
= avimuxin
->pin
.pAllocator
;
1587 static HRESULT WINAPI
AviMuxIn_MemInputPin_NotifyAllocator(
1588 IMemInputPin
*iface
, IMemAllocator
*pAllocator
, BOOL bReadOnly
)
1590 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1591 ALLOCATOR_PROPERTIES props
;
1594 TRACE("pin %p, pAllocator %p, bReadOnly %d.\n", avimuxin
, pAllocator
, bReadOnly
);
1599 memset(&props
, 0, sizeof(props
));
1600 hr
= IMemAllocator_GetProperties(pAllocator
, &props
);
1606 return IMemAllocator_SetProperties(avimuxin
->pin
.pAllocator
, &props
, &props
);
1609 static HRESULT WINAPI
AviMuxIn_MemInputPin_GetAllocatorRequirements(
1610 IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*pProps
)
1612 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1614 TRACE("pin %p, pProps %p.\n", avimuxin
, pProps
);
1619 pProps
->cbAlign
= 1;
1620 pProps
->cbPrefix
= 8;
1624 static HRESULT WINAPI
AviMuxIn_MemInputPin_Receive(
1625 IMemInputPin
*iface
, IMediaSample
*pSample
)
1627 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1629 TRACE("pin %p, pSample %p.\n", avimuxin
, pSample
);
1631 return avimuxin
->pin
.pFuncsTable
->pfnReceive(&avimuxin
->pin
, pSample
);
1634 static HRESULT WINAPI
AviMuxIn_MemInputPin_ReceiveMultiple(IMemInputPin
*iface
,
1635 IMediaSample
**pSamples
, LONG nSamples
, LONG
*nSamplesProcessed
)
1637 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1640 TRACE("pin %p, pSamples %p, nSamples %d, nSamplesProcessed %p.\n",
1641 avimuxin
, pSamples
, nSamples
, nSamplesProcessed
);
1643 for(*nSamplesProcessed
=0; *nSamplesProcessed
<nSamples
; (*nSamplesProcessed
)++)
1645 hr
= avimuxin
->pin
.pFuncsTable
->pfnReceive(&avimuxin
->pin
, pSamples
[*nSamplesProcessed
]);
1653 static HRESULT WINAPI
AviMuxIn_MemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
1655 AviMuxIn
*avimuxin
= AviMuxIn_from_IMemInputPin(iface
);
1656 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1659 TRACE("avimuxin %p.\n", avimuxin
);
1661 if(!This
->source
.pMemInputPin
)
1664 hr
= IMemInputPin_ReceiveCanBlock(This
->source
.pMemInputPin
);
1665 return hr
!= S_FALSE
? S_OK
: S_FALSE
;
1668 static const IMemInputPinVtbl AviMuxIn_MemInputPinVtbl
= {
1669 AviMuxIn_MemInputPin_QueryInterface
,
1670 AviMuxIn_MemInputPin_AddRef
,
1671 AviMuxIn_MemInputPin_Release
,
1672 AviMuxIn_MemInputPin_GetAllocator
,
1673 AviMuxIn_MemInputPin_NotifyAllocator
,
1674 AviMuxIn_MemInputPin_GetAllocatorRequirements
,
1675 AviMuxIn_MemInputPin_Receive
,
1676 AviMuxIn_MemInputPin_ReceiveMultiple
,
1677 AviMuxIn_MemInputPin_ReceiveCanBlock
1680 static inline AviMuxIn
* AviMuxIn_from_IPropertyBag(IPropertyBag
*iface
)
1682 return CONTAINING_RECORD(iface
, AviMuxIn
, IPropertyBag_iface
);
1685 static HRESULT WINAPI
AviMuxIn_PropertyBag_QueryInterface(
1686 IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1688 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1689 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1692 static ULONG WINAPI
AviMuxIn_PropertyBag_AddRef(IPropertyBag
*iface
)
1694 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1695 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1696 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1699 static ULONG WINAPI
AviMuxIn_PropertyBag_Release(IPropertyBag
*iface
)
1701 AviMuxIn
*avimuxin
= AviMuxIn_from_IPropertyBag(iface
);
1702 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1703 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1706 static HRESULT WINAPI
AviMuxIn_PropertyBag_Read(IPropertyBag
*iface
,
1707 const WCHAR
*name
, VARIANT
*value
, IErrorLog
*error_log
)
1709 FIXME("iface %p, name %s, value %p, error_log %p, stub!\n",
1710 iface
, debugstr_w(name
), value
, error_log
);
1714 static HRESULT WINAPI
AviMuxIn_PropertyBag_Write(IPropertyBag
*iface
,
1715 const WCHAR
*name
, VARIANT
*value
)
1717 FIXME("iface %p, name %s, value %s, stub!\n",
1718 iface
, debugstr_w(name
), debugstr_variant(value
));
1722 static const IPropertyBagVtbl AviMuxIn_PropertyBagVtbl
= {
1723 AviMuxIn_PropertyBag_QueryInterface
,
1724 AviMuxIn_PropertyBag_AddRef
,
1725 AviMuxIn_PropertyBag_Release
,
1726 AviMuxIn_PropertyBag_Read
,
1727 AviMuxIn_PropertyBag_Write
1730 static inline AviMuxIn
* AviMuxIn_from_IQualityControl(IQualityControl
*iface
)
1732 return CONTAINING_RECORD(iface
, AviMuxIn
, IQualityControl_iface
);
1735 static HRESULT WINAPI
AviMuxIn_QualityControl_QueryInterface(
1736 IQualityControl
*iface
, REFIID riid
, void **ppv
)
1738 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1739 return IPin_QueryInterface(&avimuxin
->pin
.pin
.IPin_iface
, riid
, ppv
);
1742 static ULONG WINAPI
AviMuxIn_QualityControl_AddRef(IQualityControl
*iface
)
1744 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1745 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1746 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
1749 static ULONG WINAPI
AviMuxIn_QualityControl_Release(IQualityControl
*iface
)
1751 AviMuxIn
*avimuxin
= AviMuxIn_from_IQualityControl(iface
);
1752 AviMux
*This
= impl_from_in_IPin(&avimuxin
->pin
.pin
.IPin_iface
);
1753 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
1756 static HRESULT WINAPI
AviMuxIn_QualityControl_Notify(IQualityControl
*iface
,
1757 IBaseFilter
*filter
, Quality q
)
1759 FIXME("iface %p, filter %p, type %u, proportion %d, late %s, timestamp %s, stub!\n",
1760 iface
, filter
, q
.Type
, q
.Proportion
, wine_dbgstr_longlong(q
.Late
),
1761 wine_dbgstr_longlong(q
.TimeStamp
));
1765 static HRESULT WINAPI
AviMuxIn_QualityControl_SetSink(IQualityControl
*iface
, IQualityControl
*sink
)
1767 FIXME("iface %p, sink %p, stub!\n", iface
, sink
);
1771 static const IQualityControlVtbl AviMuxIn_QualityControlVtbl
= {
1772 AviMuxIn_QualityControl_QueryInterface
,
1773 AviMuxIn_QualityControl_AddRef
,
1774 AviMuxIn_QualityControl_Release
,
1775 AviMuxIn_QualityControl_Notify
,
1776 AviMuxIn_QualityControl_SetSink
1779 static HRESULT
create_input_pin(AviMux
*avimux
)
1781 WCHAR name
[] = {'I','n','p','u','t',' ','0','0',0};
1785 if(avimux
->input_pin_no
>= MAX_PIN_NO
-1)
1788 name
[7] = '0' + (avimux
->input_pin_no
+1) % 10;
1789 name
[6] = '0' + (avimux
->input_pin_no
+1) / 10;
1791 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1792 return E_OUTOFMEMORY
;
1794 strmbase_sink_init(&object
->pin
, &avimux
->filter
, name
, &sink_ops
, NULL
);
1795 object
->pin
.IMemInputPin_iface
.lpVtbl
= &AviMuxIn_MemInputPinVtbl
;
1796 object
->IAMStreamControl_iface
.lpVtbl
= &AviMuxIn_AMStreamControlVtbl
;
1797 object
->IPropertyBag_iface
.lpVtbl
= &AviMuxIn_PropertyBagVtbl
;
1798 object
->IQualityControl_iface
.lpVtbl
= &AviMuxIn_QualityControlVtbl
;
1800 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1801 &IID_IMemAllocator
, (void **)&object
->samples_allocator
);
1804 strmbase_sink_cleanup(&object
->pin
);
1809 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
1810 &IID_IMemAllocator
, (void **)&object
->pin
.pAllocator
);
1813 IMemAllocator_Release(object
->samples_allocator
);
1814 strmbase_sink_cleanup(&object
->pin
);
1819 object
->indx
= (AVISUPERINDEX
*)&object
->indx_data
;
1820 object
->ix
= (AVISTDINDEX
*)object
->ix_data
;
1822 avimux
->in
[avimux
->input_pin_no
++] = object
;
1826 HRESULT
avi_mux_create(IUnknown
*outer
, IUnknown
**out
)
1828 static const WCHAR output_name
[] = {'A','V','I',' ','O','u','t',0};
1834 if (!(avimux
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AviMux
))))
1835 return E_OUTOFMEMORY
;
1837 strmbase_filter_init(&avimux
->filter
, outer
, &CLSID_AviDest
, &filter_ops
);
1838 avimux
->IConfigAviMux_iface
.lpVtbl
= &ConfigAviMuxVtbl
;
1839 avimux
->IConfigInterleaving_iface
.lpVtbl
= &ConfigInterleavingVtbl
;
1840 avimux
->IMediaSeeking_iface
.lpVtbl
= &MediaSeekingVtbl
;
1841 avimux
->IPersistMediaPropertyBag_iface
.lpVtbl
= &PersistMediaPropertyBagVtbl
;
1842 avimux
->ISpecifyPropertyPages_iface
.lpVtbl
= &SpecifyPropertyPagesVtbl
;
1844 info
.dir
= PINDIR_OUTPUT
;
1845 info
.pFilter
= &avimux
->filter
.IBaseFilter_iface
;
1846 lstrcpyW(info
.achName
, output_name
);
1847 strmbase_source_init(&avimux
->source
, &avimux
->filter
, output_name
, &source_ops
);
1848 avimux
->IQualityControl_iface
.lpVtbl
= &AviMuxOut_QualityControlVtbl
;
1849 avimux
->cur_stream
= 0;
1850 avimux
->cur_time
= 0;
1851 avimux
->stream
= NULL
;
1853 hr
= create_input_pin(avimux
);
1855 strmbase_source_cleanup(&avimux
->source
);
1856 strmbase_filter_cleanup(&avimux
->filter
);
1857 HeapFree(GetProcessHeap(), 0, avimux
);
1861 avimux
->interleave
= 10000000;
1863 TRACE("Created AVI mux %p.\n", avimux
);
1864 ObjectRefCount(TRUE
);
1865 *out
= &avimux
->filter
.IUnknown_inner
;