4 * Copyright 2005 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "quartz_private.h"
22 #include "control_private.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
42 static const WCHAR wcsOutputPinName
[] = {'o','u','t','p','u','t',' ','p','i','n',0};
44 typedef struct WAVEParserImpl
47 IMediaSample
* pCurrentSample
;
48 LONGLONG StartOfFile
; /* in media time */
52 static HRESULT
WAVEParser_Sample(LPVOID iface
, IMediaSample
* pSample
)
54 WAVEParserImpl
*This
= (WAVEParserImpl
*)iface
;
55 LPBYTE pbSrcStream
= NULL
;
57 REFERENCE_TIME tStart
, tStop
;
59 BOOL bMoreData
= TRUE
;
60 Parser_OutputPin
* pOutputPin
;
63 long chunk_remaining_bytes
= 0;
66 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
68 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
70 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
72 assert(BYTES_FROM_MEDIATIME(tStop
- tStart
) == cbSrcStream
);
74 pOutputPin
= (Parser_OutputPin
*)This
->Parser
.ppPins
[1];
76 if (tStop
< This
->StartOfFile
)
79 if (tStart
< This
->StartOfFile
)
80 offset_src
= BYTES_FROM_MEDIATIME(This
->StartOfFile
- tStart
);
84 if (!This
->pCurrentSample
)
86 /* cache media sample until it is ready to be despatched
87 * (i.e. we reach the end of the chunk) */
88 hr
= OutputPin_GetDeliveryBuffer(&pOutputPin
->pin
, &This
->pCurrentSample
, NULL
, NULL
, 0);
92 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, 0);
97 TRACE("Skipping sending sample due to error (%x)\n", hr
);
98 This
->pCurrentSample
= NULL
;
103 hr
= IMediaSample_GetPointer(This
->pCurrentSample
, &pbDstStream
);
107 cbDstStream
= IMediaSample_GetSize(This
->pCurrentSample
);
109 chunk_remaining_bytes
= cbDstStream
- IMediaSample_GetActualDataLength(This
->pCurrentSample
);
111 assert(chunk_remaining_bytes
>= 0);
112 assert(chunk_remaining_bytes
<= cbDstStream
- IMediaSample_GetActualDataLength(This
->pCurrentSample
));
115 if (chunk_remaining_bytes
<= cbSrcStream
- offset_src
)
119 memcpy(pbDstStream
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
), pbSrcStream
+ offset_src
, chunk_remaining_bytes
);
120 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, chunk_remaining_bytes
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
));
126 REFERENCE_TIME tAviStart
, tAviStop
;
129 if (pOutputPin
->dwSamplesProcessed
== 0) {
130 IMediaSample_SetDiscontinuity(This
->pCurrentSample
, TRUE
);
131 IMediaSample_SetSyncPoint(This
->pCurrentSample
, TRUE
);
134 pOutputPin
->dwSamplesProcessed
++;
136 if (pOutputPin
->dwSampleSize
)
137 tAviStart
= (LONGLONG
)ceil(10000000.0 * (float)(pOutputPin
->dwSamplesProcessed
- 1) * (float)IMediaSample_GetActualDataLength(This
->pCurrentSample
) / ((float)pOutputPin
->dwSampleSize
* pOutputPin
->fSamplesPerSec
));
139 tAviStart
= (LONGLONG
)ceil(10000000.0 * (float)(pOutputPin
->dwSamplesProcessed
- 1) / (float)pOutputPin
->fSamplesPerSec
);
140 if (pOutputPin
->dwSampleSize
)
141 tAviStop
= (LONGLONG
)ceil(10000000.0 * (float)pOutputPin
->dwSamplesProcessed
* (float)IMediaSample_GetActualDataLength(This
->pCurrentSample
) / ((float)pOutputPin
->dwSampleSize
* pOutputPin
->fSamplesPerSec
));
143 tAviStop
= (LONGLONG
)ceil(10000000.0 * (float)pOutputPin
->dwSamplesProcessed
/ (float)pOutputPin
->fSamplesPerSec
);
145 IMediaSample_SetTime(This
->pCurrentSample
, &tAviStart
, &tAviStop
);
147 hr
= OutputPin_SendSample(&pOutputPin
->pin
, This
->pCurrentSample
);
148 if (hr
!= S_OK
&& hr
!= VFW_E_NOT_CONNECTED
)
149 ERR("Error sending sample (%x)\n", hr
);
152 if (This
->pCurrentSample
)
153 IMediaSample_Release(This
->pCurrentSample
);
155 This
->pCurrentSample
= NULL
;
161 memcpy(pbDstStream
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
), pbSrcStream
+ offset_src
, cbSrcStream
- offset_src
);
162 IMediaSample_SetActualDataLength(This
->pCurrentSample
, cbSrcStream
- offset_src
+ IMediaSample_GetActualDataLength(This
->pCurrentSample
));
166 offset_src
+= chunk_remaining_bytes
;
169 if (tStop
>= This
->EndOfFile
)
173 TRACE("End of file reached\n");
175 for (i
= 0; i
< This
->Parser
.cStreams
; i
++)
180 TRACE("Send End Of Stream to output pin %d\n", i
);
182 hr
= IPin_ConnectedTo(This
->Parser
.ppPins
[i
+1], &ppin
);
185 hr
= IPin_EndOfStream(ppin
);
195 /* Force the pullpin thread to stop */
202 static HRESULT
WAVEParser_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
204 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Stream
))
206 if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_WAVE
))
208 if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_AU
) || IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_AIFF
))
209 FIXME("AU and AIFF files not supported yet!\n");
213 static HRESULT
WAVEParser_InputPin_PreConnect(IPin
* iface
, IPin
* pConnectPin
)
215 PullPin
*This
= (PullPin
*)iface
;
219 LONGLONG pos
= 0; /* in bytes */
221 ALLOCATOR_PROPERTIES props
;
223 float fSamplesPerSec
= 0.0f
;
224 DWORD dwSampleSize
= 0;
226 WAVEParserImpl
* pWAVEParser
= (WAVEParserImpl
*)This
->pin
.pinInfo
.pFilter
;
228 piOutput
.dir
= PINDIR_OUTPUT
;
229 piOutput
.pFilter
= (IBaseFilter
*)This
;
230 lstrcpynW(piOutput
.achName
, wcsOutputPinName
, sizeof(piOutput
.achName
) / sizeof(piOutput
.achName
[0]));
232 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(list
), (BYTE
*)&list
);
235 if (list
.fcc
!= ckidRIFF
)
237 ERR("Input stream not a RIFF file\n");
240 if (list
.cb
> 1 * 1024 * 1024 * 1024) /* cannot be more than 1Gb in size */
242 ERR("Input stream violates RIFF spec\n");
245 if (list
.fccListType
!= mmioFOURCC('W','A','V','E'))
247 ERR("Input stream not an WAVE RIFF file\n");
251 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(chunk
), (BYTE
*)&chunk
);
252 pos
+= sizeof(chunk
);
253 if (chunk
.fcc
!= mmioFOURCC('f','m','t',' '))
255 ERR("Expected 'fmt ' chunk, but got %.04s\n", (LPSTR
)&chunk
.fcc
);
259 memcpy(&amt
.majortype
, &MEDIATYPE_Audio
, sizeof(GUID
));
260 memcpy(&amt
.formattype
, &FORMAT_WaveFormatEx
, sizeof(GUID
));
261 amt
.cbFormat
= chunk
.cb
;
262 amt
.pbFormat
= CoTaskMemAlloc(amt
.cbFormat
);
264 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, amt
.cbFormat
, amt
.pbFormat
);
265 memcpy(&amt
.subtype
, &MEDIATYPE_Audio
, sizeof(GUID
));
266 amt
.subtype
.Data1
= ((WAVEFORMATEX
*)amt
.pbFormat
)->wFormatTag
;
269 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(chunk
), (BYTE
*)&chunk
);
270 if (chunk
.fcc
== mmioFOURCC('f','a','c','t'))
272 FIXME("'fact' chunk not supported yet\n");
273 pos
+= sizeof(chunk
) + chunk
.cb
;
274 hr
= IAsyncReader_SyncRead(This
->pReader
, pos
, sizeof(chunk
), (BYTE
*)&chunk
);
276 if (chunk
.fcc
!= mmioFOURCC('d','a','t','a'))
278 ERR("Expected 'data' chunk, but got %.04s\n", (LPSTR
)&chunk
.fcc
);
284 pWAVEParser
->StartOfFile
= MEDIATIME_FROM_BYTES(pos
+ sizeof(RIFFCHUNK
));
285 pWAVEParser
->EndOfFile
= MEDIATIME_FROM_BYTES(pos
+ chunk
.cb
+ sizeof(RIFFCHUNK
));
291 props
.cbAlign
= ((WAVEFORMATEX
*)amt
.pbFormat
)->nBlockAlign
;
293 props
.cbBuffer
= 4096;
296 hr
= Parser_AddPin(&(pWAVEParser
->Parser
), &piOutput
, &props
, &amt
, fSamplesPerSec
, dwSampleSize
, dwLength
);
298 TRACE("WAVE File ok\n");
303 static HRESULT
WAVEParser_Cleanup(LPVOID iface
)
305 WAVEParserImpl
*This
= (WAVEParserImpl
*)iface
;
307 TRACE("(%p)->()\n", This
);
309 if (This
->pCurrentSample
)
310 IMediaSample_Release(This
->pCurrentSample
);
311 This
->pCurrentSample
= NULL
;
316 HRESULT
WAVEParser_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
319 WAVEParserImpl
* This
;
321 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
326 return CLASS_E_NOAGGREGATION
;
328 /* Note: This memory is managed by the transform filter once created */
329 This
= CoTaskMemAlloc(sizeof(WAVEParserImpl
));
331 This
->pCurrentSample
= NULL
;
333 hr
= Parser_Create(&(This
->Parser
), &CLSID_WAVEParser
, WAVEParser_Sample
, WAVEParser_QueryAccept
, WAVEParser_InputPin_PreConnect
, WAVEParser_Cleanup
);