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