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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #define COM_NO_WINDOWS_H
33 #include "avifile_private.h"
34 #include "extrachunk.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(avifile
);
40 /***********************************************************************/
42 /* internal interface to get access to table of stream in an editable stream */
43 typedef struct IEditStreamInternal IEditStreamInternal
;
45 typedef struct _EditStreamTable
{
46 PAVISTREAM pStream
; /* stream which contains the data */
47 DWORD dwStart
; /* where starts the part which is also our */
48 DWORD dwLength
; /* how many is also in this stream */
51 #define INTERFACE IEditStreamInternal
52 #define IEditStreamInternal_METHODS \
54 STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
55 DECLARE_INTERFACE_(IEditStreamInternal
, IUnknown
) { IEditStreamInternal_METHODS
};
58 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
59 (This)->pStreams[streamNr].dwLength)
61 /***********************************************************************/
63 static HRESULT WINAPI
IAVIEditStream_fnQueryInterface(IAVIEditStream
*iface
,REFIID refiid
,LPVOID
*obj
);
64 static ULONG WINAPI
IAVIEditStream_fnAddRef(IAVIEditStream
*iface
);
65 static ULONG WINAPI
IAVIEditStream_fnRelease(IAVIEditStream
*iface
);
66 static HRESULT WINAPI
IAVIEditStream_fnCut(IAVIEditStream
*iface
,LONG
*plStart
,
67 LONG
*plLength
,PAVISTREAM
*ppResult
);
68 static HRESULT WINAPI
IAVIEditStream_fnCopy(IAVIEditStream
*iface
,LONG
*plStart
,
69 LONG
*plLength
,PAVISTREAM
*ppResult
);
70 static HRESULT WINAPI
IAVIEditStream_fnPaste(IAVIEditStream
*iface
,LONG
*plStart
,
71 LONG
*plLength
,PAVISTREAM pSource
,
72 LONG lStart
,LONG lEnd
);
73 static HRESULT WINAPI
IAVIEditStream_fnClone(IAVIEditStream
*iface
,
75 static HRESULT WINAPI
IAVIEditStream_fnSetInfo(IAVIEditStream
*iface
,
76 LPAVISTREAMINFOW asi
,LONG size
);
78 struct IAVIEditStreamVtbl ieditstream
= {
79 IAVIEditStream_fnQueryInterface
,
80 IAVIEditStream_fnAddRef
,
81 IAVIEditStream_fnRelease
,
83 IAVIEditStream_fnCopy
,
84 IAVIEditStream_fnPaste
,
85 IAVIEditStream_fnClone
,
86 IAVIEditStream_fnSetInfo
89 static HRESULT WINAPI
IEditAVIStream_fnQueryInterface(IAVIStream
*iface
,REFIID refiid
,LPVOID
*obj
);
90 static ULONG WINAPI
IEditAVIStream_fnAddRef(IAVIStream
*iface
);
91 static ULONG WINAPI
IEditAVIStream_fnRelease(IAVIStream
*iface
);
92 static HRESULT WINAPI
IEditAVIStream_fnCreate(IAVIStream
*iface
,LPARAM lParam1
,LPARAM lParam2
);
93 static HRESULT WINAPI
IEditAVIStream_fnInfo(IAVIStream
*iface
,AVISTREAMINFOW
*psi
,LONG size
);
94 static LONG WINAPI
IEditAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,
96 static HRESULT WINAPI
IEditAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG
*formatsize
);
97 static HRESULT WINAPI
IEditAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,LPVOID format
,LONG formatsize
);
98 static HRESULT WINAPI
IEditAVIStream_fnRead(IAVIStream
*iface
,LONG start
,
99 LONG samples
,LPVOID buffer
,
100 LONG buffersize
,LONG
*bytesread
,
102 static HRESULT WINAPI
IEditAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,
103 LONG samples
,LPVOID buffer
,
104 LONG buffersize
,DWORD flags
,
105 LONG
*sampwritten
,LONG
*byteswritten
);
106 static HRESULT WINAPI
IEditAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,LONG samples
);
107 static HRESULT WINAPI
IEditAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,
108 LPVOID lp
,LONG
*lpread
);
109 static HRESULT WINAPI
IEditAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,
110 LPVOID lp
,LONG size
);
111 static HRESULT WINAPI
IEditAVIStream_fnSetInfo(IAVIStream
*iface
,AVISTREAMINFOW
*info
,LONG infolen
);
113 struct IAVIStreamVtbl ieditstast
= {
114 IEditAVIStream_fnQueryInterface
,
115 IEditAVIStream_fnAddRef
,
116 IEditAVIStream_fnRelease
,
117 IEditAVIStream_fnCreate
,
118 IEditAVIStream_fnInfo
,
119 IEditAVIStream_fnFindSample
,
120 IEditAVIStream_fnReadFormat
,
121 IEditAVIStream_fnSetFormat
,
122 IEditAVIStream_fnRead
,
123 IEditAVIStream_fnWrite
,
124 IEditAVIStream_fnDelete
,
125 IEditAVIStream_fnReadData
,
126 IEditAVIStream_fnWriteData
,
127 IEditAVIStream_fnSetInfo
130 static HRESULT WINAPI
IEditStreamInternal_fnQueryInterface(IEditStreamInternal
*iface
,REFIID refiid
,LPVOID
*obj
);
131 static ULONG WINAPI
IEditStreamInternal_fnAddRef(IEditStreamInternal
*iface
);
132 static ULONG WINAPI
IEditStreamInternal_fnRelease(IEditStreamInternal
*iface
);
133 static HRESULT WINAPI
IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal
*iface
,LPVOID
*ppimpl
);
135 struct IEditStreamInternalVtbl ieditstreaminternal
= {
136 IEditStreamInternal_fnQueryInterface
,
137 IEditStreamInternal_fnAddRef
,
138 IEditStreamInternal_fnRelease
,
139 IEditStreamInternal_fnGetEditStreamImpl
142 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl
;
144 typedef struct _IEditAVIStreamImpl
{
146 IAVIStreamVtbl
*lpVtbl
;
148 /* IAVIStream stuff */
149 IAVIEditStreamImpl
*pae
;
150 } IEditAVIStreamImpl
;
152 typedef struct _IEditStreamInternalImpl
{
154 IEditStreamInternalVtbl
*lpVtbl
;
156 /* IEditStreamInternal stuff */
157 IAVIEditStreamImpl
*pae
;
158 } IEditStreamInternalImpl
;
160 struct _IAVIEditStreamImpl
{
162 IAVIEditStreamVtbl
*lpVtbl
;
165 /* IAVIEditStream stuff */
166 IEditAVIStreamImpl iAVIStream
;
167 IEditStreamInternalImpl iEditStreamInternal
;
169 AVISTREAMINFOW sInfo
;
171 EditStreamTable
*pStreams
;
172 DWORD nStreams
; /* current fill level of pStreams table */
173 DWORD nTableSize
; /* size of pStreams table */
176 PAVISTREAM pCurStream
;
177 PGETFRAME pg
; /* IGetFrame for pCurStream */
178 LPBITMAPINFOHEADER lpFrame
; /* frame of pCurStream */
181 /***********************************************************************/
183 PAVIEDITSTREAM
AVIFILE_CreateEditStream(PAVISTREAM pstream
)
185 IAVIEditStreamImpl
*pedit
= NULL
;
187 pedit
= (IAVIEditStreamImpl
*)LocalAlloc(LPTR
,sizeof(IAVIEditStreamImpl
));
191 pedit
->lpVtbl
= &ieditstream
;
192 pedit
->iAVIStream
.lpVtbl
= &ieditstast
;
193 pedit
->iAVIStream
.pae
= pedit
;
194 pedit
->iEditStreamInternal
.lpVtbl
= &ieditstreaminternal
;
195 pedit
->iEditStreamInternal
.pae
= pedit
;
198 IAVIStream_Create((PAVISTREAM
)&pedit
->iAVIStream
,(LPARAM
)pstream
,0);
200 return (PAVIEDITSTREAM
)pedit
;
203 static HRESULT
AVIFILE_FindStreamInTable(IAVIEditStreamImpl
* const This
,
204 DWORD pos
,PAVISTREAM
*ppStream
,
206 DWORD
* streamNr
,BOOL bFindSample
)
210 TRACE("(%p,%lu,%p,%p,%p,%d)\n",This
,pos
,ppStream
,streamPos
,
211 streamNr
,bFindSample
);
213 if (pos
< This
->sInfo
.dwStart
)
214 return AVIERR_BADPARAM
;
216 pos
-= This
->sInfo
.dwStart
;
217 for (n
= 0; n
< This
->nStreams
; n
++) {
218 if (pos
< This
->pStreams
[n
].dwLength
) {
219 *ppStream
= This
->pStreams
[n
].pStream
;
220 *streamPos
= This
->pStreams
[n
].dwStart
+ pos
;
221 if (streamNr
!= NULL
)
226 pos
-= This
->pStreams
[n
].dwLength
;
228 if (pos
== 0 && bFindSample
) {
229 *ppStream
= This
->pStreams
[--n
].pStream
;
230 *streamPos
= EditStreamEnd(This
, n
);
231 if (streamNr
!= NULL
)
234 TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream
, *streamPos
, n
);
239 if (streamNr
!= NULL
)
242 TRACE(" -> ERROR (NULL,0,0)\n");
243 return AVIERR_BADPARAM
;
247 static LPVOID
AVIFILE_ReadFrame(IAVIEditStreamImpl
* const This
,
248 PAVISTREAM pstream
, LONG pos
)
252 TRACE("(%p,%p,%ld)\n",This
,pstream
,pos
);
257 /* if stream changes make sure that only palette changes */
258 if (This
->pCurStream
!= pstream
) {
259 pg
= AVIStreamGetFrameOpen(pstream
, NULL
);
262 if (This
->pg
!= NULL
) {
263 if (IGetFrame_SetFormat(pg
, This
->lpFrame
, NULL
, 0, 0, -1, -1)) {
264 AVIStreamGetFrameClose(pg
);
265 ERR(": IGetFrame_SetFormat failed\n");
268 AVIStreamGetFrameClose(This
->pg
);
271 This
->pCurStream
= pstream
;
274 /* now get the decompressed frame */
275 This
->lpFrame
= AVIStreamGetFrame(This
->pg
, pos
);
276 if (This
->lpFrame
!= NULL
)
277 This
->sInfo
.dwSuggestedBufferSize
= This
->lpFrame
->biSizeImage
;
279 return This
->lpFrame
;
282 static HRESULT
AVIFILE_RemoveStream(IAVIEditStreamImpl
* const This
, DWORD nr
)
284 assert(This
!= NULL
);
285 assert(nr
< This
->nStreams
);
288 IAVIStream_Release(This
->pStreams
[nr
].pStream
);
290 if (This
->nStreams
- nr
> 0) {
291 memmove(This
->pStreams
+ nr
, This
->pStreams
+ nr
+ 1,
292 (This
->nStreams
- nr
) * sizeof(EditStreamTable
));
294 This
->pStreams
[This
->nStreams
].pStream
= NULL
;
295 This
->pStreams
[This
->nStreams
].dwStart
= 0;
296 This
->pStreams
[This
->nStreams
].dwLength
= 0;
298 /* try to merge the part before the deleted one and the one after it */
299 if (0 < nr
&& 0 < This
->nStreams
&&
300 This
->pStreams
[nr
- 1].pStream
== This
->pStreams
[nr
].pStream
) {
301 if (EditStreamEnd(This
, nr
- 1) == This
->pStreams
[nr
].dwStart
) {
302 This
->pStreams
[nr
- 1].dwLength
+= This
->pStreams
[nr
].dwLength
;
303 return AVIFILE_RemoveStream(This
, nr
);
310 static BOOL
AVIFILE_FormatsEqual(PAVISTREAM avi1
, PAVISTREAM avi2
)
312 LPVOID fmt1
= NULL
, fmt2
= NULL
;
313 LONG size1
, size2
, start1
, start2
;
316 assert(avi1
!= NULL
&& avi2
!= NULL
);
318 /* get stream starts and check format sizes */
319 start1
= AVIStreamStart(avi1
);
320 start2
= AVIStreamStart(avi2
);
321 if (FAILED(AVIStreamFormatSize(avi1
, start1
, &size1
)))
323 if (FAILED(AVIStreamFormatSize(avi2
, start2
, &size2
)))
328 /* sizes match, now get formats and compare them */
329 fmt1
= GlobalAllocPtr(GHND
, size1
);
332 if (SUCCEEDED(AVIStreamReadFormat(avi1
, start1
, fmt1
, &size1
))) {
333 fmt2
= GlobalAllocPtr(GHND
, size1
);
335 if (SUCCEEDED(AVIStreamReadFormat(avi2
, start2
, fmt2
, &size1
)))
336 status
= (memcmp(fmt1
, fmt2
, size1
) == 0);
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
;
380 TRACE("(%p) -> %ld\n", iface
, This
->ref
+ 1);
381 return ++(This
->ref
);
384 static ULONG WINAPI
IAVIEditStream_fnRelease(IAVIEditStream
*iface
)
386 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
389 TRACE("(%p) -> %ld\n", iface
, This
->ref
- 1);
391 if (!--(This
->ref
)) {
392 /* releaase memory */
393 if (This
->pg
!= NULL
)
394 AVIStreamGetFrameClose(This
->pg
);
395 if (This
->pStreams
!= NULL
) {
396 for (i
= 0; i
< This
->nStreams
; i
++) {
397 if (This
->pStreams
[i
].pStream
!= NULL
)
398 IAVIStream_Release(This
->pStreams
[i
].pStream
);
400 GlobalFreePtr(This
->pStreams
);
403 LocalFree((HLOCAL
)This
);
409 static HRESULT WINAPI
IAVIEditStream_fnCut(IAVIEditStream
*iface
,LONG
*plStart
,
410 LONG
*plLength
,PAVISTREAM
*ppResult
)
412 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
414 DWORD start
, len
, streamPos
, streamNr
;
417 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
419 if (ppResult
!= NULL
)
421 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0)
422 return AVIERR_BADPARAM
;
424 /* if asked for cutted part copy it before deleting */
425 if (ppResult
!= NULL
) {
426 hr
= IAVIEditStream_Copy(iface
, plStart
, plLength
, ppResult
);
434 /* now delete the requested part */
436 hr
= AVIFILE_FindStreamInTable(This
, start
, &stream
,
437 &streamPos
, &streamNr
, FALSE
);
440 if (This
->pStreams
[streamNr
].dwStart
== streamPos
) {
441 /* deleting from start of part */
442 if (len
< This
->pStreams
[streamNr
].dwLength
) {
444 This
->pStreams
[streamNr
].dwStart
+= len
;
445 This
->pStreams
[streamNr
].dwLength
-= len
;
446 This
->sInfo
.dwLength
-= len
;
449 /* we must return decompressed data now */
450 This
->bDecompress
= TRUE
;
452 /* deleting hole part */
453 len
-= This
->pStreams
[streamNr
].dwLength
;
454 AVIFILE_RemoveStream(This
,streamNr
);
456 } else if (EditStreamEnd(This
, streamNr
) <= streamPos
+ len
) {
457 /* deleting at end of a part */
458 DWORD count
= EditStreamEnd(This
, streamNr
) - streamPos
;
459 This
->sInfo
.dwLength
-= count
;
461 This
->pStreams
[streamNr
].dwLength
=
462 streamPos
- This
->pStreams
[streamNr
].dwStart
;
465 if (This
->nStreams
+ 1 >= This
->nTableSize
) {
467 GlobalReAllocPtr(This
->pStreams
, (This
->nTableSize
+ 32) * sizeof(EditStreamTable
), GMEM_SHARE
|GHND
);
468 if (This
->pStreams
== NULL
)
469 return AVIERR_MEMORY
;
470 This
->nTableSize
+= 32;
472 memmove(This
->pStreams
+ streamNr
+ 1, This
->pStreams
+ streamNr
,
473 (This
->nStreams
- streamNr
) * sizeof(EditStreamTable
));
476 IAVIStream_AddRef(This
->pStreams
[streamNr
+ 1].pStream
);
477 This
->pStreams
[streamNr
+ 1].dwStart
= streamPos
+ len
;
478 This
->pStreams
[streamNr
+ 1].dwLength
=
479 EditStreamEnd(This
, streamNr
) - This
->pStreams
[streamNr
+ 1].dwStart
;
481 This
->pStreams
[streamNr
].dwLength
=
482 streamPos
- This
->pStreams
[streamNr
].dwStart
;
483 This
->sInfo
.dwLength
-= len
;
488 This
->sInfo
.dwEditCount
++;
493 static HRESULT WINAPI
IAVIEditStream_fnCopy(IAVIEditStream
*iface
,LONG
*plStart
,
494 LONG
*plLength
,PAVISTREAM
*ppResult
)
496 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
497 IAVIEditStreamImpl
* pEdit
;
501 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
503 if (ppResult
== NULL
)
504 return AVIERR_BADPARAM
;
506 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0 || *plLength
< 0)
507 return AVIERR_BADPARAM
;
510 if (*(LPDWORD
)plLength
> This
->sInfo
.dwLength
)
511 *(LPDWORD
)plLength
= This
->sInfo
.dwLength
;
512 if (*(LPDWORD
)plStart
< This
->sInfo
.dwStart
) {
513 *(LPDWORD
)plLength
-= This
->sInfo
.dwStart
- *(LPDWORD
)plStart
;
514 *(LPDWORD
)plStart
= This
->sInfo
.dwStart
;
516 return AVIERR_BADPARAM
;
518 if (*(LPDWORD
)plStart
+ *(LPDWORD
)plLength
> This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
)
519 *(LPDWORD
)plLength
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
-
522 pEdit
= (IAVIEditStreamImpl
*)AVIFILE_CreateEditStream(NULL
);
524 return AVIERR_MEMORY
;
526 hr
= IAVIEditStream_Paste((PAVIEDITSTREAM
)pEdit
,&start
,plLength
,
527 (PAVISTREAM
)&This
->iAVIStream
,*plStart
,
528 *plStart
+ *plLength
);
531 IAVIEditStream_Release((PAVIEDITSTREAM
)pEdit
);
533 *ppResult
= (PAVISTREAM
)&pEdit
->iAVIStream
;
538 static HRESULT WINAPI
IAVIEditStream_fnPaste(IAVIEditStream
*iface
,LONG
*plStart
,
539 LONG
*plLength
,PAVISTREAM pSource
,
540 LONG lStart
,LONG lLength
)
542 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
543 AVISTREAMINFOW srcInfo
;
544 IEditStreamInternal
*pInternal
= NULL
;
545 IAVIEditStreamImpl
*pEdit
= NULL
;
547 DWORD startPos
, endPos
, streamNr
, nStreams
;
550 TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface
,plStart
,plLength
,
551 pSource
,lStart
,lLength
);
554 return AVIERR_BADHANDLE
;
555 if (plStart
== NULL
|| *plStart
< 0)
556 return AVIERR_BADPARAM
;
557 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< *plStart
)
558 return AVIERR_BADPARAM
; /* Can't paste with holes */
559 if (FAILED(IAVIStream_Info(pSource
, &srcInfo
, sizeof(srcInfo
))))
561 if (lStart
< srcInfo
.dwStart
|| lStart
>= srcInfo
.dwStart
+ srcInfo
.dwLength
)
562 return AVIERR_BADPARAM
;
563 if (This
->sInfo
.fccType
== 0) {
564 /* This stream is empty */
565 IAVIStream_Info(pSource
, &This
->sInfo
, sizeof(This
->sInfo
));
566 This
->sInfo
.dwStart
= *plStart
;
567 This
->sInfo
.dwLength
= 0;
569 if (This
->sInfo
.fccType
!= srcInfo
.fccType
)
570 return AVIERR_UNSUPPORTED
; /* different stream types */
571 if (lLength
== -1) /* Copy the hole stream */
572 lLength
= srcInfo
.dwLength
;
573 if (lStart
+ lLength
> srcInfo
.dwStart
+ srcInfo
.dwLength
)
574 lLength
= srcInfo
.dwStart
+ srcInfo
.dwLength
- lStart
;
575 if (lLength
+ *plStart
>= 0x80000000)
576 return AVIERR_MEMORY
;
578 /* streamtype specific tests */
579 if (srcInfo
.fccType
== streamtypeVIDEO
) {
582 size
= srcInfo
.rcFrame
.right
- srcInfo
.rcFrame
.left
;
583 if (size
!= This
->sInfo
.rcFrame
.right
- This
->sInfo
.rcFrame
.left
)
584 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
585 size
= srcInfo
.rcFrame
.bottom
- srcInfo
.rcFrame
.top
;
586 if (size
!= This
->sInfo
.rcFrame
.bottom
- This
->sInfo
.rcFrame
.top
)
587 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
588 } else if (srcInfo
.fccType
== streamtypeAUDIO
) {
589 if (! AVIFILE_FormatsEqual((PAVISTREAM
)&This
->iAVIStream
, pSource
))
590 return AVIERR_UNSUPPORTED
;
592 /* FIXME: streamtypeMIDI and streamtypeTEXT */
593 return AVIERR_UNSUPPORTED
;
596 /* try to get an IEditStreamInternal interface */
597 if (SUCCEEDED(IAVIStream_QueryInterface(pSource
, &IID_IEditStreamInternal
,
598 (LPVOID
*)&pInternal
))) {
599 pInternal
->lpVtbl
->GetEditStreamImpl(pInternal
, (LPVOID
*)&pEdit
);
600 pInternal
->lpVtbl
->Release(pInternal
);
603 /* for video must check for change of format */
604 if (This
->sInfo
.fccType
== streamtypeVIDEO
) {
605 if (! This
->bDecompress
) {
606 /* Need to decompress if any of the following conditions matches:
607 * - pSource is an editable stream which decompresses
608 * - the nearest keyframe of pSource isn't lStart
609 * - the nearest keyframe of this stream isn't *plStart
610 * - the format of pSource doesn't match this one
612 if ((pEdit
!= NULL
&& pEdit
->bDecompress
) ||
613 AVIStreamNearestKeyFrame(pSource
, lStart
) != lStart
||
614 AVIStreamNearestKeyFrame((PAVISTREAM
)&This
->iAVIStream
, *plStart
) != *plStart
||
615 (This
->nStreams
> 0 && !AVIFILE_FormatsEqual((PAVISTREAM
)&This
->iAVIStream
, pSource
))) {
616 /* Use first stream part to get format to convert everything to */
617 AVIFILE_ReadFrame(This
, This
->pStreams
[0].pStream
,
618 This
->pStreams
[0].dwStart
);
620 /* Check if we could convert the source streams to the disired format... */
622 if (FAILED(AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
623 &startPos
, &streamNr
, TRUE
)))
624 return AVIERR_INTERNAL
;
625 for (n
= lStart
; n
< lStart
+ lLength
; streamNr
++) {
626 if (AVIFILE_ReadFrame(This
, pEdit
->pStreams
[streamNr
].pStream
, startPos
) == NULL
)
627 return AVIERR_BADFORMAT
;
628 startPos
= pEdit
->pStreams
[streamNr
].dwStart
;
629 n
+= pEdit
->pStreams
[streamNr
].dwLength
;
631 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
632 return AVIERR_BADFORMAT
;
634 This
->bDecompress
= TRUE
;
635 This
->sInfo
.fccHandler
= 0;
637 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
638 return AVIERR_BADFORMAT
; /* Can't convert source to own format */
639 } /* FIXME: something special for the other formats? */
641 /* Make sure we have enough memory for parts */
645 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
646 &endPos
, &nLastStream
, TRUE
);
647 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
648 &startPos
, &streamNr
, FALSE
);
649 if (nLastStream
== streamNr
)
652 nStreams
= nLastStream
- streamNr
;
655 if (This
->nStreams
+ nStreams
+ 1 > This
->nTableSize
) {
656 n
= This
->nStreams
+ nStreams
+ 33;
659 GlobalReAllocPtr(This
->pStreams
, n
* sizeof(EditStreamTable
), GMEM_SHARE
|GHND
);
660 if (This
->pStreams
== NULL
)
661 return AVIERR_MEMORY
;
662 This
->nTableSize
= n
;
665 if (plLength
!= NULL
)
668 /* now do the real work */
669 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> *plStart
) {
670 AVIFILE_FindStreamInTable(This
, *plStart
, &pStream
,
671 &startPos
, &streamNr
, FALSE
);
672 if (startPos
!= This
->pStreams
[streamNr
].dwStart
) {
673 /* split stream streamNr at startPos */
674 memmove(This
->pStreams
+ streamNr
+ nStreams
+ 1,
675 This
->pStreams
+ streamNr
,
676 (This
->nStreams
+ nStreams
- streamNr
+ 1) * sizeof(EditStreamTable
));
678 This
->pStreams
[streamNr
+ 2].dwLength
=
679 EditStreamEnd(This
, streamNr
+ 2) - startPos
;
680 This
->pStreams
[streamNr
+ 2].dwStart
= startPos
;
681 This
->pStreams
[streamNr
].dwLength
=
682 startPos
- This
->pStreams
[streamNr
].dwStart
;
683 IAVIStream_AddRef(This
->pStreams
[streamNr
].pStream
);
686 /* insert before stream at streamNr */
687 memmove(This
->pStreams
+ streamNr
+ nStreams
, This
->pStreams
+ streamNr
,
688 (This
->nStreams
+ nStreams
- streamNr
) * sizeof(EditStreamTable
));
690 } else /* append the streams */
691 streamNr
= This
->nStreams
;
694 /* insert the parts of the editable stream instead of itself */
695 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
696 &endPos
, NULL
, FALSE
);
697 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
, &startPos
, &n
, FALSE
);
699 memcpy(This
->pStreams
+ streamNr
, pEdit
->pStreams
+ n
,
700 nStreams
* sizeof(EditStreamTable
));
701 if (This
->pStreams
[streamNr
].dwStart
< startPos
) {
702 This
->pStreams
[streamNr
].dwLength
=
703 EditStreamEnd(This
, streamNr
) - startPos
;
704 This
->pStreams
[streamNr
].dwStart
= startPos
;
706 if (endPos
< EditStreamEnd(This
, streamNr
+ nStreams
))
707 This
->pStreams
[streamNr
+ nStreams
].dwLength
=
708 endPos
- This
->pStreams
[streamNr
+ nStreams
].dwStart
;
710 /* a simple stream */
711 This
->pStreams
[streamNr
].pStream
= pSource
;
712 This
->pStreams
[streamNr
].dwStart
= lStart
;
713 This
->pStreams
[streamNr
].dwLength
= lLength
;
716 for (n
= 0; n
< nStreams
; n
++) {
717 IAVIStream_AddRef(This
->pStreams
[streamNr
+ n
].pStream
);
718 if (0 < streamNr
+ n
&&
719 This
->pStreams
[streamNr
+ n
- 1].pStream
!= This
->pStreams
[streamNr
+ n
].pStream
) {
720 This
->sInfo
.dwFlags
|= AVISTREAMINFO_FORMATCHANGES
;
721 This
->sInfo
.dwFormatChangeCount
++;
724 This
->sInfo
.dwEditCount
++;
725 This
->sInfo
.dwLength
+= lLength
;
726 This
->nStreams
+= nStreams
;
731 static HRESULT WINAPI
IAVIEditStream_fnClone(IAVIEditStream
*iface
,
734 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
735 IAVIEditStreamImpl
* pEdit
;
738 TRACE("(%p,%p)\n",iface
,ppResult
);
740 if (ppResult
== NULL
)
741 return AVIERR_BADPARAM
;
744 pEdit
= (IAVIEditStreamImpl
*)AVIFILE_CreateEditStream(NULL
);
746 return AVIERR_MEMORY
;
747 if (This
->nStreams
> pEdit
->nTableSize
) {
748 pEdit
->pStreams
= GlobalReAllocPtr(pEdit
->pStreams
, This
->nStreams
* sizeof(EditStreamTable
),GMEM_SHARE
|GHND
);
749 if (pEdit
->pStreams
== NULL
)
750 return AVIERR_MEMORY
;
751 pEdit
->nTableSize
= This
->nStreams
;
753 pEdit
->nStreams
= This
->nStreams
;
754 memcpy(pEdit
->pStreams
, This
->pStreams
,
755 This
->nStreams
* sizeof(EditStreamTable
));
756 memcpy(&pEdit
->sInfo
,&This
->sInfo
,sizeof(This
->sInfo
));
757 for (i
= 0; i
< This
->nStreams
; i
++) {
758 if (pEdit
->pStreams
[i
].pStream
!= NULL
)
759 IAVIStream_AddRef(pEdit
->pStreams
[i
].pStream
);
762 *ppResult
= (PAVISTREAM
)&pEdit
->iAVIStream
;
767 static HRESULT WINAPI
IAVIEditStream_fnSetInfo(IAVIEditStream
*iface
,
768 LPAVISTREAMINFOW asi
,LONG size
)
770 IAVIEditStreamImpl
*This
= (IAVIEditStreamImpl
*)iface
;
772 TRACE("(%p,%p,%ld)\n",iface
,asi
,size
);
774 /* check parameters */
776 return AVIERR_BADPARAM
;
777 if (size
!= sizeof(AVISTREAMINFOW
))
778 return AVIERR_BADSIZE
;
779 if (asi
->dwScale
== 0 || asi
->dwRate
== 0 || (LONG
)asi
->dwQuality
< -1 ||
780 asi
->dwQuality
> ICQUALITY_HIGH
)
783 This
->sInfo
.wLanguage
= asi
->wLanguage
;
784 This
->sInfo
.wPriority
= asi
->wPriority
;
785 This
->sInfo
.dwStart
= asi
->dwStart
;
786 if (asi
->dwRate
!= 0)
787 This
->sInfo
.dwRate
= asi
->dwRate
;
788 if (asi
->dwScale
!= 0)
789 This
->sInfo
.dwScale
= asi
->dwScale
;
790 if (asi
->dwQuality
<= ICQUALITY_HIGH
)
791 This
->sInfo
.dwQuality
= ICQUALITY_HIGH
;
792 CopyRect(&This
->sInfo
.rcFrame
, &asi
->rcFrame
);
793 memcpy(&This
->sInfo
.szName
, &asi
->szName
, sizeof(asi
->szName
));
794 This
->sInfo
.dwEditCount
++;
799 static HRESULT WINAPI
IEditAVIStream_fnQueryInterface(IAVIStream
*iface
,
800 REFIID refiid
,LPVOID
*obj
)
802 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
804 assert(This
->pae
!= NULL
);
806 return IAVIEditStream_QueryInterface((IAVIEditStream
*)This
->pae
,refiid
,obj
);
809 static ULONG WINAPI
IEditAVIStream_fnAddRef(IAVIStream
*iface
)
811 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
813 assert(This
->pae
!= NULL
);
815 return IAVIEditStream_AddRef((IAVIEditStream
*)This
->pae
);
818 static ULONG WINAPI
IEditAVIStream_fnRelease(IAVIStream
*iface
)
820 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
822 assert(This
->pae
!= NULL
);
824 return IAVIEditStream_Release((IAVIEditStream
*)This
->pae
);
827 static HRESULT WINAPI
IEditAVIStream_fnCreate(IAVIStream
*iface
,
828 LPARAM lParam1
,LPARAM lParam2
)
830 IAVIEditStreamImpl
*This
= ((IEditAVIStreamImpl
*)iface
)->pae
;
835 if (This
->pStreams
== NULL
) {
837 GlobalAllocPtr(GMEM_SHARE
|GHND
, 256 * sizeof(EditStreamTable
));
838 if (This
->pStreams
== NULL
)
839 return AVIERR_MEMORY
;
840 This
->nTableSize
= 256;
844 IAVIStream_Info((PAVISTREAM
)lParam1
, &This
->sInfo
, sizeof(This
->sInfo
));
845 IAVIStream_AddRef((PAVISTREAM
)lParam1
);
846 This
->pStreams
[0].pStream
= (PAVISTREAM
)lParam1
;
847 This
->pStreams
[0].dwStart
= This
->sInfo
.dwStart
;
848 This
->pStreams
[0].dwLength
= This
->sInfo
.dwLength
;
854 static HRESULT WINAPI
IEditAVIStream_fnInfo(IAVIStream
*iface
,
855 AVISTREAMINFOW
*psi
,LONG size
)
857 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
859 TRACE("(%p,%p,%ld)\n",iface
,psi
,size
);
861 assert(This
->pae
!= NULL
);
864 return AVIERR_BADPARAM
;
866 return AVIERR_BADSIZE
;
868 if (This
->pae
->bDecompress
)
869 This
->pae
->sInfo
.fccHandler
= 0;
871 memcpy(psi
, &This
->pae
->sInfo
, min((DWORD
)size
, sizeof(This
->pae
->sInfo
)));
873 if ((DWORD
)size
< sizeof(This
->pae
->sInfo
))
874 return AVIERR_BUFFERTOOSMALL
;
878 static LONG WINAPI
IEditAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,
881 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
883 DWORD streamPos
, streamNr
;
885 TRACE("(%p,%ld,0x%08lX)\n",iface
,pos
,flags
);
887 if (flags
& FIND_FROM_START
)
888 pos
= (LONG
)This
->sInfo
.dwStart
;
890 /* outside of stream? */
891 if (pos
< (LONG
)This
->sInfo
.dwStart
||
892 (LONG
)This
->sInfo
.dwStart
+ (LONG
)This
->sInfo
.dwLength
<= pos
)
895 /* map our position to a stream and position in it */
896 if (AVIFILE_FindStreamInTable(This
, pos
, &stream
, &streamPos
,
898 return -1; /* doesn't exist */
900 if (This
->bDecompress
) {
901 /* only one stream -- format changes only at start */
902 if (flags
& FIND_FORMAT
)
903 return (flags
& FIND_NEXT
? -1 : 0);
905 /* FIXME: map positions back to us */
906 return IAVIStream_FindSample(stream
, streamPos
, flags
);
908 /* assume change of format every frame */
913 static HRESULT WINAPI
IEditAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,
914 LPVOID format
,LONG
*fmtsize
)
916 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
917 LPBITMAPINFOHEADER lp
;
922 TRACE("(%p,%ld,%p,%p)\n",iface
,pos
,format
,fmtsize
);
924 if (fmtsize
== NULL
|| pos
< This
->sInfo
.dwStart
||
925 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
<= pos
)
926 return AVIERR_BADPARAM
;
928 /* find stream corresponding to position */
929 hr
= AVIFILE_FindStreamInTable(This
, pos
, &stream
, &n
, NULL
, FALSE
);
933 if (! This
->bDecompress
)
934 return IAVIStream_ReadFormat(stream
, n
, format
, fmtsize
);
936 lp
= (LPBITMAPINFOHEADER
)AVIFILE_ReadFrame(This
, stream
, n
);
939 if (lp
->biBitCount
<= 8) {
940 n
= (lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
);
941 n
*= sizeof(RGBQUAD
);
946 memcpy(format
, lp
, min((LONG
)n
, *fmtsize
));
947 hr
= ((LONG
)n
> *fmtsize
? AVIERR_BUFFERTOOSMALL
: AVIERR_OK
);
953 static HRESULT WINAPI
IEditAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,
954 LPVOID format
,LONG formatsize
)
956 TRACE("(%p,%ld,%p,%ld)\n",iface
,pos
,format
,formatsize
);
958 return AVIERR_UNSUPPORTED
;
961 static HRESULT WINAPI
IEditAVIStream_fnRead(IAVIStream
*iface
,LONG start
,
962 LONG samples
,LPVOID buffer
,
963 LONG buffersize
,LONG
*bytesread
,
966 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
968 DWORD streamPos
, streamNr
;
969 LONG readBytes
, readSamples
, count
;
972 TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface
,start
,samples
,
973 buffer
,buffersize
,bytesread
,samplesread
,This
->sInfo
.fccType
);
975 /* check parameters */
976 if (bytesread
!= NULL
)
978 if (samplesread
!= NULL
)
981 return AVIERR_BADSIZE
;
982 if ((DWORD
)start
< This
->sInfo
.dwStart
||
983 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< (DWORD
)start
)
984 return AVIERR_BADPARAM
;
986 if (! This
->bDecompress
) {
987 /* audio like data -- sample-based */
990 return AVIERR_OK
; /* nothing at all or already done */
992 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
993 &streamPos
, &streamNr
, FALSE
)))
996 /* limit to end of the stream */
998 if (streamPos
+ count
> EditStreamEnd(This
, streamNr
))
999 count
= EditStreamEnd(This
, streamNr
) - streamPos
;
1001 hr
= IAVIStream_Read(stream
, streamPos
, count
, buffer
, buffersize
,
1002 &readBytes
, &readSamples
);
1005 if (readBytes
== 0 && readSamples
== 0 && count
!= 0)
1006 return AVIERR_FILEREAD
; /* for bad stream implementations */
1008 if (samplesread
!= NULL
)
1009 *samplesread
+= readSamples
;
1010 if (bytesread
!= NULL
)
1011 *bytesread
+= readBytes
;
1012 if (buffer
!= NULL
) {
1013 buffer
= ((LPBYTE
)buffer
)+readBytes
;
1014 buffersize
-= readBytes
;
1018 } while (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> start
);
1020 /* video like data -- frame-based */
1021 LPBITMAPINFOHEADER lp
;
1026 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
1027 &streamPos
, &streamNr
, FALSE
)))
1028 return AVIERR_ERROR
;
1030 lp
= AVIFILE_ReadFrame(This
, stream
, streamPos
);
1032 return AVIERR_ERROR
;
1034 if (buffer
!= NULL
) {
1035 /* need size of format to skip */
1036 if (lp
->biBitCount
<= 8) {
1037 count
= lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
;
1038 count
*= sizeof(RGBQUAD
);
1041 count
+= lp
->biSize
;
1043 if (buffersize
< lp
->biSizeImage
)
1044 return AVIERR_BUFFERTOOSMALL
;
1045 memcpy(buffer
, (LPBYTE
)lp
+ count
, lp
->biSizeImage
);
1048 if (bytesread
!= NULL
)
1049 *bytesread
= lp
->biSizeImage
;
1050 if (samplesread
!= NULL
)
1057 static HRESULT WINAPI
IEditAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,
1058 LONG samples
,LPVOID buffer
,
1059 LONG buffersize
,DWORD flags
,
1060 LONG
*sampwritten
,LONG
*byteswritten
)
1062 TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface
,start
,samples
,buffer
,
1063 buffersize
,flags
,sampwritten
,byteswritten
);
1065 /* be sure return parameters have correct values */
1066 if (sampwritten
!= NULL
)
1068 if (byteswritten
!= NULL
)
1071 return AVIERR_UNSUPPORTED
;
1074 static HRESULT WINAPI
IEditAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,
1077 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
1079 TRACE("(%p,%ld,%ld)\n",iface
,start
,samples
);
1081 return IAVIEditStream_Cut((IAVIEditStream
*)This
->pae
,&start
,&samples
,NULL
);
1084 static HRESULT WINAPI
IEditAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,
1085 LPVOID lp
,LONG
*lpread
)
1087 IAVIEditStreamImpl
* const This
= ((IEditAVIStreamImpl
* const)iface
)->pae
;
1090 TRACE("(%p,0x%08lX,%p,%p)\n",iface
,fcc
,lp
,lpread
);
1092 /* check parameters */
1093 if (lp
== NULL
|| lpread
== NULL
)
1094 return AVIERR_BADPARAM
;
1096 /* simply ask every stream and return the first block found */
1097 for (n
= 0; n
< This
->nStreams
; n
++) {
1098 HRESULT hr
= IAVIStream_ReadData(This
->pStreams
[n
].pStream
,fcc
,lp
,lpread
);
1105 return AVIERR_NODATA
;
1108 static HRESULT WINAPI
IEditAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,
1109 LPVOID lp
,LONG size
)
1111 TRACE("(%p,0x%08lX,%p,%ld)\n",iface
,fcc
,lp
,size
);
1113 return AVIERR_UNSUPPORTED
;
1116 static HRESULT WINAPI
IEditAVIStream_fnSetInfo(IAVIStream
*iface
,
1117 AVISTREAMINFOW
*info
,LONG len
)
1119 IEditAVIStreamImpl
*This
= (IEditAVIStreamImpl
*)iface
;
1121 TRACE("(%p,%p,%ld)\n",iface
,info
,len
);
1123 return IAVIEditStream_SetInfo((IAVIEditStream
*)This
->pae
,info
,len
);
1126 static HRESULT WINAPI
IEditStreamInternal_fnQueryInterface(IEditStreamInternal
*iface
,REFIID refiid
,LPVOID
*obj
)
1128 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1130 assert(This
->pae
!= NULL
);
1132 return IAVIEditStream_QueryInterface((IAVIEditStream
*)This
->pae
, refiid
, obj
);
1135 static ULONG WINAPI
IEditStreamInternal_fnAddRef(IEditStreamInternal
*iface
)
1137 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1139 assert(This
->pae
!= NULL
);
1141 return IAVIEditStream_AddRef((IAVIEditStream
*)This
->pae
);
1144 static ULONG WINAPI
IEditStreamInternal_fnRelease(IEditStreamInternal
*iface
)
1146 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1148 assert(This
->pae
!= NULL
);
1150 return IAVIEditStream_Release((IAVIEditStream
*)This
->pae
);
1153 static HRESULT WINAPI
IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal
*iface
,LPVOID
*ppimpl
)
1155 IEditStreamInternalImpl
*This
= (IEditStreamInternalImpl
*)iface
;
1157 TRACE("(%p,%p) -> %p\n", iface
, ppimpl
, This
->pae
);
1159 assert(This
->pae
!= NULL
);
1160 assert(ppimpl
!= NULL
);
1162 *ppimpl
= This
->pae
;