Piotr Caban : qcap: Add partial Avi Mux IBaseFilter::Run implementation.
Alexandre Julliard
julliard at winehq.org
Tue Feb 25 16:58:15 CST 2014
Module: wine
Branch: master
Commit: 053b1f6f60d666a4cd28f475f08576722eed1c31
URL: http://source.winehq.org/git/wine.git/?a=commit;h=053b1f6f60d666a4cd28f475f08576722eed1c31
Author: Piotr Caban <piotr at codeweavers.com>
Date: Tue Feb 25 12:22:53 2014 +0100
qcap: Add partial Avi Mux IBaseFilter::Run implementation.
---
dlls/qcap/avimux.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 168 insertions(+), 2 deletions(-)
diff --git a/dlls/qcap/avimux.c b/dlls/qcap/avimux.c
index 20f830a..dde634e 100644
--- a/dlls/qcap/avimux.c
+++ b/dlls/qcap/avimux.c
@@ -25,6 +25,7 @@
#include "winbase.h"
#include "wtypes.h"
#include "dshow.h"
+#include "vfw.h"
#include "aviriff.h"
#include "qcap_main.h"
@@ -34,11 +35,17 @@
WINE_DEFAULT_DEBUG_CHANNEL(qcap);
#define MAX_PIN_NO 128
+#define AVISUPERINDEX_ENTRIES 2000
+#define AVISTDINDEX_ENTRIES 4000
#define ALIGN(x) ((x+1)/2*2)
typedef struct {
BaseOutputPin pin;
IQualityControl IQualityControl_iface;
+
+ int movi_off;
+ int size;
+ IStream *stream;
} AviMuxOut;
typedef struct {
@@ -47,6 +54,9 @@ typedef struct {
IPropertyBag IPropertyBag_iface;
IQualityControl IQualityControl_iface;
+ REFERENCE_TIME avg_time_per_frame;
+ int stream_id;
+
/* strl chunk */
AVISTREAMHEADER strh;
struct {
@@ -54,6 +64,13 @@ typedef struct {
DWORD cb;
BYTE data[1];
} *strf;
+ AVISUPERINDEX *indx;
+ BYTE indx_data[FIELD_OFFSET(AVISUPERINDEX, aIndex[AVISUPERINDEX_ENTRIES])];
+
+ /* movi chunk */
+ int ix_off;
+ AVISTDINDEX *ix;
+ BYTE ix_data[FIELD_OFFSET(AVISTDINDEX, aIndex[AVISTDINDEX_ENTRIES])];
} AviMuxIn;
typedef struct {
@@ -71,6 +88,13 @@ typedef struct {
AviMuxOut *out;
int input_pin_no;
AviMuxIn *in[MAX_PIN_NO-1];
+
+ REFERENCE_TIME start, stop;
+ AVIMAINHEADER avih;
+
+ int idx1_entries;
+ int idx1_size;
+ AVIINDEXENTRY *idx1;
} AviMux;
static HRESULT create_input_pin(AviMux*);
@@ -159,12 +183,33 @@ static ULONG WINAPI AviMux_Release(IBaseFilter *iface)
for(i=0; i<This->input_pin_no; i++)
BaseInputPinImpl_Release(&This->in[i]->pin.pin.IPin_iface);
+ HeapFree(GetProcessHeap(), 0, This->idx1);
HeapFree(GetProcessHeap(), 0, This);
ObjectRefCount(FALSE);
}
return ref;
}
+static inline HRESULT idx1_add_entry(AviMux *avimux, DWORD ckid, DWORD flags, DWORD off, DWORD len)
+{
+ if(avimux->idx1_entries == avimux->idx1_size) {
+ AVIINDEXENTRY *new_idx = HeapReAlloc(GetProcessHeap(), 0, avimux->idx1,
+ sizeof(*avimux->idx1)*2*avimux->idx1_size);
+ if(!new_idx)
+ return E_OUTOFMEMORY;
+
+ avimux->idx1_size *= 2;
+ avimux->idx1 = new_idx;
+ }
+
+ avimux->idx1[avimux->idx1_entries].ckid = ckid;
+ avimux->idx1[avimux->idx1_entries].dwFlags = flags;
+ avimux->idx1[avimux->idx1_entries].dwChunkOffset = off;
+ avimux->idx1[avimux->idx1_entries].dwChunkLength = len;
+ avimux->idx1_entries++;
+ return S_OK;
+}
+
static HRESULT WINAPI AviMux_Stop(IBaseFilter *iface)
{
AviMux *This = impl_from_IBaseFilter(iface);
@@ -182,8 +227,124 @@ static HRESULT WINAPI AviMux_Pause(IBaseFilter *iface)
static HRESULT WINAPI AviMux_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
{
AviMux *This = impl_from_IBaseFilter(iface);
- FIXME("(%p)->(0x%x%08x)\n", This, (ULONG)(tStart >> 32), (ULONG)tStart);
- return E_NOTIMPL;
+ HRESULT hr;
+ int i, stream_id;
+
+ TRACE("(%p)->(0x%x%08x)\n", This, (ULONG)(tStart >> 32), (ULONG)tStart);
+
+ if(This->filter.state == State_Running)
+ return S_OK;
+
+ if(This->mode != INTERLEAVE_FULL) {
+ FIXME("mode not supported (%d)\n", This->mode);
+ return E_NOTIMPL;
+ }
+
+ if(tStart)
+ FIXME("tStart parameter ignored\n");
+
+ for(i=0; i<This->input_pin_no; i++) {
+ IMediaSeeking *ms;
+ LONGLONG cur, stop;
+
+ if(!This->in[i]->pin.pin.pConnectedTo)
+ continue;
+
+ hr = IPin_QueryInterface(This->in[i]->pin.pin.pConnectedTo,
+ &IID_IMediaSeeking, (void**)&ms);
+ if(FAILED(hr))
+ continue;
+
+ hr = IMediaSeeking_GetPositions(ms, &cur, &stop);
+ if(FAILED(hr)) {
+ IMediaSeeking_Release(ms);
+ continue;
+ }
+
+ FIXME("Use IMediaSeeking to fill stream header\n");
+ IMediaSeeking_Release(ms);
+ }
+
+ if(This->out->pin.pMemInputPin) {
+ hr = IMemInputPin_QueryInterface(This->out->pin.pMemInputPin,
+ &IID_IStream, (void**)&This->out->stream);
+ if(FAILED(hr))
+ return hr;
+ }
+
+ This->idx1_entries = 0;
+ if(!This->idx1_size) {
+ This->idx1_size = 1024;
+ This->idx1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->idx1)*This->idx1_size);
+ if(!This->idx1)
+ return E_OUTOFMEMORY;
+ }
+
+ This->out->size = 3*sizeof(RIFFLIST) + sizeof(AVIMAINHEADER) + sizeof(AVIEXTHEADER);
+ This->start = -1;
+ This->stop = -1;
+ memset(&This->avih, 0, sizeof(This->avih));
+ for(i=0; i<This->input_pin_no; i++) {
+ if(!This->in[i]->pin.pin.pConnectedTo)
+ continue;
+
+ This->avih.dwStreams++;
+ This->out->size += sizeof(RIFFLIST) + sizeof(AVISTREAMHEADER) + sizeof(RIFFCHUNK)
+ + This->in[i]->strf->cb + sizeof(This->in[i]->indx_data);
+
+ This->in[i]->strh.dwScale = MulDiv(This->in[i]->avg_time_per_frame, This->interleave, 10000000);
+ This->in[i]->strh.dwRate = This->interleave;
+
+ hr = IMemAllocator_Commit(This->in[i]->pin.pAllocator);
+ if(FAILED(hr)) {
+ if(This->out->stream) {
+ IStream_Release(This->out->stream);
+ This->out->stream = NULL;
+ }
+ return hr;
+ }
+ }
+
+ This->out->movi_off = This->out->size;
+ This->out->size += sizeof(RIFFLIST);
+
+ idx1_add_entry(This, FCC('7','F','x','x'), 0, This->out->movi_off+sizeof(RIFFLIST), 0);
+
+ stream_id = 0;
+ for(i=0; i<This->input_pin_no; i++) {
+ if(!This->in[i]->pin.pin.pConnectedTo)
+ continue;
+
+ This->in[i]->ix_off = This->out->size;
+ This->out->size += sizeof(This->in[i]->ix_data);
+ This->in[i]->ix->fcc = FCC('i','x','0'+stream_id/10,'0'+stream_id%10);
+ This->in[i]->ix->cb = sizeof(This->in[i]->ix_data) - sizeof(RIFFCHUNK);
+ This->in[i]->ix->wLongsPerEntry = 2;
+ This->in[i]->ix->bIndexSubType = 0;
+ This->in[i]->ix->bIndexType = AVI_INDEX_OF_CHUNKS;
+ This->in[i]->ix->dwChunkId = FCC('0'+stream_id/10,'0'+stream_id%10,'d','b');
+ This->in[i]->ix->qwBaseOffset = 0;
+
+ This->in[i]->indx->fcc = ckidAVISUPERINDEX;
+ This->in[i]->indx->cb = sizeof(This->in[i]->indx_data) - sizeof(RIFFCHUNK);
+ This->in[i]->indx->wLongsPerEntry = 4;
+ This->in[i]->indx->bIndexSubType = 0;
+ This->in[i]->indx->bIndexType = AVI_INDEX_OF_INDEXES;
+ This->in[i]->indx->dwChunkId = This->in[i]->ix->dwChunkId;
+ This->in[i]->stream_id = stream_id++;
+ }
+
+ This->avih.fcc = ckidMAINAVIHEADER;
+ This->avih.cb = sizeof(AVIMAINHEADER) - sizeof(RIFFCHUNK);
+ /* TODO: Use first video stream */
+ This->avih.dwMicroSecPerFrame = This->in[0]->avg_time_per_frame/10;
+ This->avih.dwPaddingGranularity = 1;
+ This->avih.dwFlags = AVIF_TRUSTCKTYPE | AVIF_HASINDEX;
+ This->avih.dwWidth = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biWidth;
+ This->avih.dwHeight = ((BITMAPINFOHEADER*)This->in[0]->strf->data)->biHeight;
+
+ This->filter.state = State_Running;
+ return S_OK;
}
static HRESULT WINAPI AviMux_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
@@ -1653,6 +1814,10 @@ static HRESULT create_input_pin(AviMux *avimux)
memset(&avimux->in[avimux->input_pin_no]->strh, 0, sizeof(avimux->in[avimux->input_pin_no]->strh));
avimux->in[avimux->input_pin_no]->strf = NULL;
+ memset(&avimux->in[avimux->input_pin_no]->indx_data, 0, sizeof(avimux->in[avimux->input_pin_no]->indx_data));
+ memset(&avimux->in[avimux->input_pin_no]->ix_data, 0, sizeof(avimux->in[avimux->input_pin_no]->ix_data));
+ avimux->in[avimux->input_pin_no]->indx = (AVISUPERINDEX*)&avimux->in[avimux->input_pin_no]->indx_data;
+ avimux->in[avimux->input_pin_no]->ix = (AVISTDINDEX*)avimux->in[avimux->input_pin_no]->ix_data;
avimux->input_pin_no++;
return S_OK;
@@ -1699,6 +1864,7 @@ IUnknown* WINAPI QCAP_createAVIMux(IUnknown *pUnkOuter, HRESULT *phr)
return NULL;
}
avimux->out->IQualityControl_iface.lpVtbl = &AviMuxOut_QualityControlVtbl;
+ avimux->out->stream = NULL;
hr = create_input_pin(avimux);
if(FAILED(hr)) {
More information about the wine-cvs
mailing list