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"
35 WINE_DEFAULT_DEBUG_CHANNEL(avifile
);
37 /***********************************************************************/
39 /* internal interface to get access to table of stream in an editable stream */
41 typedef struct _EditStreamTable
{
42 PAVISTREAM pStream
; /* stream which contains the data */
43 DWORD dwStart
; /* where starts the part which is also our */
44 DWORD dwLength
; /* how many is also in this stream */
47 #define INTERFACE IEditStreamInternal
48 DECLARE_INTERFACE_(IEditStreamInternal
,IUnknown
)
50 /*** IUnknown methods ***/
51 STDMETHOD_(HRESULT
,QueryInterface
)(THIS_ REFIID riid
, void** ppvObject
) PURE
;
52 STDMETHOD_(ULONG
,AddRef
)(THIS
) PURE
;
53 STDMETHOD_(ULONG
,Release
)(THIS
) PURE
;
54 /*** IEditStreamInternal methods ***/
55 STDMETHOD(GetEditStreamImpl
)(THIS_ LPVOID
*) PURE
;
59 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
60 (This)->pStreams[streamNr].dwLength)
62 /***********************************************************************/
64 static HRESULT WINAPI
IAVIEditStream_fnQueryInterface(IAVIEditStream
*iface
,REFIID refiid
,LPVOID
*obj
);
65 static ULONG WINAPI
IAVIEditStream_fnAddRef(IAVIEditStream
*iface
);
66 static ULONG WINAPI
IAVIEditStream_fnRelease(IAVIEditStream
*iface
);
67 static HRESULT WINAPI
IAVIEditStream_fnCut(IAVIEditStream
*iface
,LONG
*plStart
,
68 LONG
*plLength
,PAVISTREAM
*ppResult
);
69 static HRESULT WINAPI
IAVIEditStream_fnCopy(IAVIEditStream
*iface
,LONG
*plStart
,
70 LONG
*plLength
,PAVISTREAM
*ppResult
);
71 static HRESULT WINAPI
IAVIEditStream_fnPaste(IAVIEditStream
*iface
,LONG
*plStart
,
72 LONG
*plLength
,PAVISTREAM pSource
,
73 LONG lStart
,LONG lEnd
);
74 static HRESULT WINAPI
IAVIEditStream_fnClone(IAVIEditStream
*iface
,
76 static HRESULT WINAPI
IAVIEditStream_fnSetInfo(IAVIEditStream
*iface
,
77 LPAVISTREAMINFOW asi
,LONG size
);
79 static const struct IAVIEditStreamVtbl ieditstream
= {
80 IAVIEditStream_fnQueryInterface
,
81 IAVIEditStream_fnAddRef
,
82 IAVIEditStream_fnRelease
,
84 IAVIEditStream_fnCopy
,
85 IAVIEditStream_fnPaste
,
86 IAVIEditStream_fnClone
,
87 IAVIEditStream_fnSetInfo
90 static HRESULT WINAPI
IEditAVIStream_fnQueryInterface(IAVIStream
*iface
,REFIID refiid
,LPVOID
*obj
);
91 static ULONG WINAPI
IEditAVIStream_fnAddRef(IAVIStream
*iface
);
92 static ULONG WINAPI
IEditAVIStream_fnRelease(IAVIStream
*iface
);
93 static HRESULT WINAPI
IEditAVIStream_fnCreate(IAVIStream
*iface
,LPARAM lParam1
,LPARAM lParam2
);
94 static HRESULT WINAPI
IEditAVIStream_fnInfo(IAVIStream
*iface
,AVISTREAMINFOW
*psi
,LONG size
);
95 static LONG WINAPI
IEditAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,
97 static HRESULT WINAPI
IEditAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG
*formatsize
);
98 static HRESULT WINAPI
IEditAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG formatsize
);
99 static HRESULT WINAPI
IEditAVIStream_fnRead(IAVIStream
*iface
,LONG start
,
100 LONG samples
,LPVOID buffer
,
101 LONG buffersize
,LONG
*bytesread
,
103 static HRESULT WINAPI
IEditAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,
104 LONG samples
,LPVOID buffer
,
105 LONG buffersize
,DWORD flags
,
106 LONG
*sampwritten
,LONG
*byteswritten
);
107 static HRESULT WINAPI
IEditAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,LONG samples
);
108 static HRESULT WINAPI
IEditAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,
109 LPVOID lp
,LONG
*lpread
);
110 static HRESULT WINAPI
IEditAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,
111 LPVOID lp
,LONG size
);
112 static HRESULT WINAPI
IEditAVIStream_fnSetInfo(IAVIStream
*iface
,AVISTREAMINFOW
*info
,LONG infolen
);
114 static const struct IAVIStreamVtbl ieditstast
= {
115 IEditAVIStream_fnQueryInterface
,
116 IEditAVIStream_fnAddRef
,
117 IEditAVIStream_fnRelease
,
118 IEditAVIStream_fnCreate
,
119 IEditAVIStream_fnInfo
,
120 IEditAVIStream_fnFindSample
,
121 IEditAVIStream_fnReadFormat
,
122 IEditAVIStream_fnSetFormat
,
123 IEditAVIStream_fnRead
,
124 IEditAVIStream_fnWrite
,
125 IEditAVIStream_fnDelete
,
126 IEditAVIStream_fnReadData
,
127 IEditAVIStream_fnWriteData
,
128 IEditAVIStream_fnSetInfo
131 static HRESULT WINAPI
IEditStreamInternal_fnQueryInterface(IEditStreamInternal
*iface
,REFIID refiid
,LPVOID
*obj
);
132 static ULONG WINAPI
IEditStreamInternal_fnAddRef(IEditStreamInternal
*iface
);
133 static ULONG WINAPI
IEditStreamInternal_fnRelease(IEditStreamInternal
*iface
);
134 static HRESULT WINAPI
IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal
*iface
,LPVOID
*ppimpl
);
136 static const struct IEditStreamInternalVtbl ieditstreaminternal
= {
137 IEditStreamInternal_fnQueryInterface
,
138 IEditStreamInternal_fnAddRef
,
139 IEditStreamInternal_fnRelease
,
140 IEditStreamInternal_fnGetEditStreamImpl
143 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl
;
145 typedef struct _IEditAVIStreamImpl
{
147 const IAVIStreamVtbl
*lpVtbl
;
149 /* IAVIStream stuff */
150 IAVIEditStreamImpl
*pae
;
151 } IEditAVIStreamImpl
;
153 typedef struct _IEditStreamInternalImpl
{
155 const IEditStreamInternalVtbl
*lpVtbl
;
157 /* IEditStreamInternal stuff */
158 IAVIEditStreamImpl
*pae
;
159 } IEditStreamInternalImpl
;
161 struct _IAVIEditStreamImpl
{
163 const IAVIEditStreamVtbl
*lpVtbl
;
166 /* IAVIEditStream stuff */
167 IEditAVIStreamImpl iAVIStream
;
168 IEditStreamInternalImpl iEditStreamInternal
;
170 AVISTREAMINFOW sInfo
;
172 EditStreamTable
*pStreams
;
173 DWORD nStreams
; /* current fill level of pStreams table */
174 DWORD nTableSize
; /* size of pStreams table */
177 PAVISTREAM pCurStream
;
178 PGETFRAME pg
; /* IGetFrame for pCurStream */
179 LPBITMAPINFOHEADER lpFrame
; /* frame of pCurStream */
182 /***********************************************************************/
184 PAVIEDITSTREAM
AVIFILE_CreateEditStream(PAVISTREAM pstream
)
186 IAVIEditStreamImpl
*pedit
= NULL
;
188 pedit
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IAVIEditStreamImpl
));
192 pedit
->lpVtbl
= &ieditstream
;
193 pedit
->iAVIStream
.lpVtbl
= &ieditstast
;
194 pedit
->iAVIStream
.pae
= pedit
;
195 pedit
->iEditStreamInternal
.lpVtbl
= &ieditstreaminternal
;
196 pedit
->iEditStreamInternal
.pae
= pedit
;
199 IAVIStream_Create((PAVISTREAM
)&pedit
->iAVIStream
,(LPARAM
)pstream
,0);
201 return (PAVIEDITSTREAM
)pedit
;
204 static HRESULT
AVIFILE_FindStreamInTable(IAVIEditStreamImpl
* const This
,
205 DWORD pos
,PAVISTREAM
*ppStream
,
207 DWORD
* streamNr
,BOOL bFindSample
)
211 TRACE("(%p,%u,%p,%p,%p,%d)\n",This
,pos
,ppStream
,streamPos
,
212 streamNr
,bFindSample
);
214 if (pos
< This
->sInfo
.dwStart
)
215 return AVIERR_BADPARAM
;
217 pos
-= This
->sInfo
.dwStart
;
218 for (n
= 0; n
< This
->nStreams
; n
++) {
219 if (pos
< This
->pStreams
[n
].dwLength
) {
220 *ppStream
= This
->pStreams
[n
].pStream
;
221 *streamPos
= This
->pStreams
[n
].dwStart
+ pos
;
222 if (streamNr
!= NULL
)
227 pos
-= This
->pStreams
[n
].dwLength
;
229 if (pos
== 0 && bFindSample
) {
230 *ppStream
= This
->pStreams
[--n
].pStream
;
231 *streamPos
= EditStreamEnd(This
, n
);
232 if (streamNr
!= NULL
)
235 TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream
, *streamPos
, n
);
240 if (streamNr
!= NULL
)
243 TRACE(" -> ERROR (NULL,0,0)\n");
244 return AVIERR_BADPARAM
;
248 static LPVOID
AVIFILE_ReadFrame(IAVIEditStreamImpl
* const This
,
249 PAVISTREAM pstream
, LONG pos
)
253 TRACE("(%p,%p,%d)\n",This
,pstream
,pos
);
258 /* if stream changes make sure that only palette changes */
259 if (This
->pCurStream
!= pstream
) {
260 pg
= AVIStreamGetFrameOpen(pstream
, NULL
);
263 if (This
->pg
!= NULL
) {
264 if (IGetFrame_SetFormat(pg
, This
->lpFrame
, NULL
, 0, 0, -1, -1)) {
265 AVIStreamGetFrameClose(pg
);
266 ERR(": IGetFrame_SetFormat failed\n");
269 AVIStreamGetFrameClose(This
->pg
);
272 This
->pCurStream
= pstream
;
275 /* now get the decompressed frame */
276 This
->lpFrame
= AVIStreamGetFrame(This
->pg
, pos
);
277 if (This
->lpFrame
!= NULL
)
278 This
->sInfo
.dwSuggestedBufferSize
= This
->lpFrame
->biSizeImage
;
280 return This
->lpFrame
;
283 static HRESULT
AVIFILE_RemoveStream(IAVIEditStreamImpl
* const This
, DWORD nr
)
285 assert(This
!= NULL
);
286 assert(nr
< This
->nStreams
);
289 IAVIStream_Release(This
->pStreams
[nr
].pStream
);
291 if (This
->nStreams
- nr
> 0) {
292 memmove(This
->pStreams
+ nr
, This
->pStreams
+ nr
+ 1,
293 (This
->nStreams
- nr
) * sizeof(EditStreamTable
));
295 This
->pStreams
[This
->nStreams
].pStream
= NULL
;
296 This
->pStreams
[This
->nStreams
].dwStart
= 0;
297 This
->pStreams
[This
->nStreams
].dwLength
= 0;
299 /* try to merge the part before the deleted one and the one after it */
300 if (0 < nr
&& 0 < This
->nStreams
&&
301 This
->pStreams
[nr
- 1].pStream
== This
->pStreams
[nr
].pStream
) {
302 if (EditStreamEnd(This
, nr
- 1) == This
->pStreams
[nr
].dwStart
) {
303 This
->pStreams
[nr
- 1].dwLength
+= This
->pStreams
[nr
].dwLength
;
304 return AVIFILE_RemoveStream(This
, nr
);
311 static BOOL
AVIFILE_FormatsEqual(PAVISTREAM avi1
, PAVISTREAM avi2
)
313 LPVOID fmt1
= NULL
, fmt2
= NULL
;
314 LONG size1
, size2
, start1
, start2
;
317 assert(avi1
!= NULL
&& avi2
!= NULL
);
319 /* get stream starts and check format sizes */
320 start1
= AVIStreamStart(avi1
);
321 start2
= AVIStreamStart(avi2
);
322 if (FAILED(AVIStreamFormatSize(avi1
, start1
, &size1
)))
324 if (FAILED(AVIStreamFormatSize(avi2
, start2
, &size2
)))
329 /* sizes match, now get formats and compare them */
330 fmt1
= HeapAlloc(GetProcessHeap(), 0, size1
);
333 if (SUCCEEDED(AVIStreamReadFormat(avi1
, start1
, fmt1
, &size1
))) {
334 fmt2
= HeapAlloc(GetProcessHeap(), 0, size1
);
336 if (SUCCEEDED(AVIStreamReadFormat(avi2
, start2
, fmt2
, &size1
)))
337 status
= (memcmp(fmt1
, fmt2
, size1
) == 0);
341 HeapFree(GetProcessHeap(), 0, fmt2
);
342 HeapFree(GetProcessHeap(), 0, fmt1
);
347 /***********************************************************************/
349 static HRESULT WINAPI
IAVIEditStream_fnQueryInterface(IAVIEditStream
*iface
,REFIID refiid
,LPVOID
*obj
)
351 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
353 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(refiid
), obj
);
355 if (IsEqualGUID(&IID_IUnknown
, refiid
) ||
356 IsEqualGUID(&IID_IAVIEditStream
, refiid
)) {
358 IAVIEditStream_AddRef(iface
);
361 } else if (IsEqualGUID(&IID_IAVIStream
, refiid
)) {
362 *obj
= &This
->iAVIStream
;
363 IAVIEditStream_AddRef(iface
);
366 } else if (IsEqualGUID(&IID_IEditStreamInternal
, refiid
)) {
367 *obj
= &This
->iEditStreamInternal
;
368 IAVIEditStream_AddRef(iface
);
373 return OLE_E_ENUM_NOMORE
;
376 static ULONG WINAPI
IAVIEditStream_fnAddRef(IAVIEditStream
*iface
)
378 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
379 ULONG ref
= InterlockedIncrement(&This
->ref
);
381 TRACE("(%p) -> %d\n", iface
, ref
);
386 static ULONG WINAPI
IAVIEditStream_fnRelease(IAVIEditStream
*iface
)
388 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
390 ULONG ref
= InterlockedDecrement(&This
->ref
);
392 TRACE("(%p) -> %d\n", iface
, ref
);
396 if (This
->pg
!= NULL
)
397 AVIStreamGetFrameClose(This
->pg
);
398 if (This
->pStreams
!= NULL
) {
399 for (i
= 0; i
< This
->nStreams
; i
++) {
400 if (This
->pStreams
[i
].pStream
!= NULL
)
401 IAVIStream_Release(This
->pStreams
[i
].pStream
);
403 HeapFree(GetProcessHeap(), 0, This
->pStreams
);
406 HeapFree(GetProcessHeap(), 0, This
);
412 static HRESULT WINAPI
IAVIEditStream_fnCut(IAVIEditStream
*iface
,LONG
*plStart
,
413 LONG
*plLength
,PAVISTREAM
*ppResult
)
415 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
417 DWORD start
, len
, streamPos
, streamNr
;
420 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
422 if (ppResult
!= NULL
)
424 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0)
425 return AVIERR_BADPARAM
;
427 /* if asked for cut part copy it before deleting */
428 if (ppResult
!= NULL
) {
429 hr
= IAVIEditStream_Copy(iface
, plStart
, plLength
, ppResult
);
437 /* now delete the requested part */
439 hr
= AVIFILE_FindStreamInTable(This
, start
, &stream
,
440 &streamPos
, &streamNr
, FALSE
);
443 if (This
->pStreams
[streamNr
].dwStart
== streamPos
) {
444 /* deleting from start of part */
445 if (len
< This
->pStreams
[streamNr
].dwLength
) {
447 This
->pStreams
[streamNr
].dwStart
+= len
;
448 This
->pStreams
[streamNr
].dwLength
-= len
;
449 This
->sInfo
.dwLength
-= len
;
452 /* we must return decompressed data now */
453 This
->bDecompress
= TRUE
;
455 /* deleting hole part */
456 len
-= This
->pStreams
[streamNr
].dwLength
;
457 AVIFILE_RemoveStream(This
,streamNr
);
459 } else if (EditStreamEnd(This
, streamNr
) <= streamPos
+ len
) {
460 /* deleting at end of a part */
461 DWORD count
= EditStreamEnd(This
, streamNr
) - streamPos
;
462 This
->sInfo
.dwLength
-= count
;
464 This
->pStreams
[streamNr
].dwLength
=
465 streamPos
- This
->pStreams
[streamNr
].dwStart
;
468 if (This
->nStreams
+ 1 >= This
->nTableSize
) {
469 This
->pStreams
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pStreams
,
470 (This
->nTableSize
+ 32) * sizeof(EditStreamTable
));
471 if (This
->pStreams
== NULL
)
472 return AVIERR_MEMORY
;
473 This
->nTableSize
+= 32;
475 memmove(This
->pStreams
+ streamNr
+ 1, This
->pStreams
+ streamNr
,
476 (This
->nStreams
- streamNr
) * sizeof(EditStreamTable
));
479 IAVIStream_AddRef(This
->pStreams
[streamNr
+ 1].pStream
);
480 This
->pStreams
[streamNr
+ 1].dwStart
= streamPos
+ len
;
481 This
->pStreams
[streamNr
+ 1].dwLength
=
482 EditStreamEnd(This
, streamNr
) - This
->pStreams
[streamNr
+ 1].dwStart
;
484 This
->pStreams
[streamNr
].dwLength
=
485 streamPos
- This
->pStreams
[streamNr
].dwStart
;
486 This
->sInfo
.dwLength
-= len
;
491 This
->sInfo
.dwEditCount
++;
496 static HRESULT WINAPI
IAVIEditStream_fnCopy(IAVIEditStream
*iface
,LONG
*plStart
,
497 LONG
*plLength
,PAVISTREAM
*ppResult
)
499 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
500 IAVIEditStreamImpl
* pEdit
;
504 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
506 if (ppResult
== NULL
)
507 return AVIERR_BADPARAM
;
509 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0 || *plLength
< 0)
510 return AVIERR_BADPARAM
;
513 if (*(LPDWORD
)plLength
> This
->sInfo
.dwLength
)
514 *(LPDWORD
)plLength
= This
->sInfo
.dwLength
;
515 if (*(LPDWORD
)plStart
< This
->sInfo
.dwStart
) {
516 *(LPDWORD
)plLength
-= This
->sInfo
.dwStart
- *(LPDWORD
)plStart
;
517 *(LPDWORD
)plStart
= This
->sInfo
.dwStart
;
519 return AVIERR_BADPARAM
;
521 if (*(LPDWORD
)plStart
+ *(LPDWORD
)plLength
> This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
)
522 *(LPDWORD
)plLength
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
-
525 pEdit
= (IAVIEditStreamImpl
*)AVIFILE_CreateEditStream(NULL
);
527 return AVIERR_MEMORY
;
529 hr
= IAVIEditStream_Paste((PAVIEDITSTREAM
)pEdit
,&start
,plLength
,
530 (PAVISTREAM
)&This
->iAVIStream
,*plStart
,
531 *plStart
+ *plLength
);
534 IAVIEditStream_Release((PAVIEDITSTREAM
)pEdit
);
536 *ppResult
= (PAVISTREAM
)&pEdit
->iAVIStream
;
541 static HRESULT WINAPI
IAVIEditStream_fnPaste(IAVIEditStream
*iface
,LONG
*plStart
,
542 LONG
*plLength
,PAVISTREAM pSource
,
543 LONG lStart
,LONG lLength
)
545 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
546 AVISTREAMINFOW srcInfo
;
547 IEditStreamInternal
*pInternal
= NULL
;
548 IAVIEditStreamImpl
*pEdit
= NULL
;
550 DWORD startPos
, endPos
, streamNr
, nStreams
;
553 TRACE("(%p,%p,%p,%p,%d,%d)\n",iface
,plStart
,plLength
,
554 pSource
,lStart
,lLength
);
557 return AVIERR_BADHANDLE
;
558 if (plStart
== NULL
|| *plStart
< 0)
559 return AVIERR_BADPARAM
;
560 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< *plStart
)
561 return AVIERR_BADPARAM
; /* Can't paste with holes */
562 if (FAILED(IAVIStream_Info(pSource
, &srcInfo
, sizeof(srcInfo
))))
564 if (lStart
< srcInfo
.dwStart
|| lStart
>= srcInfo
.dwStart
+ srcInfo
.dwLength
)
565 return AVIERR_BADPARAM
;
566 if (This
->sInfo
.fccType
== 0) {
567 /* This stream is empty */
568 IAVIStream_Info(pSource
, &This
->sInfo
, sizeof(This
->sInfo
));
569 This
->sInfo
.dwStart
= *plStart
;
570 This
->sInfo
.dwLength
= 0;
572 if (This
->sInfo
.fccType
!= srcInfo
.fccType
)
573 return AVIERR_UNSUPPORTED
; /* different stream types */
574 if (lLength
== -1) /* Copy the hole stream */
575 lLength
= srcInfo
.dwLength
;
576 if (lStart
+ lLength
> srcInfo
.dwStart
+ srcInfo
.dwLength
)
577 lLength
= srcInfo
.dwStart
+ srcInfo
.dwLength
- lStart
;
578 if (lLength
+ *plStart
>= 0x80000000)
579 return AVIERR_MEMORY
;
581 /* streamtype specific tests */
582 if (srcInfo
.fccType
== streamtypeVIDEO
) {
585 size
= srcInfo
.rcFrame
.right
- srcInfo
.rcFrame
.left
;
586 if (size
!= This
->sInfo
.rcFrame
.right
- This
->sInfo
.rcFrame
.left
)
587 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
588 size
= srcInfo
.rcFrame
.bottom
- srcInfo
.rcFrame
.top
;
589 if (size
!= This
->sInfo
.rcFrame
.bottom
- This
->sInfo
.rcFrame
.top
)
590 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
591 } else if (srcInfo
.fccType
== streamtypeAUDIO
) {
592 if (! AVIFILE_FormatsEqual((PAVISTREAM
)&This
->iAVIStream
, pSource
))
593 return AVIERR_UNSUPPORTED
;
595 /* FIXME: streamtypeMIDI and streamtypeTEXT */
596 return AVIERR_UNSUPPORTED
;
599 /* try to get an IEditStreamInternal interface */
600 if (SUCCEEDED(IAVIStream_QueryInterface(pSource
, &IID_IEditStreamInternal
,
601 (LPVOID
*)&pInternal
))) {
602 pInternal
->lpVtbl
->GetEditStreamImpl(pInternal
, (LPVOID
*)&pEdit
);
603 pInternal
->lpVtbl
->Release(pInternal
);
606 /* for video must check for change of format */
607 if (This
->sInfo
.fccType
== streamtypeVIDEO
) {
608 if (! This
->bDecompress
) {
609 /* Need to decompress if any of the following conditions matches:
610 * - pSource is an editable stream which decompresses
611 * - the nearest keyframe of pSource isn't lStart
612 * - the nearest keyframe of this stream isn't *plStart
613 * - the format of pSource doesn't match this one
615 if ((pEdit
!= NULL
&& pEdit
->bDecompress
) ||
616 AVIStreamNearestKeyFrame(pSource
, lStart
) != lStart
||
617 AVIStreamNearestKeyFrame((PAVISTREAM
)&This
->iAVIStream
, *plStart
) != *plStart
||
618 (This
->nStreams
> 0 && !AVIFILE_FormatsEqual((PAVISTREAM
)&This
->iAVIStream
, pSource
))) {
619 /* Use first stream part to get format to convert everything to */
620 AVIFILE_ReadFrame(This
, This
->pStreams
[0].pStream
,
621 This
->pStreams
[0].dwStart
);
623 /* Check if we could convert the source streams to the desired format... */
625 if (FAILED(AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
626 &startPos
, &streamNr
, TRUE
)))
627 return AVIERR_INTERNAL
;
628 for (n
= lStart
; n
< lStart
+ lLength
; streamNr
++) {
629 if (AVIFILE_ReadFrame(This
, pEdit
->pStreams
[streamNr
].pStream
, startPos
) == NULL
)
630 return AVIERR_BADFORMAT
;
631 startPos
= pEdit
->pStreams
[streamNr
].dwStart
;
632 n
+= pEdit
->pStreams
[streamNr
].dwLength
;
634 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
635 return AVIERR_BADFORMAT
;
637 This
->bDecompress
= TRUE
;
638 This
->sInfo
.fccHandler
= 0;
640 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
641 return AVIERR_BADFORMAT
; /* Can't convert source to own format */
642 } /* FIXME: something special for the other formats? */
644 /* Make sure we have enough memory for parts */
648 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
649 &endPos
, &nLastStream
, TRUE
);
650 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
651 &startPos
, &streamNr
, FALSE
);
652 if (nLastStream
== streamNr
)
655 nStreams
= nLastStream
- streamNr
;
658 if (This
->nStreams
+ nStreams
+ 1 > This
->nTableSize
) {
659 n
= This
->nStreams
+ nStreams
+ 33;
661 This
->pStreams
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pStreams
, n
* sizeof(EditStreamTable
));
662 if (This
->pStreams
== NULL
)
663 return AVIERR_MEMORY
;
664 This
->nTableSize
= n
;
667 if (plLength
!= NULL
)
670 /* now do the real work */
671 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> *plStart
) {
672 AVIFILE_FindStreamInTable(This
, *plStart
, &pStream
,
673 &startPos
, &streamNr
, FALSE
);
674 if (startPos
!= This
->pStreams
[streamNr
].dwStart
) {
675 /* split stream streamNr at startPos */
676 memmove(This
->pStreams
+ streamNr
+ nStreams
+ 1,
677 This
->pStreams
+ streamNr
,
678 (This
->nStreams
+ nStreams
- streamNr
+ 1) * sizeof(EditStreamTable
));
680 This
->pStreams
[streamNr
+ 2].dwLength
=
681 EditStreamEnd(This
, streamNr
+ 2) - startPos
;
682 This
->pStreams
[streamNr
+ 2].dwStart
= startPos
;
683 This
->pStreams
[streamNr
].dwLength
=
684 startPos
- This
->pStreams
[streamNr
].dwStart
;
685 IAVIStream_AddRef(This
->pStreams
[streamNr
].pStream
);
688 /* insert before stream at streamNr */
689 memmove(This
->pStreams
+ streamNr
+ nStreams
, This
->pStreams
+ streamNr
,
690 (This
->nStreams
+ nStreams
- streamNr
) * sizeof(EditStreamTable
));
692 } else /* append the streams */
693 streamNr
= This
->nStreams
;
696 /* insert the parts of the editable stream instead of itself */
697 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
698 &endPos
, NULL
, FALSE
);
699 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
, &startPos
, &n
, FALSE
);
701 memcpy(This
->pStreams
+ streamNr
, pEdit
->pStreams
+ n
,
702 nStreams
* sizeof(EditStreamTable
));
703 if (This
->pStreams
[streamNr
].dwStart
< startPos
) {
704 This
->pStreams
[streamNr
].dwLength
=
705 EditStreamEnd(This
, streamNr
) - startPos
;
706 This
->pStreams
[streamNr
].dwStart
= startPos
;
708 if (endPos
< EditStreamEnd(This
, streamNr
+ nStreams
))
709 This
->pStreams
[streamNr
+ nStreams
].dwLength
=
710 endPos
- This
->pStreams
[streamNr
+ nStreams
].dwStart
;
712 /* a simple stream */
713 This
->pStreams
[streamNr
].pStream
= pSource
;
714 This
->pStreams
[streamNr
].dwStart
= lStart
;
715 This
->pStreams
[streamNr
].dwLength
= lLength
;
718 for (n
= 0; n
< nStreams
; n
++) {
719 IAVIStream_AddRef(This
->pStreams
[streamNr
+ n
].pStream
);
720 if (0 < streamNr
+ n
&&
721 This
->pStreams
[streamNr
+ n
- 1].pStream
!= This
->pStreams
[streamNr
+ n
].pStream
) {
722 This
->sInfo
.dwFlags
|= AVISTREAMINFO_FORMATCHANGES
;
723 This
->sInfo
.dwFormatChangeCount
++;
726 This
->sInfo
.dwEditCount
++;
727 This
->sInfo
.dwLength
+= lLength
;
728 This
->nStreams
+= nStreams
;
733 static HRESULT WINAPI
IAVIEditStream_fnClone(IAVIEditStream
*iface
,
736 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
737 IAVIEditStreamImpl
* pEdit
;
740 TRACE("(%p,%p)\n",iface
,ppResult
);
742 if (ppResult
== NULL
)
743 return AVIERR_BADPARAM
;
746 pEdit
= (IAVIEditStreamImpl
*)AVIFILE_CreateEditStream(NULL
);
748 return AVIERR_MEMORY
;
749 if (This
->nStreams
> pEdit
->nTableSize
) {
750 pEdit
->pStreams
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, pEdit
->pStreams
,
751 This
->nStreams
* sizeof(EditStreamTable
));
752 if (pEdit
->pStreams
== NULL
)
753 return AVIERR_MEMORY
;
754 pEdit
->nTableSize
= This
->nStreams
;
756 pEdit
->nStreams
= This
->nStreams
;
757 memcpy(pEdit
->pStreams
, This
->pStreams
,
758 This
->nStreams
* sizeof(EditStreamTable
));
759 memcpy(&pEdit
->sInfo
,&This
->sInfo
,sizeof(This
->sInfo
));
760 for (i
= 0; i
< This
->nStreams
; i
++) {
761 if (pEdit
->pStreams
[i
].pStream
!= NULL
)
762 IAVIStream_AddRef(pEdit
->pStreams
[i
].pStream
);
765 *ppResult
= (PAVISTREAM
)&pEdit
->iAVIStream
;
770 static HRESULT WINAPI
IAVIEditStream_fnSetInfo(IAVIEditStream
*iface
,
771 LPAVISTREAMINFOW asi
,LONG size
)
773 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
775 TRACE("(%p,%p,%d)\n",iface
,asi
,size
);
777 /* check parameters */
779 return AVIERR_BADPARAM
;
780 if (size
!= sizeof(AVISTREAMINFOW
))
781 return AVIERR_BADSIZE
;
782 if (asi
->dwScale
== 0 || asi
->dwRate
== 0 || (LONG
)asi
->dwQuality
< -1 ||
783 asi
->dwQuality
> ICQUALITY_HIGH
)
786 This
->sInfo
.wLanguage
= asi
->wLanguage
;
787 This
->sInfo
.wPriority
= asi
->wPriority
;
788 This
->sInfo
.dwStart
= asi
->dwStart
;
789 if (asi
->dwRate
!= 0)
790 This
->sInfo
.dwRate
= asi
->dwRate
;
791 if (asi
->dwScale
!= 0)
792 This
->sInfo
.dwScale
= asi
->dwScale
;
793 if (asi
->dwQuality
<= ICQUALITY_HIGH
)
794 This
->sInfo
.dwQuality
= ICQUALITY_HIGH
;
795 CopyRect(&This
->sInfo
.rcFrame
, &asi
->rcFrame
);
796 memcpy(This
->sInfo
.szName
, asi
->szName
, sizeof(asi
->szName
));
797 This
->sInfo
.dwEditCount
++;
802 static HRESULT WINAPI
IEditAVIStream_fnQueryInterface(IAVIStream
*iface
,
803 REFIID refiid
,LPVOID
*obj
)
805 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
807 assert(This
->pae
!= NULL
);
809 return IAVIEditStream_QueryInterface((IAVIEditStream
*)This
->pae
,refiid
,obj
);
812 static ULONG WINAPI
IEditAVIStream_fnAddRef(IAVIStream
*iface
)
814 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
816 assert(This
->pae
!= NULL
);
818 return IAVIEditStream_AddRef((IAVIEditStream
*)This
->pae
);
821 static ULONG WINAPI
IEditAVIStream_fnRelease(IAVIStream
*iface
)
823 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
825 assert(This
->pae
!= NULL
);
827 return IAVIEditStream_Release((IAVIEditStream
*)This
->pae
);
830 static HRESULT WINAPI
IEditAVIStream_fnCreate(IAVIStream
*iface
,
831 LPARAM lParam1
,LPARAM lParam2
)
833 IAVIEditStreamImpl
*This
= ((IEditAVIStreamImpl
*)iface
)->pae
;
838 if (This
->pStreams
== NULL
) {
839 This
->pStreams
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, 256 * sizeof(EditStreamTable
));
840 if (This
->pStreams
== NULL
)
841 return AVIERR_MEMORY
;
842 This
->nTableSize
= 256;
846 IAVIStream_Info((PAVISTREAM
)lParam1
, &This
->sInfo
, sizeof(This
->sInfo
));
847 IAVIStream_AddRef((PAVISTREAM
)lParam1
);
848 This
->pStreams
[0].pStream
= (PAVISTREAM
)lParam1
;
849 This
->pStreams
[0].dwStart
= This
->sInfo
.dwStart
;
850 This
->pStreams
[0].dwLength
= This
->sInfo
.dwLength
;
856 static HRESULT WINAPI
IEditAVIStream_fnInfo(IAVIStream
*iface
,
857 AVISTREAMINFOW
*psi
,LONG size
)
859 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
861 TRACE("(%p,%p,%d)\n",iface
,psi
,size
);
863 assert(This
->pae
!= NULL
);
866 return AVIERR_BADPARAM
;
868 return AVIERR_BADSIZE
;
870 if (This
->pae
->bDecompress
)
871 This
->pae
->sInfo
.fccHandler
= 0;
873 memcpy(psi
, &This
->pae
->sInfo
, min((DWORD
)size
, sizeof(This
->pae
->sInfo
)));
875 if ((DWORD
)size
< sizeof(This
->pae
->sInfo
))
876 return AVIERR_BUFFERTOOSMALL
;
880 static LONG WINAPI
IEditAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,
883 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
885 DWORD streamPos
, streamNr
;
887 TRACE("(%p,%d,0x%08X)\n",iface
,pos
,flags
);
889 if (flags
& FIND_FROM_START
)
890 pos
= (LONG
)This
->sInfo
.dwStart
;
892 /* outside of stream? */
893 if (pos
< (LONG
)This
->sInfo
.dwStart
||
894 (LONG
)This
->sInfo
.dwStart
+ (LONG
)This
->sInfo
.dwLength
<= pos
)
897 /* map our position to a stream and position in it */
898 if (AVIFILE_FindStreamInTable(This
, pos
, &stream
, &streamPos
,
900 return -1; /* doesn't exist */
902 if (This
->bDecompress
) {
903 /* only one stream -- format changes only at start */
904 if (flags
& FIND_FORMAT
)
905 return (flags
& FIND_NEXT
? -1 : 0);
907 /* FIXME: map positions back to us */
908 return IAVIStream_FindSample(stream
, streamPos
, flags
);
910 /* assume change of format every frame */
915 static HRESULT WINAPI
IEditAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,
916 LPVOID format
,LONG
*fmtsize
)
918 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
919 LPBITMAPINFOHEADER lp
;
924 TRACE("(%p,%d,%p,%p)\n",iface
,pos
,format
,fmtsize
);
926 if (fmtsize
== NULL
|| pos
< This
->sInfo
.dwStart
||
927 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
<= pos
)
928 return AVIERR_BADPARAM
;
930 /* find stream corresponding to position */
931 hr
= AVIFILE_FindStreamInTable(This
, pos
, &stream
, &n
, NULL
, FALSE
);
935 if (! This
->bDecompress
)
936 return IAVIStream_ReadFormat(stream
, n
, format
, fmtsize
);
938 lp
= (LPBITMAPINFOHEADER
)AVIFILE_ReadFrame(This
, stream
, n
);
941 if (lp
->biBitCount
<= 8) {
942 n
= (lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
);
943 n
*= sizeof(RGBQUAD
);
948 memcpy(format
, lp
, min((LONG
)n
, *fmtsize
));
949 hr
= ((LONG
)n
> *fmtsize
? AVIERR_BUFFERTOOSMALL
: AVIERR_OK
);
955 static HRESULT WINAPI
IEditAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,
956 LPVOID format
,LONG formatsize
)
958 TRACE("(%p,%d,%p,%d)\n",iface
,pos
,format
,formatsize
);
960 return AVIERR_UNSUPPORTED
;
963 static HRESULT WINAPI
IEditAVIStream_fnRead(IAVIStream
*iface
,LONG start
,
964 LONG samples
,LPVOID buffer
,
965 LONG buffersize
,LONG
*bytesread
,
968 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
970 DWORD streamPos
, streamNr
;
971 LONG readBytes
, readSamples
, count
;
974 TRACE("(%p,%d,%d,%p,%d,%p,%p) -- 0x%08X\n",iface
,start
,samples
,
975 buffer
,buffersize
,bytesread
,samplesread
,This
->sInfo
.fccType
);
977 /* check parameters */
978 if (bytesread
!= NULL
)
980 if (samplesread
!= NULL
)
983 return AVIERR_BADSIZE
;
984 if ((DWORD
)start
< This
->sInfo
.dwStart
||
985 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< (DWORD
)start
)
986 return AVIERR_BADPARAM
;
988 if (! This
->bDecompress
) {
989 /* audio like data -- sample-based */
992 return AVIERR_OK
; /* nothing at all or already done */
994 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
995 &streamPos
, &streamNr
, FALSE
)))
998 /* limit to end of the stream */
1000 if (streamPos
+ count
> EditStreamEnd(This
, streamNr
))
1001 count
= EditStreamEnd(This
, streamNr
) - streamPos
;
1003 hr
= IAVIStream_Read(stream
, streamPos
, count
, buffer
, buffersize
,
1004 &readBytes
, &readSamples
);
1007 if (readBytes
== 0 && readSamples
== 0 && count
!= 0)
1008 return AVIERR_FILEREAD
; /* for bad stream implementations */
1010 if (samplesread
!= NULL
)
1011 *samplesread
+= readSamples
;
1012 if (bytesread
!= NULL
)
1013 *bytesread
+= readBytes
;
1014 if (buffer
!= NULL
) {
1015 buffer
= ((LPBYTE
)buffer
)+readBytes
;
1016 buffersize
-= readBytes
;
1020 } while (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> start
);
1022 /* video like data -- frame-based */
1023 LPBITMAPINFOHEADER lp
;
1028 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
1029 &streamPos
, &streamNr
, FALSE
)))
1030 return AVIERR_ERROR
;
1032 lp
= AVIFILE_ReadFrame(This
, stream
, streamPos
);
1034 return AVIERR_ERROR
;
1036 if (buffer
!= NULL
) {
1037 /* need size of format to skip */
1038 if (lp
->biBitCount
<= 8) {
1039 count
= lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
;
1040 count
*= sizeof(RGBQUAD
);
1043 count
+= lp
->biSize
;
1045 if (buffersize
< lp
->biSizeImage
)
1046 return AVIERR_BUFFERTOOSMALL
;
1047 memcpy(buffer
, (LPBYTE
)lp
+ count
, lp
->biSizeImage
);
1050 if (bytesread
!= NULL
)
1051 *bytesread
= lp
->biSizeImage
;
1052 if (samplesread
!= NULL
)
1059 static HRESULT WINAPI
IEditAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,
1060 LONG samples
,LPVOID buffer
,
1061 LONG buffersize
,DWORD flags
,
1062 LONG
*sampwritten
,LONG
*byteswritten
)
1064 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n",iface
,start
,samples
,buffer
,
1065 buffersize
,flags
,sampwritten
,byteswritten
);
1067 /* be sure return parameters have correct values */
1068 if (sampwritten
!= NULL
)
1070 if (byteswritten
!= NULL
)
1073 return AVIERR_UNSUPPORTED
;
1076 static HRESULT WINAPI
IEditAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,
1079 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
1081 TRACE("(%p,%d,%d)\n",iface
,start
,samples
);
1083 return IAVIEditStream_Cut((IAVIEditStream
*)This
->pae
,&start
,&samples
,NULL
);
1086 static HRESULT WINAPI
IEditAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,
1087 LPVOID lp
,LONG
*lpread
)
1089 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
1092 TRACE("(%p,0x%08X,%p,%p)\n",iface
,fcc
,lp
,lpread
);
1094 /* check parameters */
1095 if (lp
== NULL
|| lpread
== NULL
)
1096 return AVIERR_BADPARAM
;
1098 /* simply ask every stream and return the first block found */
1099 for (n
= 0; n
< This
->nStreams
; n
++) {
1100 HRESULT hr
= IAVIStream_ReadData(This
->pStreams
[n
].pStream
,fcc
,lp
,lpread
);
1107 return AVIERR_NODATA
;
1110 static HRESULT WINAPI
IEditAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,
1111 LPVOID lp
,LONG size
)
1113 TRACE("(%p,0x%08X,%p,%d)\n",iface
,fcc
,lp
,size
);
1115 return AVIERR_UNSUPPORTED
;
1118 static HRESULT WINAPI
IEditAVIStream_fnSetInfo(IAVIStream
*iface
,
1119 AVISTREAMINFOW
*info
,LONG len
)
1121 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
1123 TRACE("(%p,%p,%d)\n",iface
,info
,len
);
1125 return IAVIEditStream_SetInfo((IAVIEditStream
*)This
->pae
,info
,len
);
1128 static HRESULT WINAPI
IEditStreamInternal_fnQueryInterface(IEditStreamInternal
*iface
,REFIID refiid
,LPVOID
*obj
)
1130 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1132 assert(This
->pae
!= NULL
);
1134 return IAVIEditStream_QueryInterface((IAVIEditStream
*)This
->pae
, refiid
, obj
);
1137 static ULONG WINAPI
IEditStreamInternal_fnAddRef(IEditStreamInternal
*iface
)
1139 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1141 assert(This
->pae
!= NULL
);
1143 return IAVIEditStream_AddRef((IAVIEditStream
*)This
->pae
);
1146 static ULONG WINAPI
IEditStreamInternal_fnRelease(IEditStreamInternal
*iface
)
1148 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1150 assert(This
->pae
!= NULL
);
1152 return IAVIEditStream_Release((IAVIEditStream
*)This
->pae
);
1155 static HRESULT WINAPI
IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal
*iface
,LPVOID
*ppimpl
)
1157 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1159 TRACE("(%p,%p) -> %p\n", iface
, ppimpl
, This
->pae
);
1161 assert(This
->pae
!= NULL
);
1162 assert(ppimpl
!= NULL
);
1164 *ppimpl
= This
->pae
;