windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / avifil32 / acmstream.c
blob09db400513bb9a81332ca09f943e41bacd0d5eb9
1 /*
2 * Copyright 2002 Michael Günnewig
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 <assert.h>
20 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winuser.h"
26 #include "winerror.h"
27 #include "mmsystem.h"
28 #include "vfw.h"
29 #include "msacm.h"
31 #include "avifile_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
37 /***********************************************************************/
39 typedef struct _IAVIStreamImpl {
40 /* IUnknown stuff */
41 IAVIStream IAVIStream_iface;
42 LONG ref;
44 /* IAVIStream stuff */
45 PAVISTREAM pStream;
46 AVISTREAMINFOW sInfo;
48 HACMSTREAM has;
50 LPWAVEFORMATEX lpInFormat;
51 LONG cbInFormat;
53 LPWAVEFORMATEX lpOutFormat;
54 LONG cbOutFormat;
56 ACMSTREAMHEADER acmStreamHdr;
57 } IAVIStreamImpl;
59 /***********************************************************************/
61 #define CONVERT_STREAM_to_THIS(a) do { \
62 DWORD __bytes; \
63 acmStreamSize(This->has,*(a) * This->lpInFormat->nBlockAlign,\
64 &__bytes, ACM_STREAMSIZEF_SOURCE); \
65 *(a) = __bytes / This->lpOutFormat->nBlockAlign; } while(0)
67 #define CONVERT_THIS_to_STREAM(a) do { \
68 DWORD __bytes; \
69 acmStreamSize(This->has,*(a) * This->lpOutFormat->nBlockAlign,\
70 &__bytes, ACM_STREAMSIZEF_DESTINATION); \
71 *(a) = __bytes / This->lpInFormat->nBlockAlign; } while(0)
73 static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This)
75 HRESULT hr;
77 /* pre-conditions */
78 assert(This != NULL);
79 assert(This->pStream != NULL);
81 if (This->has != NULL)
82 return AVIERR_OK;
84 if (This->lpInFormat == NULL) {
85 /* decode or encode the data from pStream */
86 hr = AVIStreamFormatSize(This->pStream, This->sInfo.dwStart, &This->cbInFormat);
87 if (FAILED(hr))
88 return hr;
89 This->lpInFormat = malloc(This->cbInFormat);
90 if (This->lpInFormat == NULL)
91 return AVIERR_MEMORY;
93 hr = IAVIStream_ReadFormat(This->pStream, This->sInfo.dwStart,
94 This->lpInFormat, &This->cbInFormat);
95 if (FAILED(hr))
96 return hr;
98 if (This->lpOutFormat == NULL) {
99 /* we must decode to default format */
100 This->cbOutFormat = sizeof(WAVEFORMATEX);
101 This->lpOutFormat = malloc(This->cbOutFormat);
102 if (This->lpOutFormat == NULL)
103 return AVIERR_MEMORY;
105 This->lpOutFormat->wFormatTag = WAVE_FORMAT_PCM;
106 if (acmFormatSuggest(NULL, This->lpInFormat, This->lpOutFormat,
107 This->cbOutFormat, ACM_FORMATSUGGESTF_WFORMATTAG) != S_OK)
108 return AVIERR_NOCOMPRESSOR;
110 } else if (This->lpOutFormat == NULL)
111 return AVIERR_ERROR; /* To what should I encode? */
113 if (acmStreamOpen(&This->has, NULL, This->lpInFormat, This->lpOutFormat,
114 NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME) != S_OK)
115 return AVIERR_NOCOMPRESSOR;
117 /* update AVISTREAMINFO structure */
118 This->sInfo.dwSampleSize = This->lpOutFormat->nBlockAlign;
119 This->sInfo.dwScale = This->lpOutFormat->nBlockAlign;
120 This->sInfo.dwRate = This->lpOutFormat->nAvgBytesPerSec;
121 This->sInfo.dwQuality = (DWORD)ICQUALITY_DEFAULT;
122 SetRectEmpty(&This->sInfo.rcFrame);
124 /* convert positions and sizes to output format */
125 CONVERT_STREAM_to_THIS(&This->sInfo.dwStart);
126 CONVERT_STREAM_to_THIS(&This->sInfo.dwLength);
127 CONVERT_STREAM_to_THIS(&This->sInfo.dwSuggestedBufferSize);
129 return AVIERR_OK;
132 static inline IAVIStreamImpl *impl_from_IAVIStream(IAVIStream *iface)
134 return CONTAINING_RECORD(iface, IAVIStreamImpl, IAVIStream_iface);
137 static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream *iface,
138 REFIID refiid, LPVOID *obj)
140 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
142 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
144 if (IsEqualGUID(&IID_IUnknown, refiid) ||
145 IsEqualGUID(&IID_IAVIStream, refiid)) {
146 *obj = &This->IAVIStream_iface;
147 IAVIStream_AddRef(iface);
149 return S_OK;
152 return OLE_E_ENUM_NOMORE;
155 static ULONG WINAPI ACMStream_fnAddRef(IAVIStream *iface)
157 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
158 ULONG ref = InterlockedIncrement(&This->ref);
160 TRACE("(%p) -> %ld\n", iface, ref);
162 /* also add reference to the nested stream */
163 if (This->pStream != NULL)
164 IAVIStream_AddRef(This->pStream);
166 return ref;
169 static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface)
171 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
172 ULONG ref = InterlockedDecrement(&This->ref);
174 TRACE("(%p) -> %ld\n", iface, ref);
176 if (ref == 0) {
177 /* destruct */
178 if (This->has != NULL) {
179 if (This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
180 acmStreamUnprepareHeader(This->has, &This->acmStreamHdr, 0);
181 acmStreamClose(This->has, 0);
182 This->has = NULL;
184 free(This->acmStreamHdr.pbSrc);
185 This->acmStreamHdr.pbSrc = NULL;
186 free(This->acmStreamHdr.pbDst);
187 This->acmStreamHdr.pbDst = NULL;
188 if (This->lpInFormat != NULL) {
189 free(This->lpInFormat);
190 This->lpInFormat = NULL;
191 This->cbInFormat = 0;
193 if (This->lpOutFormat != NULL) {
194 free(This->lpOutFormat);
195 This->lpOutFormat = NULL;
196 This->cbOutFormat = 0;
198 if (This->pStream != NULL) {
199 IAVIStream_Release(This->pStream);
200 This->pStream = NULL;
202 free(This);
204 return 0;
207 /* also release reference to the nested stream */
208 if (This->pStream != NULL)
209 IAVIStream_Release(This->pStream);
211 return ref;
214 /* lParam1: PAVISTREAM
215 * lParam2: LPAVICOMPRESSOPTIONS -- even if doc's say LPWAVEFORMAT
217 static HRESULT WINAPI ACMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
218 LPARAM lParam2)
220 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
222 TRACE("(%p,0x%08IX,0x%08IX)\n", iface, lParam1, lParam2);
224 /* check for swapped parameters */
225 if ((LPVOID)lParam1 != NULL &&
226 ((LPAVICOMPRESSOPTIONS)lParam1)->fccType == streamtypeAUDIO) {
227 LPARAM tmp = lParam1;
229 lParam1 = lParam2;
230 lParam2 = tmp;
233 if ((LPVOID)lParam1 == NULL)
234 return AVIERR_BADPARAM;
236 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
237 if (This->sInfo.fccType != streamtypeAUDIO)
238 return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
240 This->sInfo.fccHandler = 0; /* be paranoid */
242 /* FIXME: check ACM version? Which version does we need? */
244 if ((LPVOID)lParam2 != NULL) {
245 /* We only need the format from the compress-options */
246 if (((LPAVICOMPRESSOPTIONS)lParam2)->fccType == streamtypeAUDIO)
247 lParam2 = (LPARAM)((LPAVICOMPRESSOPTIONS)lParam2)->lpFormat;
249 if (((LPWAVEFORMATEX)lParam2)->wFormatTag != WAVE_FORMAT_PCM)
250 This->cbOutFormat = sizeof(WAVEFORMATEX) + ((LPWAVEFORMATEX)lParam2)->cbSize;
251 else
252 This->cbOutFormat = sizeof(WAVEFORMATEX);
254 This->lpOutFormat = malloc(This->cbOutFormat);
255 if (This->lpOutFormat == NULL)
256 return AVIERR_MEMORY;
258 memcpy(This->lpOutFormat, (LPVOID)lParam2, This->cbOutFormat);
259 } else {
260 This->lpOutFormat = NULL;
261 This->cbOutFormat = 0;
264 This->pStream = (PAVISTREAM)lParam1;
265 IAVIStream_AddRef(This->pStream);
267 return AVIERR_OK;
270 static HRESULT WINAPI ACMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
271 LONG size)
273 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
275 TRACE("(%p,%p,%ld)\n", iface, psi, size);
277 if (psi == NULL)
278 return AVIERR_BADPARAM;
279 if (size < 0)
280 return AVIERR_BADSIZE;
282 /* Need codec to correct some values in structure */
283 if (This->has == NULL) {
284 HRESULT hr = AVIFILE_OpenCompressor(This);
286 if (FAILED(hr))
287 return hr;
290 memcpy(psi, &This->sInfo, min(size, (LONG)sizeof(This->sInfo)));
292 if (size < (LONG)sizeof(This->sInfo))
293 return AVIERR_BUFFERTOOSMALL;
294 return AVIERR_OK;
297 static LONG WINAPI ACMStream_fnFindSample(IAVIStream *iface, LONG pos,
298 LONG flags)
300 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
302 TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
304 if (flags & FIND_FROM_START) {
305 pos = This->sInfo.dwStart;
306 flags &= ~(FIND_FROM_START|FIND_PREV);
307 flags |= FIND_NEXT;
310 /* convert pos from our 'space' to This->pStream's one */
311 CONVERT_THIS_to_STREAM(&pos);
313 /* ask stream */
314 pos = IAVIStream_FindSample(This->pStream, pos, flags);
316 if (pos != -1) {
317 /* convert pos back to our 'space' if it's no size or physical pos */
318 if ((flags & FIND_RET) == 0)
319 CONVERT_STREAM_to_THIS(&pos);
322 return pos;
325 static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream *iface, LONG pos,
326 LPVOID format, LONG *formatsize)
328 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
330 TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
332 if (formatsize == NULL)
333 return AVIERR_BADPARAM;
335 if (This->has == NULL) {
336 HRESULT hr = AVIFILE_OpenCompressor(This);
338 if (FAILED(hr))
339 return hr;
342 /* only interested in needed buffersize? */
343 if (format == NULL || *formatsize <= 0) {
344 *formatsize = This->cbOutFormat;
346 return AVIERR_OK;
349 /* copy initial format (only as much as will fit) */
350 memcpy(format, This->lpOutFormat, min(*formatsize, This->cbOutFormat));
351 if (*formatsize < This->cbOutFormat) {
352 *formatsize = This->cbOutFormat;
353 return AVIERR_BUFFERTOOSMALL;
356 *formatsize = This->cbOutFormat;
357 return AVIERR_OK;
360 static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream *iface, LONG pos,
361 LPVOID format, LONG formatsize)
363 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
365 HRESULT hr;
367 TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
369 /* check parameters */
370 if (format == NULL || formatsize <= 0)
371 return AVIERR_BADPARAM;
373 /* Input format already known?
374 * Changing is unsupported, but be quiet if it's the same */
375 if (This->lpInFormat != NULL) {
376 if (This->cbInFormat != formatsize ||
377 memcmp(format, This->lpInFormat, formatsize) != 0)
378 return AVIERR_UNSUPPORTED;
380 return AVIERR_OK;
383 /* Does the nested stream support writing? */
384 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
385 return AVIERR_READONLY;
387 This->lpInFormat = malloc(formatsize);
388 if (This->lpInFormat == NULL)
389 return AVIERR_MEMORY;
390 This->cbInFormat = formatsize;
391 memcpy(This->lpInFormat, format, formatsize);
393 /* initialize formats and get compressor */
394 hr = AVIFILE_OpenCompressor(This);
395 if (FAILED(hr))
396 return hr;
398 CONVERT_THIS_to_STREAM(&pos);
400 /* tell the nested stream the new format */
401 return IAVIStream_SetFormat(This->pStream, pos, This->lpOutFormat,
402 This->cbOutFormat);
405 static HRESULT WINAPI ACMStream_fnRead(IAVIStream *iface, LONG start,
406 LONG samples, LPVOID buffer,
407 LONG buffersize, LPLONG bytesread,
408 LPLONG samplesread)
410 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
412 HRESULT hr;
413 DWORD size;
415 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
416 buffersize, bytesread, samplesread);
418 /* clear return parameters if given */
419 if (bytesread != NULL)
420 *bytesread = 0;
421 if (samplesread != NULL)
422 *samplesread = 0;
424 /* Do we have our compressor? */
425 if (This->has == NULL) {
426 hr = AVIFILE_OpenCompressor(This);
428 if (FAILED(hr))
429 return hr;
432 /* only need to pass through? */
433 if (This->cbInFormat == This->cbOutFormat &&
434 memcmp(This->lpInFormat, This->lpOutFormat, This->cbInFormat) == 0) {
435 return IAVIStream_Read(This->pStream, start, samples, buffer, buffersize,
436 bytesread, samplesread);
439 /* read as much as fit? */
440 if (samples == -1)
441 samples = buffersize / This->lpOutFormat->nBlockAlign;
442 /* limit to buffersize */
443 if (samples * This->lpOutFormat->nBlockAlign > buffersize)
444 samples = buffersize / This->lpOutFormat->nBlockAlign;
446 /* only return needed size? */
447 if (buffer == NULL || buffersize <= 0 || samples == 0) {
448 if (bytesread == NULL && samplesread == NULL)
449 return AVIERR_BADPARAM;
451 if (bytesread != NULL)
452 *bytesread = samples * This->lpOutFormat->nBlockAlign;
453 if (samplesread != NULL)
454 *samplesread = samples;
456 return AVIERR_OK;
459 /* map our positions to pStream positions */
460 CONVERT_THIS_to_STREAM(&start);
462 /* our needed internal buffersize */
463 size = samples * This->lpInFormat->nBlockAlign;
465 /* Need to free destination buffer used for writing? */
466 if (This->acmStreamHdr.pbDst != NULL) {
467 free(This->acmStreamHdr.pbDst);
468 This->acmStreamHdr.pbDst = NULL;
469 This->acmStreamHdr.dwDstUser = 0;
472 /* need bigger source buffer? */
473 if (This->acmStreamHdr.pbSrc == NULL ||
474 This->acmStreamHdr.dwSrcUser < size) {
475 This->acmStreamHdr.pbSrc = realloc(This->acmStreamHdr.pbSrc, size);
476 if (This->acmStreamHdr.pbSrc == NULL)
477 return AVIERR_MEMORY;
478 This->acmStreamHdr.dwSrcUser = size;
481 This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
482 This->acmStreamHdr.cbSrcLengthUsed = 0;
483 This->acmStreamHdr.cbDstLengthUsed = 0;
484 This->acmStreamHdr.cbSrcLength = size;
486 /* read source data */
487 hr = IAVIStream_Read(This->pStream, start, -1, This->acmStreamHdr.pbSrc,
488 This->acmStreamHdr.cbSrcLength,
489 (LONG *)&This->acmStreamHdr.cbSrcLength, NULL);
490 if (FAILED(hr) || This->acmStreamHdr.cbSrcLength == 0)
491 return hr;
493 /* need to prepare stream? */
494 This->acmStreamHdr.pbDst = buffer;
495 This->acmStreamHdr.cbDstLength = buffersize;
496 if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
497 if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
498 This->acmStreamHdr.pbDst = NULL;
499 This->acmStreamHdr.cbDstLength = 0;
500 return AVIERR_COMPRESSOR;
504 /* now do the conversion */
505 /* FIXME: use ACM_CONVERTF_* flags */
506 if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
507 hr = AVIERR_COMPRESSOR;
509 This->acmStreamHdr.pbDst = NULL;
510 This->acmStreamHdr.cbDstLength = 0;
512 /* fill out return parameters if given */
513 if (bytesread != NULL)
514 *bytesread = This->acmStreamHdr.cbDstLengthUsed;
515 if (samplesread != NULL)
516 *samplesread =
517 This->acmStreamHdr.cbDstLengthUsed / This->lpOutFormat->nBlockAlign;
519 return hr;
522 static HRESULT WINAPI ACMStream_fnWrite(IAVIStream *iface, LONG start,
523 LONG samples, LPVOID buffer,
524 LONG buffersize, DWORD flags,
525 LPLONG sampwritten,
526 LPLONG byteswritten)
528 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
530 HRESULT hr;
531 ULONG size;
533 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
534 buffer, buffersize, flags, sampwritten, byteswritten);
536 /* clear return parameters if given */
537 if (sampwritten != NULL)
538 *sampwritten = 0;
539 if (byteswritten != NULL)
540 *byteswritten = 0;
542 /* check parameters */
543 if (buffer == NULL && (buffersize > 0 || samples > 0))
544 return AVIERR_BADPARAM;
546 /* Have we write capability? */
547 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
548 return AVIERR_READONLY;
550 /* also need a compressor */
551 if (This->has == NULL)
552 return AVIERR_NOCOMPRESSOR;
554 /* map our sizes to pStream sizes */
555 size = buffersize;
556 CONVERT_THIS_to_STREAM(&size);
557 CONVERT_THIS_to_STREAM(&start);
559 /* no bytes to write? -- short circuit */
560 if (size == 0) {
561 return IAVIStream_Write(This->pStream, -1, samples, buffer, size,
562 flags, sampwritten, byteswritten);
565 /* Need to free source buffer used for reading? */
566 if (This->acmStreamHdr.pbSrc != NULL) {
567 free(This->acmStreamHdr.pbSrc);
568 This->acmStreamHdr.pbSrc = NULL;
569 This->acmStreamHdr.dwSrcUser = 0;
572 /* Need bigger destination buffer? */
573 if (This->acmStreamHdr.pbDst == NULL ||
574 This->acmStreamHdr.dwDstUser < size) {
575 This->acmStreamHdr.pbDst = realloc(This->acmStreamHdr.pbDst, size);
576 if (This->acmStreamHdr.pbDst == NULL)
577 return AVIERR_MEMORY;
578 This->acmStreamHdr.dwDstUser = size;
580 This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
581 This->acmStreamHdr.cbSrcLengthUsed = 0;
582 This->acmStreamHdr.cbDstLengthUsed = 0;
583 This->acmStreamHdr.cbDstLength = This->acmStreamHdr.dwDstUser;
585 /* need to prepare stream? */
586 This->acmStreamHdr.pbSrc = buffer;
587 This->acmStreamHdr.cbSrcLength = buffersize;
588 if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
589 if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
590 This->acmStreamHdr.pbSrc = NULL;
591 This->acmStreamHdr.cbSrcLength = 0;
592 return AVIERR_COMPRESSOR;
596 /* now do the conversion */
597 /* FIXME: use ACM_CONVERTF_* flags */
598 if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
599 hr = AVIERR_COMPRESSOR;
600 else
601 hr = AVIERR_OK;
603 This->acmStreamHdr.pbSrc = NULL;
604 This->acmStreamHdr.cbSrcLength = 0;
606 if (FAILED(hr))
607 return hr;
609 return IAVIStream_Write(This->pStream,-1,This->acmStreamHdr.cbDstLengthUsed /
610 This->lpOutFormat->nBlockAlign,This->acmStreamHdr.pbDst,
611 This->acmStreamHdr.cbDstLengthUsed,flags,sampwritten,
612 byteswritten);
615 static HRESULT WINAPI ACMStream_fnDelete(IAVIStream *iface, LONG start,
616 LONG samples)
618 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
620 TRACE("(%p,%ld,%ld)\n", iface, start, samples);
622 /* check parameters */
623 if (start < 0 || samples < 0)
624 return AVIERR_BADPARAM;
626 /* Delete before start of stream? */
627 if ((DWORD)(start + samples) < This->sInfo.dwStart)
628 return AVIERR_OK;
630 /* Delete after end of stream? */
631 if ((DWORD)start > This->sInfo.dwLength)
632 return AVIERR_OK;
634 /* For the rest we need write capability */
635 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
636 return AVIERR_READONLY;
638 /* A compressor is also necessary */
639 if (This->has == NULL)
640 return AVIERR_NOCOMPRESSOR;
642 /* map our positions to pStream positions */
643 CONVERT_THIS_to_STREAM(&start);
644 CONVERT_THIS_to_STREAM(&samples);
646 return IAVIStream_Delete(This->pStream, start, samples);
649 static HRESULT WINAPI ACMStream_fnReadData(IAVIStream *iface, DWORD fcc,
650 LPVOID lp, LPLONG lpread)
652 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
654 TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
656 assert(This->pStream != NULL);
658 return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
661 static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
662 LPVOID lp, LONG size)
664 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
666 TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
668 assert(This->pStream != NULL);
670 return IAVIStream_WriteData(This->pStream, fcc, lp, size);
673 static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream *iface,
674 LPAVISTREAMINFOW info, LONG infolen)
676 FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
678 return E_FAIL;
681 static const struct IAVIStreamVtbl iacmst = {
682 ACMStream_fnQueryInterface,
683 ACMStream_fnAddRef,
684 ACMStream_fnRelease,
685 ACMStream_fnCreate,
686 ACMStream_fnInfo,
687 ACMStream_fnFindSample,
688 ACMStream_fnReadFormat,
689 ACMStream_fnSetFormat,
690 ACMStream_fnRead,
691 ACMStream_fnWrite,
692 ACMStream_fnDelete,
693 ACMStream_fnReadData,
694 ACMStream_fnWriteData,
695 ACMStream_fnSetInfo
698 HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppv)
700 IAVIStreamImpl *pstream;
701 HRESULT hr;
703 assert(riid != NULL && ppv != NULL);
705 *ppv = NULL;
707 pstream = calloc(1, sizeof(IAVIStreamImpl));
708 if (pstream == NULL)
709 return AVIERR_MEMORY;
711 pstream->IAVIStream_iface.lpVtbl = &iacmst;
713 hr = IAVIStream_QueryInterface(&pstream->IAVIStream_iface, riid, ppv);
714 if (FAILED(hr))
715 free(pstream);
717 return hr;