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