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