Sync with trunk r58740.
[reactos.git] / dll / win32 / avifil32 / acmstream.c
1 /*
2 * Copyright 2002 Michael Günnewig
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #include <assert.h>
24 #include <stdarg.h>
25
26 #include <windef.h>
27 #include <winbase.h>
28 #include <wingdi.h>
29 //#include "winuser.h"
30 //#include "winerror.h"
31 //#include "mmsystem.h"
32 #include <vfw.h>
33 //#include "msacm.h"
34
35 //#include "avifile_private.h"
36
37 #include <wine/debug.h>
38
39 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
40
41 /***********************************************************************/
42
43 typedef struct _IAVIStreamImpl {
44 /* IUnknown stuff */
45 IAVIStream IAVIStream_iface;
46 LONG ref;
47
48 /* IAVIStream stuff */
49 PAVISTREAM pStream;
50 AVISTREAMINFOW sInfo;
51
52 HACMSTREAM has;
53
54 LPWAVEFORMATEX lpInFormat;
55 LONG cbInFormat;
56
57 LPWAVEFORMATEX lpOutFormat;
58 LONG cbOutFormat;
59
60 ACMSTREAMHEADER acmStreamHdr;
61 } IAVIStreamImpl;
62
63 /***********************************************************************/
64
65 #define CONVERT_STREAM_to_THIS(a) do { \
66 DWORD __bytes; \
67 acmStreamSize(This->has,*(a) * This->lpInFormat->nBlockAlign,\
68 &__bytes, ACM_STREAMSIZEF_SOURCE); \
69 *(a) = __bytes / This->lpOutFormat->nBlockAlign; } while(0)
70
71 #define CONVERT_THIS_to_STREAM(a) do { \
72 DWORD __bytes; \
73 acmStreamSize(This->has,*(a) * This->lpOutFormat->nBlockAlign,\
74 &__bytes, ACM_STREAMSIZEF_DESTINATION); \
75 *(a) = __bytes / This->lpInFormat->nBlockAlign; } while(0)
76
77 static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This)
78 {
79 HRESULT hr;
80
81 /* pre-conditions */
82 assert(This != NULL);
83 assert(This->pStream != NULL);
84
85 if (This->has != NULL)
86 return AVIERR_OK;
87
88 if (This->lpInFormat == NULL) {
89 /* decode or encode the data from pStream */
90 hr = AVIStreamFormatSize(This->pStream, This->sInfo.dwStart, &This->cbInFormat);
91 if (FAILED(hr))
92 return hr;
93 This->lpInFormat = HeapAlloc(GetProcessHeap(), 0, This->cbInFormat);
94 if (This->lpInFormat == NULL)
95 return AVIERR_MEMORY;
96
97 hr = IAVIStream_ReadFormat(This->pStream, This->sInfo.dwStart,
98 This->lpInFormat, &This->cbInFormat);
99 if (FAILED(hr))
100 return hr;
101
102 if (This->lpOutFormat == NULL) {
103 /* we must decode to default format */
104 This->cbOutFormat = sizeof(PCMWAVEFORMAT);
105 This->lpOutFormat = HeapAlloc(GetProcessHeap(), 0, This->cbOutFormat);
106 if (This->lpOutFormat == NULL)
107 return AVIERR_MEMORY;
108
109 This->lpOutFormat->wFormatTag = WAVE_FORMAT_PCM;
110 if (acmFormatSuggest(NULL, This->lpInFormat, This->lpOutFormat,
111 This->cbOutFormat, ACM_FORMATSUGGESTF_WFORMATTAG) != S_OK)
112 return AVIERR_NOCOMPRESSOR;
113 }
114 } else if (This->lpOutFormat == NULL)
115 return AVIERR_ERROR; /* To what should I encode? */
116
117 if (acmStreamOpen(&This->has, NULL, This->lpInFormat, This->lpOutFormat,
118 NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME) != S_OK)
119 return AVIERR_NOCOMPRESSOR;
120
121 /* update AVISTREAMINFO structure */
122 This->sInfo.dwSampleSize = This->lpOutFormat->nBlockAlign;
123 This->sInfo.dwScale = This->lpOutFormat->nBlockAlign;
124 This->sInfo.dwRate = This->lpOutFormat->nAvgBytesPerSec;
125 This->sInfo.dwQuality = (DWORD)ICQUALITY_DEFAULT;
126 SetRectEmpty(&This->sInfo.rcFrame);
127
128 /* convert positions and sizes to output format */
129 CONVERT_STREAM_to_THIS(&This->sInfo.dwStart);
130 CONVERT_STREAM_to_THIS(&This->sInfo.dwLength);
131 CONVERT_STREAM_to_THIS(&This->sInfo.dwSuggestedBufferSize);
132
133 return AVIERR_OK;
134 }
135
136 static inline IAVIStreamImpl *impl_from_IAVIStream(IAVIStream *iface)
137 {
138 return CONTAINING_RECORD(iface, IAVIStreamImpl, IAVIStream_iface);
139 }
140
141 static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream *iface,
142 REFIID refiid, LPVOID *obj)
143 {
144 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
145
146 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
147
148 if (IsEqualGUID(&IID_IUnknown, refiid) ||
149 IsEqualGUID(&IID_IAVIStream, refiid)) {
150 *obj = This;
151 IAVIStream_AddRef(iface);
152
153 return S_OK;
154 }
155
156 return OLE_E_ENUM_NOMORE;
157 }
158
159 static ULONG WINAPI ACMStream_fnAddRef(IAVIStream *iface)
160 {
161 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
162 ULONG ref = InterlockedIncrement(&This->ref);
163
164 TRACE("(%p) -> %d\n", iface, ref);
165
166 /* also add reference to the nested stream */
167 if (This->pStream != NULL)
168 IAVIStream_AddRef(This->pStream);
169
170 return ref;
171 }
172
173 static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface)
174 {
175 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
176 ULONG ref = InterlockedDecrement(&This->ref);
177
178 TRACE("(%p) -> %d\n", iface, ref);
179
180 if (ref == 0) {
181 /* destruct */
182 if (This->has != NULL) {
183 if (This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
184 acmStreamUnprepareHeader(This->has, &This->acmStreamHdr, 0);
185 acmStreamClose(This->has, 0);
186 This->has = NULL;
187 }
188 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc);
189 This->acmStreamHdr.pbSrc = NULL;
190 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbDst);
191 This->acmStreamHdr.pbDst = NULL;
192 if (This->lpInFormat != NULL) {
193 HeapFree(GetProcessHeap(), 0, This->lpInFormat);
194 This->lpInFormat = NULL;
195 This->cbInFormat = 0;
196 }
197 if (This->lpOutFormat != NULL) {
198 HeapFree(GetProcessHeap(), 0, This->lpOutFormat);
199 This->lpOutFormat = NULL;
200 This->cbOutFormat = 0;
201 }
202 if (This->pStream != NULL) {
203 IAVIStream_Release(This->pStream);
204 This->pStream = NULL;
205 }
206 HeapFree(GetProcessHeap(), 0, This);
207
208 return 0;
209 }
210
211 /* also release reference to the nested stream */
212 if (This->pStream != NULL)
213 IAVIStream_Release(This->pStream);
214
215 return ref;
216 }
217
218 /* lParam1: PAVISTREAM
219 * lParam2: LPAVICOMPRESSOPTIONS -- even if doc's say LPWAVEFORMAT
220 */
221 static HRESULT WINAPI ACMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
222 LPARAM lParam2)
223 {
224 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
225
226 TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
227
228 /* check for swapped parameters */
229 if ((LPVOID)lParam1 != NULL &&
230 ((LPAVICOMPRESSOPTIONS)lParam1)->fccType == streamtypeAUDIO) {
231 register LPARAM tmp = lParam1;
232
233 lParam1 = lParam2;
234 lParam2 = tmp;
235 }
236
237 if ((LPVOID)lParam1 == NULL)
238 return AVIERR_BADPARAM;
239
240 IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
241 if (This->sInfo.fccType != streamtypeAUDIO)
242 return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
243
244 This->sInfo.fccHandler = 0; /* be paranoid */
245
246 /* FIXME: check ACM version? Which version does we need? */
247
248 if ((LPVOID)lParam2 != NULL) {
249 /* We only need the format from the compress-options */
250 if (((LPAVICOMPRESSOPTIONS)lParam2)->fccType == streamtypeAUDIO)
251 lParam2 = (LPARAM)((LPAVICOMPRESSOPTIONS)lParam2)->lpFormat;
252
253 if (((LPWAVEFORMATEX)lParam2)->wFormatTag != WAVE_FORMAT_PCM)
254 This->cbOutFormat = sizeof(WAVEFORMATEX) + ((LPWAVEFORMATEX)lParam2)->cbSize;
255 else
256 This->cbOutFormat = sizeof(PCMWAVEFORMAT);
257
258 This->lpOutFormat = HeapAlloc(GetProcessHeap(), 0, This->cbOutFormat);
259 if (This->lpOutFormat == NULL)
260 return AVIERR_MEMORY;
261
262 memcpy(This->lpOutFormat, (LPVOID)lParam2, This->cbOutFormat);
263 } else {
264 This->lpOutFormat = NULL;
265 This->cbOutFormat = 0;
266 }
267
268 This->pStream = (PAVISTREAM)lParam1;
269 IAVIStream_AddRef(This->pStream);
270
271 return AVIERR_OK;
272 }
273
274 static HRESULT WINAPI ACMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
275 LONG size)
276 {
277 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
278
279 TRACE("(%p,%p,%d)\n", iface, psi, size);
280
281 if (psi == NULL)
282 return AVIERR_BADPARAM;
283 if (size < 0)
284 return AVIERR_BADSIZE;
285
286 /* Need codec to correct some values in structure */
287 if (This->has == NULL) {
288 HRESULT hr = AVIFILE_OpenCompressor(This);
289
290 if (FAILED(hr))
291 return hr;
292 }
293
294 memcpy(psi, &This->sInfo, min(size, (LONG)sizeof(This->sInfo)));
295
296 if (size < (LONG)sizeof(This->sInfo))
297 return AVIERR_BUFFERTOOSMALL;
298 return AVIERR_OK;
299 }
300
301 static LONG WINAPI ACMStream_fnFindSample(IAVIStream *iface, LONG pos,
302 LONG flags)
303 {
304 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
305
306 TRACE("(%p,%d,0x%08X)\n",iface,pos,flags);
307
308 if (flags & FIND_FROM_START) {
309 pos = This->sInfo.dwStart;
310 flags &= ~(FIND_FROM_START|FIND_PREV);
311 flags |= FIND_NEXT;
312 }
313
314 /* convert pos from our 'space' to This->pStream's one */
315 CONVERT_THIS_to_STREAM(&pos);
316
317 /* ask stream */
318 pos = IAVIStream_FindSample(This->pStream, pos, flags);
319
320 if (pos != -1) {
321 /* convert pos back to our 'space' if it's no size or physical pos */
322 if ((flags & FIND_RET) == 0)
323 CONVERT_STREAM_to_THIS(&pos);
324 }
325
326 return pos;
327 }
328
329 static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream *iface, LONG pos,
330 LPVOID format, LONG *formatsize)
331 {
332 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
333
334 TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
335
336 if (formatsize == NULL)
337 return AVIERR_BADPARAM;
338
339 if (This->has == NULL) {
340 HRESULT hr = AVIFILE_OpenCompressor(This);
341
342 if (FAILED(hr))
343 return hr;
344 }
345
346 /* only interested in needed buffersize? */
347 if (format == NULL || *formatsize <= 0) {
348 *formatsize = This->cbOutFormat;
349
350 return AVIERR_OK;
351 }
352
353 /* copy initial format (only as much as will fit) */
354 memcpy(format, This->lpOutFormat, min(*formatsize, This->cbOutFormat));
355 if (*formatsize < This->cbOutFormat) {
356 *formatsize = This->cbOutFormat;
357 return AVIERR_BUFFERTOOSMALL;
358 }
359
360 *formatsize = This->cbOutFormat;
361 return AVIERR_OK;
362 }
363
364 static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream *iface, LONG pos,
365 LPVOID format, LONG formatsize)
366 {
367 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
368
369 HRESULT hr;
370
371 TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
372
373 /* check parameters */
374 if (format == NULL || formatsize <= 0)
375 return AVIERR_BADPARAM;
376
377 /* Input format already known?
378 * Changing is unsupported, but be quiet if it's the same */
379 if (This->lpInFormat != NULL) {
380 if (This->cbInFormat != formatsize ||
381 memcmp(format, This->lpInFormat, formatsize) != 0)
382 return AVIERR_UNSUPPORTED;
383
384 return AVIERR_OK;
385 }
386
387 /* Does the nested stream support writing? */
388 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
389 return AVIERR_READONLY;
390
391 This->lpInFormat = HeapAlloc(GetProcessHeap(), 0, formatsize);
392 if (This->lpInFormat == NULL)
393 return AVIERR_MEMORY;
394 This->cbInFormat = formatsize;
395 memcpy(This->lpInFormat, format, formatsize);
396
397 /* initialize formats and get compressor */
398 hr = AVIFILE_OpenCompressor(This);
399 if (FAILED(hr))
400 return hr;
401
402 CONVERT_THIS_to_STREAM(&pos);
403
404 /* tell the nested stream the new format */
405 return IAVIStream_SetFormat(This->pStream, pos, This->lpOutFormat,
406 This->cbOutFormat);
407 }
408
409 static HRESULT WINAPI ACMStream_fnRead(IAVIStream *iface, LONG start,
410 LONG samples, LPVOID buffer,
411 LONG buffersize, LPLONG bytesread,
412 LPLONG samplesread)
413 {
414 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
415
416 HRESULT hr;
417 DWORD size;
418
419 TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface, start, samples, buffer,
420 buffersize, bytesread, samplesread);
421
422 /* clear return parameters if given */
423 if (bytesread != NULL)
424 *bytesread = 0;
425 if (samplesread != NULL)
426 *samplesread = 0;
427
428 /* Do we have our compressor? */
429 if (This->has == NULL) {
430 hr = AVIFILE_OpenCompressor(This);
431
432 if (FAILED(hr))
433 return hr;
434 }
435
436 /* only need to pass through? */
437 if (This->cbInFormat == This->cbOutFormat &&
438 memcmp(This->lpInFormat, This->lpOutFormat, This->cbInFormat) == 0) {
439 return IAVIStream_Read(This->pStream, start, samples, buffer, buffersize,
440 bytesread, samplesread);
441 }
442
443 /* read as much as fit? */
444 if (samples == -1)
445 samples = buffersize / This->lpOutFormat->nBlockAlign;
446 /* limit to buffersize */
447 if (samples * This->lpOutFormat->nBlockAlign > buffersize)
448 samples = buffersize / This->lpOutFormat->nBlockAlign;
449
450 /* only return needed size? */
451 if (buffer == NULL || buffersize <= 0 || samples == 0) {
452 if (bytesread == NULL && samplesread == NULL)
453 return AVIERR_BADPARAM;
454
455 if (bytesread != NULL)
456 *bytesread = samples * This->lpOutFormat->nBlockAlign;
457 if (samplesread != NULL)
458 *samplesread = samples;
459
460 return AVIERR_OK;
461 }
462
463 /* map our positions to pStream positions */
464 CONVERT_THIS_to_STREAM(&start);
465
466 /* our needed internal buffersize */
467 size = samples * This->lpInFormat->nBlockAlign;
468
469 /* Need to free destination buffer used for writing? */
470 if (This->acmStreamHdr.pbDst != NULL) {
471 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbDst);
472 This->acmStreamHdr.pbDst = NULL;
473 This->acmStreamHdr.dwDstUser = 0;
474 }
475
476 /* need bigger source buffer? */
477 if (This->acmStreamHdr.pbSrc == NULL ||
478 This->acmStreamHdr.dwSrcUser < size) {
479 if (This->acmStreamHdr.pbSrc == NULL)
480 This->acmStreamHdr.pbSrc = HeapAlloc(GetProcessHeap(), 0, size);
481 else
482 This->acmStreamHdr.pbSrc = HeapReAlloc(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc, size);
483 if (This->acmStreamHdr.pbSrc == NULL)
484 return AVIERR_MEMORY;
485 This->acmStreamHdr.dwSrcUser = size;
486 }
487
488 This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
489 This->acmStreamHdr.cbSrcLengthUsed = 0;
490 This->acmStreamHdr.cbDstLengthUsed = 0;
491 This->acmStreamHdr.cbSrcLength = size;
492
493 /* read source data */
494 hr = IAVIStream_Read(This->pStream, start, -1, This->acmStreamHdr.pbSrc,
495 This->acmStreamHdr.cbSrcLength,
496 (LONG *)&This->acmStreamHdr.cbSrcLength, NULL);
497 if (FAILED(hr) || This->acmStreamHdr.cbSrcLength == 0)
498 return hr;
499
500 /* need to prepare stream? */
501 This->acmStreamHdr.pbDst = buffer;
502 This->acmStreamHdr.cbDstLength = buffersize;
503 if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
504 if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
505 This->acmStreamHdr.pbDst = NULL;
506 This->acmStreamHdr.cbDstLength = 0;
507 return AVIERR_COMPRESSOR;
508 }
509 }
510
511 /* now do the conversion */
512 /* FIXME: use ACM_CONVERTF_* flags */
513 if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
514 hr = AVIERR_COMPRESSOR;
515
516 This->acmStreamHdr.pbDst = NULL;
517 This->acmStreamHdr.cbDstLength = 0;
518
519 /* fill out return parameters if given */
520 if (bytesread != NULL)
521 *bytesread = This->acmStreamHdr.cbDstLengthUsed;
522 if (samplesread != NULL)
523 *samplesread =
524 This->acmStreamHdr.cbDstLengthUsed / This->lpOutFormat->nBlockAlign;
525
526 return hr;
527 }
528
529 static HRESULT WINAPI ACMStream_fnWrite(IAVIStream *iface, LONG start,
530 LONG samples, LPVOID buffer,
531 LONG buffersize, DWORD flags,
532 LPLONG sampwritten,
533 LPLONG byteswritten)
534 {
535 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
536
537 HRESULT hr;
538 ULONG size;
539
540 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface, start, samples,
541 buffer, buffersize, flags, sampwritten, byteswritten);
542
543 /* clear return parameters if given */
544 if (sampwritten != NULL)
545 *sampwritten = 0;
546 if (byteswritten != NULL)
547 *byteswritten = 0;
548
549 /* check parameters */
550 if (buffer == NULL && (buffersize > 0 || samples > 0))
551 return AVIERR_BADPARAM;
552
553 /* Have we write capability? */
554 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
555 return AVIERR_READONLY;
556
557 /* also need a compressor */
558 if (This->has == NULL)
559 return AVIERR_NOCOMPRESSOR;
560
561 /* map our sizes to pStream sizes */
562 size = buffersize;
563 CONVERT_THIS_to_STREAM(&size);
564 CONVERT_THIS_to_STREAM(&start);
565
566 /* no bytes to write? -- short circuit */
567 if (size == 0) {
568 return IAVIStream_Write(This->pStream, -1, samples, buffer, size,
569 flags, sampwritten, byteswritten);
570 }
571
572 /* Need to free source buffer used for reading? */
573 if (This->acmStreamHdr.pbSrc != NULL) {
574 HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc);
575 This->acmStreamHdr.pbSrc = NULL;
576 This->acmStreamHdr.dwSrcUser = 0;
577 }
578
579 /* Need bigger destination buffer? */
580 if (This->acmStreamHdr.pbDst == NULL ||
581 This->acmStreamHdr.dwDstUser < size) {
582 if (This->acmStreamHdr.pbDst == NULL)
583 This->acmStreamHdr.pbDst = HeapAlloc(GetProcessHeap(), 0, size);
584 else
585 This->acmStreamHdr.pbDst = HeapReAlloc(GetProcessHeap(), 0, This->acmStreamHdr.pbDst, size);
586 if (This->acmStreamHdr.pbDst == NULL)
587 return AVIERR_MEMORY;
588 This->acmStreamHdr.dwDstUser = size;
589 }
590 This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
591 This->acmStreamHdr.cbSrcLengthUsed = 0;
592 This->acmStreamHdr.cbDstLengthUsed = 0;
593 This->acmStreamHdr.cbDstLength = This->acmStreamHdr.dwDstUser;
594
595 /* need to prepare stream? */
596 This->acmStreamHdr.pbSrc = buffer;
597 This->acmStreamHdr.cbSrcLength = buffersize;
598 if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
599 if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
600 This->acmStreamHdr.pbSrc = NULL;
601 This->acmStreamHdr.cbSrcLength = 0;
602 return AVIERR_COMPRESSOR;
603 }
604 }
605
606 /* now do the conversion */
607 /* FIXME: use ACM_CONVERTF_* flags */
608 if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
609 hr = AVIERR_COMPRESSOR;
610 else
611 hr = AVIERR_OK;
612
613 This->acmStreamHdr.pbSrc = NULL;
614 This->acmStreamHdr.cbSrcLength = 0;
615
616 if (FAILED(hr))
617 return hr;
618
619 return IAVIStream_Write(This->pStream,-1,This->acmStreamHdr.cbDstLengthUsed /
620 This->lpOutFormat->nBlockAlign,This->acmStreamHdr.pbDst,
621 This->acmStreamHdr.cbDstLengthUsed,flags,sampwritten,
622 byteswritten);
623 }
624
625 static HRESULT WINAPI ACMStream_fnDelete(IAVIStream *iface, LONG start,
626 LONG samples)
627 {
628 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
629
630 TRACE("(%p,%d,%d)\n", iface, start, samples);
631
632 /* check parameters */
633 if (start < 0 || samples < 0)
634 return AVIERR_BADPARAM;
635
636 /* Delete before start of stream? */
637 if ((DWORD)(start + samples) < This->sInfo.dwStart)
638 return AVIERR_OK;
639
640 /* Delete after end of stream? */
641 if ((DWORD)start > This->sInfo.dwLength)
642 return AVIERR_OK;
643
644 /* For the rest we need write capability */
645 if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
646 return AVIERR_READONLY;
647
648 /* A compressor is also necessary */
649 if (This->has == NULL)
650 return AVIERR_NOCOMPRESSOR;
651
652 /* map our positions to pStream positions */
653 CONVERT_THIS_to_STREAM(&start);
654 CONVERT_THIS_to_STREAM(&samples);
655
656 return IAVIStream_Delete(This->pStream, start, samples);
657 }
658
659 static HRESULT WINAPI ACMStream_fnReadData(IAVIStream *iface, DWORD fcc,
660 LPVOID lp, LPLONG lpread)
661 {
662 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
663
664 TRACE("(%p,0x%08X,%p,%p)\n", iface, fcc, lp, lpread);
665
666 assert(This->pStream != NULL);
667
668 return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
669 }
670
671 static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
672 LPVOID lp, LONG size)
673 {
674 IAVIStreamImpl *This = impl_from_IAVIStream(iface);
675
676 TRACE("(%p,0x%08x,%p,%d)\n", iface, fcc, lp, size);
677
678 assert(This->pStream != NULL);
679
680 return IAVIStream_WriteData(This->pStream, fcc, lp, size);
681 }
682
683 static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream *iface,
684 LPAVISTREAMINFOW info, LONG infolen)
685 {
686 FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
687
688 return E_FAIL;
689 }
690
691 static const struct IAVIStreamVtbl iacmst = {
692 ACMStream_fnQueryInterface,
693 ACMStream_fnAddRef,
694 ACMStream_fnRelease,
695 ACMStream_fnCreate,
696 ACMStream_fnInfo,
697 ACMStream_fnFindSample,
698 ACMStream_fnReadFormat,
699 ACMStream_fnSetFormat,
700 ACMStream_fnRead,
701 ACMStream_fnWrite,
702 ACMStream_fnDelete,
703 ACMStream_fnReadData,
704 ACMStream_fnWriteData,
705 ACMStream_fnSetInfo
706 };
707
708 HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppv)
709 {
710 IAVIStreamImpl *pstream;
711 HRESULT hr;
712
713 assert(riid != NULL && ppv != NULL);
714
715 *ppv = NULL;
716
717 pstream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIStreamImpl));
718 if (pstream == NULL)
719 return AVIERR_MEMORY;
720
721 pstream->IAVIStream_iface.lpVtbl = &iacmst;
722
723 hr = IAVIStream_QueryInterface(&pstream->IAVIStream_iface, riid, ppv);
724 if (FAILED(hr))
725 HeapFree(GetProcessHeap(), 0, pstream);
726
727 return hr;
728 }