2 * Copyright 2003 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
30 #include "avifile_private.h"
31 #include "extrachunk.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(avifile
);
38 /***********************************************************************/
40 /* internal interface to get access to table of stream in an editable stream */
42 DEFINE_AVIGUID(IID_IEditStreamInternal
, 0x0002000A,0,0);
44 typedef struct _EditStreamTable
{
45 PAVISTREAM pStream
; /* stream which contains the data */
46 DWORD dwStart
; /* where starts the part which is also our */
47 DWORD dwLength
; /* how many is also in this stream */
50 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
51 (This)->pStreams[streamNr].dwLength)
53 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl
;
55 struct _IAVIEditStreamImpl
{
56 IAVIEditStream IAVIEditStream_iface
;
57 IAVIStream IAVIStream_iface
;
63 EditStreamTable
*pStreams
;
64 DWORD nStreams
; /* current fill level of pStreams table */
65 DWORD nTableSize
; /* size of pStreams table */
68 PAVISTREAM pCurStream
;
69 PGETFRAME pg
; /* IGetFrame for pCurStream */
70 LPBITMAPINFOHEADER lpFrame
; /* frame of pCurStream */
73 static IAVIEditStreamImpl
*AVIFILE_CreateEditStream(IAVIStream
*stream
);
75 static inline IAVIEditStreamImpl
*impl_from_IAVIEditStream(IAVIEditStream
*iface
)
77 return CONTAINING_RECORD(iface
, IAVIEditStreamImpl
, IAVIEditStream_iface
);
80 static inline IAVIEditStreamImpl
*impl_from_IAVIStream(IAVIStream
*iface
)
82 return CONTAINING_RECORD(iface
, IAVIEditStreamImpl
, IAVIStream_iface
);
85 /***********************************************************************/
87 static HRESULT
AVIFILE_FindStreamInTable(IAVIEditStreamImpl
* const This
,
88 DWORD pos
,PAVISTREAM
*ppStream
,
90 DWORD
* streamNr
,BOOL bFindSample
)
94 TRACE("(%p,%lu,%p,%p,%p,%d)\n",This
,pos
,ppStream
,streamPos
,
95 streamNr
,bFindSample
);
97 if (pos
< This
->sInfo
.dwStart
)
98 return AVIERR_BADPARAM
;
100 pos
-= This
->sInfo
.dwStart
;
101 for (n
= 0; n
< This
->nStreams
; n
++) {
102 if (pos
< This
->pStreams
[n
].dwLength
) {
103 *ppStream
= This
->pStreams
[n
].pStream
;
104 *streamPos
= This
->pStreams
[n
].dwStart
+ pos
;
105 if (streamNr
!= NULL
)
110 pos
-= This
->pStreams
[n
].dwLength
;
112 if (pos
== 0 && bFindSample
) {
113 *ppStream
= This
->pStreams
[--n
].pStream
;
114 *streamPos
= EditStreamEnd(This
, n
);
115 if (streamNr
!= NULL
)
118 TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream
, *streamPos
, n
);
123 if (streamNr
!= NULL
)
126 TRACE(" -> ERROR (NULL,0,0)\n");
127 return AVIERR_BADPARAM
;
131 static LPVOID
AVIFILE_ReadFrame(IAVIEditStreamImpl
* const This
,
132 PAVISTREAM pstream
, LONG pos
)
136 TRACE("(%p,%p,%ld)\n",This
,pstream
,pos
);
141 /* if stream changes make sure that only palette changes */
142 if (This
->pCurStream
!= pstream
) {
143 pg
= AVIStreamGetFrameOpen(pstream
, NULL
);
146 if (This
->pg
!= NULL
) {
147 if (IGetFrame_SetFormat(pg
, This
->lpFrame
, NULL
, 0, 0, -1, -1) != S_OK
) {
148 AVIStreamGetFrameClose(pg
);
149 ERR(": IGetFrame_SetFormat failed\n");
152 AVIStreamGetFrameClose(This
->pg
);
155 This
->pCurStream
= pstream
;
158 /* now get the decompressed frame */
159 This
->lpFrame
= AVIStreamGetFrame(This
->pg
, pos
);
160 if (This
->lpFrame
!= NULL
)
161 This
->sInfo
.dwSuggestedBufferSize
= This
->lpFrame
->biSizeImage
;
163 return This
->lpFrame
;
166 static HRESULT
AVIFILE_RemoveStream(IAVIEditStreamImpl
* const This
, DWORD nr
)
168 assert(This
!= NULL
);
169 assert(nr
< This
->nStreams
);
172 IAVIStream_Release(This
->pStreams
[nr
].pStream
);
174 if (nr
< This
->nStreams
)
175 memmove(&This
->pStreams
[nr
], &This
->pStreams
[nr
+ 1],
176 (This
->nStreams
- nr
) * sizeof(This
->pStreams
[0]));
177 This
->pStreams
[This
->nStreams
].pStream
= NULL
;
178 This
->pStreams
[This
->nStreams
].dwStart
= 0;
179 This
->pStreams
[This
->nStreams
].dwLength
= 0;
181 /* try to merge the part before the deleted one and the one after it */
182 if (0 < nr
&& 0 < This
->nStreams
&&
183 This
->pStreams
[nr
- 1].pStream
== This
->pStreams
[nr
].pStream
) {
184 if (EditStreamEnd(This
, nr
- 1) == This
->pStreams
[nr
].dwStart
) {
185 This
->pStreams
[nr
- 1].dwLength
+= This
->pStreams
[nr
].dwLength
;
186 return AVIFILE_RemoveStream(This
, nr
);
193 static BOOL
AVIFILE_FormatsEqual(PAVISTREAM avi1
, PAVISTREAM avi2
)
195 LPVOID fmt1
= NULL
, fmt2
= NULL
;
196 LONG size1
, size2
, start1
, start2
;
199 assert(avi1
!= NULL
&& avi2
!= NULL
);
201 /* get stream starts and check format sizes */
202 start1
= AVIStreamStart(avi1
);
203 start2
= AVIStreamStart(avi2
);
204 if (FAILED(AVIStreamFormatSize(avi1
, start1
, &size1
)))
206 if (FAILED(AVIStreamFormatSize(avi2
, start2
, &size2
)))
211 /* sizes match, now get formats and compare them */
212 fmt1
= malloc(size1
);
215 if (SUCCEEDED(AVIStreamReadFormat(avi1
, start1
, fmt1
, &size1
))) {
216 fmt2
= malloc(size1
);
218 if (SUCCEEDED(AVIStreamReadFormat(avi2
, start2
, fmt2
, &size1
)))
219 status
= (memcmp(fmt1
, fmt2
, size1
) == 0);
229 /***********************************************************************/
231 static HRESULT WINAPI
IAVIEditStream_fnQueryInterface(IAVIEditStream
*iface
,REFIID refiid
,LPVOID
*obj
)
233 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
235 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(refiid
), obj
);
237 if (IsEqualGUID(&IID_IUnknown
, refiid
) ||
238 IsEqualGUID(&IID_IAVIEditStream
, refiid
) ||
239 IsEqualGUID(&IID_IEditStreamInternal
, refiid
)) {
241 IAVIEditStream_AddRef(iface
);
244 } else if (IsEqualGUID(&IID_IAVIStream
, refiid
)) {
245 *obj
= &This
->IAVIStream_iface
;
246 IAVIEditStream_AddRef(iface
);
251 return E_NOINTERFACE
;
254 static ULONG WINAPI
IAVIEditStream_fnAddRef(IAVIEditStream
*iface
)
256 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
257 ULONG ref
= InterlockedIncrement(&This
->ref
);
259 TRACE("(%p) -> %ld\n", iface
, ref
);
264 static ULONG WINAPI
IAVIEditStream_fnRelease(IAVIEditStream
*iface
)
266 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
268 ULONG ref
= InterlockedDecrement(&This
->ref
);
270 TRACE("(%p) -> %ld\n", iface
, ref
);
274 if (This
->pg
!= NULL
)
275 AVIStreamGetFrameClose(This
->pg
);
276 if (This
->pStreams
!= NULL
) {
277 for (i
= 0; i
< This
->nStreams
; i
++) {
278 if (This
->pStreams
[i
].pStream
!= NULL
)
279 IAVIStream_Release(This
->pStreams
[i
].pStream
);
281 free(This
->pStreams
);
289 static HRESULT WINAPI
IAVIEditStream_fnCut(IAVIEditStream
*iface
,LONG
*plStart
,
290 LONG
*plLength
,PAVISTREAM
*ppResult
)
292 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
294 DWORD start
, len
, streamPos
, streamNr
;
297 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
299 if (ppResult
!= NULL
)
301 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0)
302 return AVIERR_BADPARAM
;
304 /* if asked for cut part copy it before deleting */
305 if (ppResult
!= NULL
) {
306 hr
= IAVIEditStream_Copy(iface
, plStart
, plLength
, ppResult
);
314 /* now delete the requested part */
316 hr
= AVIFILE_FindStreamInTable(This
, start
, &stream
,
317 &streamPos
, &streamNr
, FALSE
);
320 if (This
->pStreams
[streamNr
].dwStart
== streamPos
) {
321 /* deleting from start of part */
322 if (len
< This
->pStreams
[streamNr
].dwLength
) {
324 This
->pStreams
[streamNr
].dwStart
+= len
;
325 This
->pStreams
[streamNr
].dwLength
-= len
;
326 This
->sInfo
.dwLength
-= len
;
329 /* we must return decompressed data now */
330 This
->bDecompress
= TRUE
;
332 /* deleting hole part */
333 len
-= This
->pStreams
[streamNr
].dwLength
;
334 AVIFILE_RemoveStream(This
,streamNr
);
336 } else if (EditStreamEnd(This
, streamNr
) <= streamPos
+ len
) {
337 /* deleting at end of a part */
338 DWORD count
= EditStreamEnd(This
, streamNr
) - streamPos
;
339 This
->sInfo
.dwLength
-= count
;
341 This
->pStreams
[streamNr
].dwLength
=
342 streamPos
- This
->pStreams
[streamNr
].dwStart
;
345 if (This
->nStreams
+ 1 >= This
->nTableSize
) {
346 This
->pStreams
= _recalloc(This
->pStreams
, This
->nTableSize
+ 32, sizeof(EditStreamTable
));
347 if (This
->pStreams
== NULL
)
348 return AVIERR_MEMORY
;
349 This
->nTableSize
+= 32;
351 memmove(This
->pStreams
+ streamNr
+ 1, This
->pStreams
+ streamNr
,
352 (This
->nStreams
- streamNr
) * sizeof(EditStreamTable
));
355 IAVIStream_AddRef(This
->pStreams
[streamNr
+ 1].pStream
);
356 This
->pStreams
[streamNr
+ 1].dwStart
= streamPos
+ len
;
357 This
->pStreams
[streamNr
+ 1].dwLength
=
358 EditStreamEnd(This
, streamNr
) - This
->pStreams
[streamNr
+ 1].dwStart
;
360 This
->pStreams
[streamNr
].dwLength
=
361 streamPos
- This
->pStreams
[streamNr
].dwStart
;
362 This
->sInfo
.dwLength
-= len
;
367 This
->sInfo
.dwEditCount
++;
372 static HRESULT WINAPI
IAVIEditStream_fnCopy(IAVIEditStream
*iface
,LONG
*plStart
,
373 LONG
*plLength
,PAVISTREAM
*ppResult
)
375 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
376 IAVIEditStreamImpl
* pEdit
;
380 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
382 if (ppResult
== NULL
)
383 return AVIERR_BADPARAM
;
385 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0 || *plLength
< 0)
386 return AVIERR_BADPARAM
;
389 if (*(LPDWORD
)plLength
> This
->sInfo
.dwLength
)
390 *(LPDWORD
)plLength
= This
->sInfo
.dwLength
;
391 if (*(LPDWORD
)plStart
< This
->sInfo
.dwStart
) {
392 *(LPDWORD
)plLength
-= This
->sInfo
.dwStart
- *(LPDWORD
)plStart
;
393 *(LPDWORD
)plStart
= This
->sInfo
.dwStart
;
395 return AVIERR_BADPARAM
;
397 if (*(LPDWORD
)plStart
+ *(LPDWORD
)plLength
> This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
)
398 *(LPDWORD
)plLength
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
-
401 pEdit
= AVIFILE_CreateEditStream(NULL
);
403 return AVIERR_MEMORY
;
405 hr
= IAVIEditStream_Paste(&pEdit
->IAVIEditStream_iface
, &start
, plLength
, &This
->IAVIStream_iface
,
406 *plStart
, *plStart
+ *plLength
);
409 IAVIEditStream_Release(&pEdit
->IAVIEditStream_iface
);
411 *ppResult
= &This
->IAVIStream_iface
;
416 static HRESULT WINAPI
IAVIEditStream_fnPaste(IAVIEditStream
*iface
,LONG
*plStart
,
417 LONG
*plLength
,PAVISTREAM pSource
,
418 LONG lStart
,LONG lLength
)
420 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
421 AVISTREAMINFOW srcInfo
;
422 IAVIEditStreamImpl
*pEdit
= NULL
;
424 DWORD startPos
, endPos
, streamNr
, nStreams
;
427 TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface
,plStart
,plLength
,
428 pSource
,lStart
,lLength
);
431 return AVIERR_BADHANDLE
;
432 if (plStart
== NULL
|| *plStart
< 0)
433 return AVIERR_BADPARAM
;
434 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< *plStart
)
435 return AVIERR_BADPARAM
; /* Can't paste with holes */
436 if (FAILED(IAVIStream_Info(pSource
, &srcInfo
, sizeof(srcInfo
))))
438 if (lStart
< srcInfo
.dwStart
|| lStart
>= srcInfo
.dwStart
+ srcInfo
.dwLength
)
439 return AVIERR_BADPARAM
;
440 if (This
->sInfo
.fccType
== 0) {
441 /* This stream is empty */
442 IAVIStream_Info(pSource
, &This
->sInfo
, sizeof(This
->sInfo
));
443 This
->sInfo
.dwStart
= *plStart
;
444 This
->sInfo
.dwLength
= 0;
446 if (This
->sInfo
.fccType
!= srcInfo
.fccType
)
447 return AVIERR_UNSUPPORTED
; /* different stream types */
448 if (lLength
== -1) /* Copy the hole stream */
449 lLength
= srcInfo
.dwLength
;
450 if (lStart
+ lLength
> srcInfo
.dwStart
+ srcInfo
.dwLength
)
451 lLength
= srcInfo
.dwStart
+ srcInfo
.dwLength
- lStart
;
452 if (lLength
+ *plStart
>= 0x80000000)
453 return AVIERR_MEMORY
;
455 /* streamtype specific tests */
456 if (srcInfo
.fccType
== streamtypeVIDEO
) {
459 size
= srcInfo
.rcFrame
.right
- srcInfo
.rcFrame
.left
;
460 if (size
!= This
->sInfo
.rcFrame
.right
- This
->sInfo
.rcFrame
.left
)
461 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
462 size
= srcInfo
.rcFrame
.bottom
- srcInfo
.rcFrame
.top
;
463 if (size
!= This
->sInfo
.rcFrame
.bottom
- This
->sInfo
.rcFrame
.top
)
464 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
465 } else if (srcInfo
.fccType
== streamtypeAUDIO
) {
466 if (!AVIFILE_FormatsEqual(&This
->IAVIStream_iface
, pSource
))
467 return AVIERR_UNSUPPORTED
;
469 /* FIXME: streamtypeMIDI and streamtypeTEXT */
470 return AVIERR_UNSUPPORTED
;
473 /* try to get an IEditStreamInternal interface */
474 if (SUCCEEDED(IAVIStream_QueryInterface(pSource
, &IID_IEditStreamInternal
, (LPVOID
*)&pEdit
)))
475 IAVIEditStream_Release(&pEdit
->IAVIEditStream_iface
); /* pSource holds a reference */
477 /* for video must check for change of format */
478 if (This
->sInfo
.fccType
== streamtypeVIDEO
) {
479 if (! This
->bDecompress
) {
480 /* Need to decompress if any of the following conditions matches:
481 * - pSource is an editable stream which decompresses
482 * - the nearest keyframe of pSource isn't lStart
483 * - the nearest keyframe of this stream isn't *plStart
484 * - the format of pSource doesn't match this one
486 if ((pEdit
!= NULL
&& pEdit
->bDecompress
) ||
487 AVIStreamNearestKeyFrame(pSource
, lStart
) != lStart
||
488 AVIStreamNearestKeyFrame(&This
->IAVIStream_iface
, *plStart
) != *plStart
||
489 (This
->nStreams
> 0 && !AVIFILE_FormatsEqual(&This
->IAVIStream_iface
, pSource
))) {
490 /* Use first stream part to get format to convert everything to */
491 AVIFILE_ReadFrame(This
, This
->pStreams
[0].pStream
,
492 This
->pStreams
[0].dwStart
);
494 /* Check if we could convert the source streams to the desired format... */
496 if (FAILED(AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
497 &startPos
, &streamNr
, TRUE
)))
498 return AVIERR_INTERNAL
;
499 for (n
= lStart
; n
< lStart
+ lLength
; streamNr
++) {
500 if (AVIFILE_ReadFrame(This
, pEdit
->pStreams
[streamNr
].pStream
, startPos
) == NULL
)
501 return AVIERR_BADFORMAT
;
502 startPos
= pEdit
->pStreams
[streamNr
].dwStart
;
503 n
+= pEdit
->pStreams
[streamNr
].dwLength
;
505 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
506 return AVIERR_BADFORMAT
;
508 This
->bDecompress
= TRUE
;
509 This
->sInfo
.fccHandler
= 0;
511 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
512 return AVIERR_BADFORMAT
; /* Can't convert source to own format */
513 } /* FIXME: something special for the other formats? */
515 /* Make sure we have enough memory for parts */
519 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
520 &endPos
, &nLastStream
, TRUE
);
521 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
522 &startPos
, &streamNr
, FALSE
);
523 if (nLastStream
== streamNr
)
526 nStreams
= nLastStream
- streamNr
;
529 if (This
->nStreams
+ nStreams
+ 1 > This
->nTableSize
) {
530 n
= This
->nStreams
+ nStreams
+ 33;
532 This
->pStreams
= _recalloc(This
->pStreams
, n
, sizeof(EditStreamTable
));
533 if (This
->pStreams
== NULL
)
534 return AVIERR_MEMORY
;
535 This
->nTableSize
= n
;
538 if (plLength
!= NULL
)
541 /* now do the real work */
542 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> *plStart
) {
543 AVIFILE_FindStreamInTable(This
, *plStart
, &pStream
,
544 &startPos
, &streamNr
, FALSE
);
545 if (startPos
!= This
->pStreams
[streamNr
].dwStart
) {
546 /* split stream streamNr at startPos */
547 memmove(This
->pStreams
+ streamNr
+ nStreams
+ 1,
548 This
->pStreams
+ streamNr
,
549 (This
->nStreams
+ nStreams
- streamNr
+ 1) * sizeof(EditStreamTable
));
551 This
->pStreams
[streamNr
+ 2].dwLength
=
552 EditStreamEnd(This
, streamNr
+ 2) - startPos
;
553 This
->pStreams
[streamNr
+ 2].dwStart
= startPos
;
554 This
->pStreams
[streamNr
].dwLength
=
555 startPos
- This
->pStreams
[streamNr
].dwStart
;
556 IAVIStream_AddRef(This
->pStreams
[streamNr
].pStream
);
559 /* insert before stream at streamNr */
560 memmove(This
->pStreams
+ streamNr
+ nStreams
, This
->pStreams
+ streamNr
,
561 (This
->nStreams
+ nStreams
- streamNr
) * sizeof(EditStreamTable
));
563 } else /* append the streams */
564 streamNr
= This
->nStreams
;
567 /* insert the parts of the editable stream instead of itself */
568 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
569 &endPos
, NULL
, FALSE
);
570 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
, &startPos
, &n
, FALSE
);
572 memcpy(This
->pStreams
+ streamNr
, pEdit
->pStreams
+ n
,
573 nStreams
* sizeof(EditStreamTable
));
574 if (This
->pStreams
[streamNr
].dwStart
< startPos
) {
575 This
->pStreams
[streamNr
].dwLength
=
576 EditStreamEnd(This
, streamNr
) - startPos
;
577 This
->pStreams
[streamNr
].dwStart
= startPos
;
579 if (endPos
< EditStreamEnd(This
, streamNr
+ nStreams
))
580 This
->pStreams
[streamNr
+ nStreams
].dwLength
=
581 endPos
- This
->pStreams
[streamNr
+ nStreams
].dwStart
;
583 /* a simple stream */
584 This
->pStreams
[streamNr
].pStream
= pSource
;
585 This
->pStreams
[streamNr
].dwStart
= lStart
;
586 This
->pStreams
[streamNr
].dwLength
= lLength
;
589 for (n
= 0; n
< nStreams
; n
++) {
590 IAVIStream_AddRef(This
->pStreams
[streamNr
+ n
].pStream
);
591 if (0 < streamNr
+ n
&&
592 This
->pStreams
[streamNr
+ n
- 1].pStream
!= This
->pStreams
[streamNr
+ n
].pStream
) {
593 This
->sInfo
.dwFlags
|= AVISTREAMINFO_FORMATCHANGES
;
594 This
->sInfo
.dwFormatChangeCount
++;
597 This
->sInfo
.dwEditCount
++;
598 This
->sInfo
.dwLength
+= lLength
;
599 This
->nStreams
+= nStreams
;
604 static HRESULT WINAPI
IAVIEditStream_fnClone(IAVIEditStream
*iface
,
607 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
608 IAVIEditStreamImpl
* pEdit
;
611 TRACE("(%p,%p)\n",iface
,ppResult
);
613 if (ppResult
== NULL
)
614 return AVIERR_BADPARAM
;
617 pEdit
= AVIFILE_CreateEditStream(NULL
);
619 return AVIERR_MEMORY
;
620 if (This
->nStreams
> pEdit
->nTableSize
) {
621 pEdit
->pStreams
= _recalloc(pEdit
->pStreams
, This
->nStreams
, sizeof(EditStreamTable
));
622 if (pEdit
->pStreams
== NULL
)
623 return AVIERR_MEMORY
;
624 pEdit
->nTableSize
= This
->nStreams
;
626 pEdit
->nStreams
= This
->nStreams
;
627 memcpy(pEdit
->pStreams
, This
->pStreams
,
628 This
->nStreams
* sizeof(EditStreamTable
));
629 memcpy(&pEdit
->sInfo
,&This
->sInfo
,sizeof(This
->sInfo
));
630 for (i
= 0; i
< This
->nStreams
; i
++) {
631 if (pEdit
->pStreams
[i
].pStream
!= NULL
)
632 IAVIStream_AddRef(pEdit
->pStreams
[i
].pStream
);
635 *ppResult
= &This
->IAVIStream_iface
;
640 static HRESULT WINAPI
IAVIEditStream_fnSetInfo(IAVIEditStream
*iface
,
641 LPAVISTREAMINFOW asi
,LONG size
)
643 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
645 TRACE("(%p,%p,%ld)\n",iface
,asi
,size
);
647 /* check parameters */
648 if (size
>= 0 && size
< sizeof(AVISTREAMINFOW
))
649 return AVIERR_BADSIZE
;
651 This
->sInfo
.wLanguage
= asi
->wLanguage
;
652 This
->sInfo
.wPriority
= asi
->wPriority
;
653 This
->sInfo
.dwStart
= asi
->dwStart
;
654 This
->sInfo
.dwRate
= asi
->dwRate
;
655 This
->sInfo
.dwScale
= asi
->dwScale
;
656 This
->sInfo
.dwQuality
= asi
->dwQuality
;
657 This
->sInfo
.rcFrame
= asi
->rcFrame
;
658 memcpy(This
->sInfo
.szName
, asi
->szName
, sizeof(asi
->szName
));
659 This
->sInfo
.dwEditCount
++;
664 static const struct IAVIEditStreamVtbl ieditstream
= {
665 IAVIEditStream_fnQueryInterface
,
666 IAVIEditStream_fnAddRef
,
667 IAVIEditStream_fnRelease
,
668 IAVIEditStream_fnCut
,
669 IAVIEditStream_fnCopy
,
670 IAVIEditStream_fnPaste
,
671 IAVIEditStream_fnClone
,
672 IAVIEditStream_fnSetInfo
675 static HRESULT WINAPI
IEditAVIStream_fnQueryInterface(IAVIStream
*iface
,
676 REFIID refiid
,LPVOID
*obj
)
678 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
679 return IAVIEditStream_QueryInterface(&This
->IAVIEditStream_iface
,refiid
,obj
);
682 static ULONG WINAPI
IEditAVIStream_fnAddRef(IAVIStream
*iface
)
684 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
685 return IAVIEditStream_AddRef(&This
->IAVIEditStream_iface
);
688 static ULONG WINAPI
IEditAVIStream_fnRelease(IAVIStream
*iface
)
690 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
691 return IAVIEditStream_Release(&This
->IAVIEditStream_iface
);
694 static HRESULT WINAPI
IEditAVIStream_fnCreate(IAVIStream
*iface
,
695 LPARAM lParam1
,LPARAM lParam2
)
697 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
702 if (This
->pStreams
== NULL
) {
703 This
->pStreams
= calloc(256, sizeof(EditStreamTable
));
704 if (This
->pStreams
== NULL
)
705 return AVIERR_MEMORY
;
706 This
->nTableSize
= 256;
710 IAVIStream_Info((PAVISTREAM
)lParam1
, &This
->sInfo
, sizeof(This
->sInfo
));
711 IAVIStream_AddRef((PAVISTREAM
)lParam1
);
712 This
->pStreams
[0].pStream
= (PAVISTREAM
)lParam1
;
713 This
->pStreams
[0].dwStart
= This
->sInfo
.dwStart
;
714 This
->pStreams
[0].dwLength
= This
->sInfo
.dwLength
;
720 static HRESULT WINAPI
IEditAVIStream_fnInfo(IAVIStream
*iface
,
721 AVISTREAMINFOW
*psi
,LONG size
)
723 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
725 TRACE("(%p,%p,%ld)\n",iface
,psi
,size
);
728 return AVIERR_BADPARAM
;
730 return AVIERR_BADSIZE
;
732 if (This
->bDecompress
)
733 This
->sInfo
.fccHandler
= 0;
735 memcpy(psi
, &This
->sInfo
, min((DWORD
)size
, sizeof(This
->sInfo
)));
737 if ((DWORD
)size
< sizeof(This
->sInfo
))
738 return AVIERR_BUFFERTOOSMALL
;
742 static LONG WINAPI
IEditAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,
745 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
747 DWORD streamPos
, streamNr
;
749 TRACE("(%p,%ld,0x%08lX)\n",iface
,pos
,flags
);
751 if (flags
& FIND_FROM_START
)
752 pos
= (LONG
)This
->sInfo
.dwStart
;
754 /* outside of stream? */
755 if (pos
< (LONG
)This
->sInfo
.dwStart
||
756 (LONG
)This
->sInfo
.dwStart
+ (LONG
)This
->sInfo
.dwLength
<= pos
)
759 /* map our position to a stream and position in it */
760 if (AVIFILE_FindStreamInTable(This
, pos
, &stream
, &streamPos
,
761 &streamNr
, TRUE
) != S_OK
)
762 return -1; /* doesn't exist */
764 if (This
->bDecompress
) {
765 /* only one stream -- format changes only at start */
766 if (flags
& FIND_FORMAT
)
767 return (flags
& FIND_NEXT
? -1 : 0);
769 /* FIXME: map positions back to us */
770 return IAVIStream_FindSample(stream
, streamPos
, flags
);
772 /* assume change of format every frame */
777 static HRESULT WINAPI
IEditAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,
778 LPVOID format
,LONG
*fmtsize
)
780 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
781 LPBITMAPINFOHEADER lp
;
786 TRACE("(%p,%ld,%p,%p)\n",iface
,pos
,format
,fmtsize
);
788 if (fmtsize
== NULL
|| pos
< This
->sInfo
.dwStart
||
789 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
<= pos
)
790 return AVIERR_BADPARAM
;
792 /* find stream corresponding to position */
793 hr
= AVIFILE_FindStreamInTable(This
, pos
, &stream
, &n
, NULL
, FALSE
);
797 if (! This
->bDecompress
)
798 return IAVIStream_ReadFormat(stream
, n
, format
, fmtsize
);
800 lp
= AVIFILE_ReadFrame(This
, stream
, n
);
803 if (lp
->biBitCount
<= 8) {
804 n
= (lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
);
805 n
*= sizeof(RGBQUAD
);
810 memcpy(format
, lp
, min((LONG
)n
, *fmtsize
));
811 hr
= ((LONG
)n
> *fmtsize
? AVIERR_BUFFERTOOSMALL
: AVIERR_OK
);
817 static HRESULT WINAPI
IEditAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,
818 LPVOID format
,LONG formatsize
)
820 TRACE("(%p,%ld,%p,%ld)\n",iface
,pos
,format
,formatsize
);
822 return AVIERR_UNSUPPORTED
;
825 static HRESULT WINAPI
IEditAVIStream_fnRead(IAVIStream
*iface
,LONG start
,
826 LONG samples
,LPVOID buffer
,
827 LONG buffersize
,LONG
*bytesread
,
830 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
832 DWORD streamPos
, streamNr
;
833 LONG readBytes
, readSamples
, count
;
836 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface
,start
,samples
,
837 buffer
,buffersize
,bytesread
,samplesread
,This
->sInfo
.fccType
);
839 /* check parameters */
840 if (bytesread
!= NULL
)
842 if (samplesread
!= NULL
)
845 return AVIERR_BADSIZE
;
846 if ((DWORD
)start
< This
->sInfo
.dwStart
||
847 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< (DWORD
)start
)
848 return AVIERR_BADPARAM
;
850 if (! This
->bDecompress
) {
851 /* audio like data -- sample-based */
854 return AVIERR_OK
; /* nothing at all or already done */
856 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
857 &streamPos
, &streamNr
, FALSE
)))
860 /* limit to end of the stream */
862 if (streamPos
+ count
> EditStreamEnd(This
, streamNr
))
863 count
= EditStreamEnd(This
, streamNr
) - streamPos
;
865 hr
= IAVIStream_Read(stream
, streamPos
, count
, buffer
, buffersize
,
866 &readBytes
, &readSamples
);
869 if (readBytes
== 0 && readSamples
== 0 && count
!= 0)
870 return AVIERR_FILEREAD
; /* for bad stream implementations */
872 if (samplesread
!= NULL
)
873 *samplesread
+= readSamples
;
874 if (bytesread
!= NULL
)
875 *bytesread
+= readBytes
;
876 if (buffer
!= NULL
) {
877 buffer
= ((LPBYTE
)buffer
)+readBytes
;
878 buffersize
-= readBytes
;
882 } while (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> start
);
884 /* video like data -- frame-based */
885 LPBITMAPINFOHEADER lp
;
890 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
891 &streamPos
, &streamNr
, FALSE
)))
894 lp
= AVIFILE_ReadFrame(This
, stream
, streamPos
);
898 if (buffer
!= NULL
) {
899 /* need size of format to skip */
900 if (lp
->biBitCount
<= 8) {
901 count
= lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
;
902 count
*= sizeof(RGBQUAD
);
907 if (buffersize
< lp
->biSizeImage
)
908 return AVIERR_BUFFERTOOSMALL
;
909 memcpy(buffer
, (LPBYTE
)lp
+ count
, lp
->biSizeImage
);
912 if (bytesread
!= NULL
)
913 *bytesread
= lp
->biSizeImage
;
914 if (samplesread
!= NULL
)
921 static HRESULT WINAPI
IEditAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,
922 LONG samples
,LPVOID buffer
,
923 LONG buffersize
,DWORD flags
,
924 LONG
*sampwritten
,LONG
*byteswritten
)
926 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface
,start
,samples
,buffer
,
927 buffersize
,flags
,sampwritten
,byteswritten
);
929 /* be sure return parameters have correct values */
930 if (sampwritten
!= NULL
)
932 if (byteswritten
!= NULL
)
935 return AVIERR_UNSUPPORTED
;
938 static HRESULT WINAPI
IEditAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,
941 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
943 TRACE("(%p,%ld,%ld)\n",iface
,start
,samples
);
945 return IAVIEditStream_Cut(&This
->IAVIEditStream_iface
,&start
,&samples
,NULL
);
948 static HRESULT WINAPI
IEditAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,
949 LPVOID lp
,LONG
*lpread
)
951 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
954 TRACE("(%p,0x%08lX,%p,%p)\n",iface
,fcc
,lp
,lpread
);
956 /* check parameters */
957 if (lp
== NULL
|| lpread
== NULL
)
958 return AVIERR_BADPARAM
;
960 /* simply ask every stream and return the first block found */
961 for (n
= 0; n
< This
->nStreams
; n
++) {
962 HRESULT hr
= IAVIStream_ReadData(This
->pStreams
[n
].pStream
,fcc
,lp
,lpread
);
969 return AVIERR_NODATA
;
972 static HRESULT WINAPI
IEditAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,
975 TRACE("(%p,0x%08lX,%p,%ld)\n",iface
,fcc
,lp
,size
);
977 return AVIERR_UNSUPPORTED
;
980 static HRESULT WINAPI
IEditAVIStream_fnSetInfo(IAVIStream
*iface
,
981 AVISTREAMINFOW
*info
,LONG len
)
983 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
985 TRACE("(%p,%p,%ld)\n",iface
,info
,len
);
987 return IAVIEditStream_SetInfo(&This
->IAVIEditStream_iface
,info
,len
);
990 static const struct IAVIStreamVtbl ieditstast
= {
991 IEditAVIStream_fnQueryInterface
,
992 IEditAVIStream_fnAddRef
,
993 IEditAVIStream_fnRelease
,
994 IEditAVIStream_fnCreate
,
995 IEditAVIStream_fnInfo
,
996 IEditAVIStream_fnFindSample
,
997 IEditAVIStream_fnReadFormat
,
998 IEditAVIStream_fnSetFormat
,
999 IEditAVIStream_fnRead
,
1000 IEditAVIStream_fnWrite
,
1001 IEditAVIStream_fnDelete
,
1002 IEditAVIStream_fnReadData
,
1003 IEditAVIStream_fnWriteData
,
1004 IEditAVIStream_fnSetInfo
1007 static IAVIEditStreamImpl
*AVIFILE_CreateEditStream(IAVIStream
*pstream
)
1009 IAVIEditStreamImpl
*pedit
= NULL
;
1011 pedit
= calloc(1, sizeof(IAVIEditStreamImpl
));
1015 pedit
->IAVIEditStream_iface
.lpVtbl
= &ieditstream
;
1016 pedit
->IAVIStream_iface
.lpVtbl
= &ieditstast
;
1019 IAVIStream_Create(&pedit
->IAVIStream_iface
, (LPARAM
)pstream
, 0);
1024 /***********************************************************************
1025 * CreateEditableStream (AVIFIL32.@)
1027 HRESULT WINAPI
CreateEditableStream(IAVIStream
**editable
, IAVIStream
*src
)
1029 IAVIEditStream
*edit
= NULL
;
1030 IAVIEditStreamImpl
*editobj
;
1033 TRACE("(%p,%p)\n", editable
, src
);
1036 return AVIERR_BADPARAM
;
1040 hr
= IAVIStream_QueryInterface(src
, &IID_IAVIEditStream
, (void**)&edit
);
1041 if (SUCCEEDED(hr
) && edit
) {
1042 hr
= IAVIEditStream_Clone(edit
, editable
);
1043 IAVIEditStream_Release(edit
);
1049 /* Need own implementation of IAVIEditStream */
1050 editobj
= AVIFILE_CreateEditStream(src
);
1052 return AVIERR_MEMORY
;
1053 *editable
= &editobj
->IAVIStream_iface
;