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
19 #include "avifile_private.h"
21 /***********************************************************************/
23 /* internal interface to get access to table of stream in an editable stream */
25 DEFINE_AVIGUID(IID_IEditStreamInternal
, 0x0002000A,0,0);
27 typedef struct _EditStreamTable
{
28 PAVISTREAM pStream
; /* stream which contains the data */
29 DWORD dwStart
; /* where starts the part which is also our */
30 DWORD dwLength
; /* how many is also in this stream */
33 #define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
34 (This)->pStreams[streamNr].dwLength)
36 typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl
;
38 struct _IAVIEditStreamImpl
{
39 IAVIEditStream IAVIEditStream_iface
;
40 IAVIStream IAVIStream_iface
;
46 EditStreamTable
*pStreams
;
47 DWORD nStreams
; /* current fill level of pStreams table */
48 DWORD nTableSize
; /* size of pStreams table */
51 PAVISTREAM pCurStream
;
52 PGETFRAME pg
; /* IGetFrame for pCurStream */
53 LPBITMAPINFOHEADER lpFrame
; /* frame of pCurStream */
56 static inline IAVIEditStreamImpl
*impl_from_IAVIEditStream(IAVIEditStream
*iface
)
58 return CONTAINING_RECORD(iface
, IAVIEditStreamImpl
, IAVIEditStream_iface
);
61 static inline IAVIEditStreamImpl
*impl_from_IAVIStream(IAVIStream
*iface
)
63 return CONTAINING_RECORD(iface
, IAVIEditStreamImpl
, IAVIStream_iface
);
66 /***********************************************************************/
68 static HRESULT
AVIFILE_FindStreamInTable(IAVIEditStreamImpl
* const This
,
69 DWORD pos
,PAVISTREAM
*ppStream
,
71 DWORD
* streamNr
,BOOL bFindSample
)
75 TRACE("(%p,%u,%p,%p,%p,%d)\n",This
,pos
,ppStream
,streamPos
,
76 streamNr
,bFindSample
);
78 if (pos
< This
->sInfo
.dwStart
)
79 return AVIERR_BADPARAM
;
81 pos
-= This
->sInfo
.dwStart
;
82 for (n
= 0; n
< This
->nStreams
; n
++) {
83 if (pos
< This
->pStreams
[n
].dwLength
) {
84 *ppStream
= This
->pStreams
[n
].pStream
;
85 *streamPos
= This
->pStreams
[n
].dwStart
+ pos
;
91 pos
-= This
->pStreams
[n
].dwLength
;
93 if (pos
== 0 && bFindSample
) {
94 *ppStream
= This
->pStreams
[--n
].pStream
;
95 *streamPos
= EditStreamEnd(This
, n
);
99 TRACE(" -- pos=0 && b=1 -> (%p,%u,%u)\n",*ppStream
, *streamPos
, n
);
104 if (streamNr
!= NULL
)
107 TRACE(" -> ERROR (NULL,0,0)\n");
108 return AVIERR_BADPARAM
;
112 static LPVOID
AVIFILE_ReadFrame(IAVIEditStreamImpl
* const This
,
113 PAVISTREAM pstream
, LONG pos
)
117 TRACE("(%p,%p,%d)\n",This
,pstream
,pos
);
122 /* if stream changes make sure that only palette changes */
123 if (This
->pCurStream
!= pstream
) {
124 pg
= AVIStreamGetFrameOpen(pstream
, NULL
);
127 if (This
->pg
!= NULL
) {
128 if (IGetFrame_SetFormat(pg
, This
->lpFrame
, NULL
, 0, 0, -1, -1) != S_OK
) {
129 AVIStreamGetFrameClose(pg
);
130 ERR(": IGetFrame_SetFormat failed\n");
133 AVIStreamGetFrameClose(This
->pg
);
136 This
->pCurStream
= pstream
;
139 /* now get the decompressed frame */
140 This
->lpFrame
= AVIStreamGetFrame(This
->pg
, pos
);
141 if (This
->lpFrame
!= NULL
)
142 This
->sInfo
.dwSuggestedBufferSize
= This
->lpFrame
->biSizeImage
;
144 return This
->lpFrame
;
147 static HRESULT
AVIFILE_RemoveStream(IAVIEditStreamImpl
* const This
, DWORD nr
)
149 assert(This
!= NULL
);
150 assert(nr
< This
->nStreams
);
153 IAVIStream_Release(This
->pStreams
[nr
].pStream
);
155 if (This
->nStreams
- nr
> 0) {
156 memmove(This
->pStreams
+ nr
, This
->pStreams
+ nr
+ 1,
157 (This
->nStreams
- nr
) * sizeof(EditStreamTable
));
159 This
->pStreams
[This
->nStreams
].pStream
= NULL
;
160 This
->pStreams
[This
->nStreams
].dwStart
= 0;
161 This
->pStreams
[This
->nStreams
].dwLength
= 0;
163 /* try to merge the part before the deleted one and the one after it */
164 if (0 < nr
&& 0 < This
->nStreams
&&
165 This
->pStreams
[nr
- 1].pStream
== This
->pStreams
[nr
].pStream
) {
166 if (EditStreamEnd(This
, nr
- 1) == This
->pStreams
[nr
].dwStart
) {
167 This
->pStreams
[nr
- 1].dwLength
+= This
->pStreams
[nr
].dwLength
;
168 return AVIFILE_RemoveStream(This
, nr
);
175 static BOOL
AVIFILE_FormatsEqual(PAVISTREAM avi1
, PAVISTREAM avi2
)
177 LPVOID fmt1
= NULL
, fmt2
= NULL
;
178 LONG size1
, size2
, start1
, start2
;
181 assert(avi1
!= NULL
&& avi2
!= NULL
);
183 /* get stream starts and check format sizes */
184 start1
= AVIStreamStart(avi1
);
185 start2
= AVIStreamStart(avi2
);
186 if (FAILED(AVIStreamFormatSize(avi1
, start1
, &size1
)))
188 if (FAILED(AVIStreamFormatSize(avi2
, start2
, &size2
)))
193 /* sizes match, now get formats and compare them */
194 fmt1
= HeapAlloc(GetProcessHeap(), 0, size1
);
197 if (SUCCEEDED(AVIStreamReadFormat(avi1
, start1
, fmt1
, &size1
))) {
198 fmt2
= HeapAlloc(GetProcessHeap(), 0, size1
);
200 if (SUCCEEDED(AVIStreamReadFormat(avi2
, start2
, fmt2
, &size1
)))
201 status
= (memcmp(fmt1
, fmt2
, size1
) == 0);
205 HeapFree(GetProcessHeap(), 0, fmt2
);
206 HeapFree(GetProcessHeap(), 0, fmt1
);
211 /***********************************************************************/
213 static HRESULT WINAPI
IAVIEditStream_fnQueryInterface(IAVIEditStream
*iface
,REFIID refiid
,LPVOID
*obj
)
215 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
217 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(refiid
), obj
);
219 if (IsEqualGUID(&IID_IUnknown
, refiid
) ||
220 IsEqualGUID(&IID_IAVIEditStream
, refiid
) ||
221 IsEqualGUID(&IID_IEditStreamInternal
, refiid
)) {
223 IAVIEditStream_AddRef(iface
);
226 } else if (IsEqualGUID(&IID_IAVIStream
, refiid
)) {
227 *obj
= &This
->IAVIStream_iface
;
228 IAVIEditStream_AddRef(iface
);
233 return E_NOINTERFACE
;
236 static ULONG WINAPI
IAVIEditStream_fnAddRef(IAVIEditStream
*iface
)
238 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
239 ULONG ref
= InterlockedIncrement(&This
->ref
);
241 TRACE("(%p) -> %d\n", iface
, ref
);
246 static ULONG WINAPI
IAVIEditStream_fnRelease(IAVIEditStream
*iface
)
248 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
250 ULONG ref
= InterlockedDecrement(&This
->ref
);
252 TRACE("(%p) -> %d\n", iface
, ref
);
256 if (This
->pg
!= NULL
)
257 AVIStreamGetFrameClose(This
->pg
);
258 if (This
->pStreams
!= NULL
) {
259 for (i
= 0; i
< This
->nStreams
; i
++) {
260 if (This
->pStreams
[i
].pStream
!= NULL
)
261 IAVIStream_Release(This
->pStreams
[i
].pStream
);
263 HeapFree(GetProcessHeap(), 0, This
->pStreams
);
266 HeapFree(GetProcessHeap(), 0, This
);
272 static HRESULT WINAPI
IAVIEditStream_fnCut(IAVIEditStream
*iface
,LONG
*plStart
,
273 LONG
*plLength
,PAVISTREAM
*ppResult
)
275 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
277 DWORD start
, len
, streamPos
, streamNr
;
280 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
282 if (ppResult
!= NULL
)
284 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0)
285 return AVIERR_BADPARAM
;
287 /* if asked for cut part copy it before deleting */
288 if (ppResult
!= NULL
) {
289 hr
= IAVIEditStream_Copy(iface
, plStart
, plLength
, ppResult
);
297 /* now delete the requested part */
299 hr
= AVIFILE_FindStreamInTable(This
, start
, &stream
,
300 &streamPos
, &streamNr
, FALSE
);
303 if (This
->pStreams
[streamNr
].dwStart
== streamPos
) {
304 /* deleting from start of part */
305 if (len
< This
->pStreams
[streamNr
].dwLength
) {
307 This
->pStreams
[streamNr
].dwStart
+= len
;
308 This
->pStreams
[streamNr
].dwLength
-= len
;
309 This
->sInfo
.dwLength
-= len
;
312 /* we must return decompressed data now */
313 This
->bDecompress
= TRUE
;
315 /* deleting hole part */
316 len
-= This
->pStreams
[streamNr
].dwLength
;
317 AVIFILE_RemoveStream(This
,streamNr
);
319 } else if (EditStreamEnd(This
, streamNr
) <= streamPos
+ len
) {
320 /* deleting at end of a part */
321 DWORD count
= EditStreamEnd(This
, streamNr
) - streamPos
;
322 This
->sInfo
.dwLength
-= count
;
324 This
->pStreams
[streamNr
].dwLength
=
325 streamPos
- This
->pStreams
[streamNr
].dwStart
;
328 if (This
->nStreams
+ 1 >= This
->nTableSize
) {
329 This
->pStreams
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pStreams
,
330 (This
->nTableSize
+ 32) * sizeof(EditStreamTable
));
331 if (This
->pStreams
== NULL
)
332 return AVIERR_MEMORY
;
333 This
->nTableSize
+= 32;
335 memmove(This
->pStreams
+ streamNr
+ 1, This
->pStreams
+ streamNr
,
336 (This
->nStreams
- streamNr
) * sizeof(EditStreamTable
));
339 IAVIStream_AddRef(This
->pStreams
[streamNr
+ 1].pStream
);
340 This
->pStreams
[streamNr
+ 1].dwStart
= streamPos
+ len
;
341 This
->pStreams
[streamNr
+ 1].dwLength
=
342 EditStreamEnd(This
, streamNr
) - This
->pStreams
[streamNr
+ 1].dwStart
;
344 This
->pStreams
[streamNr
].dwLength
=
345 streamPos
- This
->pStreams
[streamNr
].dwStart
;
346 This
->sInfo
.dwLength
-= len
;
351 This
->sInfo
.dwEditCount
++;
356 static HRESULT WINAPI
IAVIEditStream_fnCopy(IAVIEditStream
*iface
,LONG
*plStart
,
357 LONG
*plLength
,PAVISTREAM
*ppResult
)
359 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
360 IAVIEditStreamImpl
* pEdit
;
364 TRACE("(%p,%p,%p,%p)\n",iface
,plStart
,plLength
,ppResult
);
366 if (ppResult
== NULL
)
367 return AVIERR_BADPARAM
;
369 if (plStart
== NULL
|| plLength
== NULL
|| *plStart
< 0 || *plLength
< 0)
370 return AVIERR_BADPARAM
;
373 if (*(LPDWORD
)plLength
> This
->sInfo
.dwLength
)
374 *(LPDWORD
)plLength
= This
->sInfo
.dwLength
;
375 if (*(LPDWORD
)plStart
< This
->sInfo
.dwStart
) {
376 *(LPDWORD
)plLength
-= This
->sInfo
.dwStart
- *(LPDWORD
)plStart
;
377 *(LPDWORD
)plStart
= This
->sInfo
.dwStart
;
379 return AVIERR_BADPARAM
;
381 if (*(LPDWORD
)plStart
+ *(LPDWORD
)plLength
> This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
)
382 *(LPDWORD
)plLength
= This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
-
385 pEdit
= (IAVIEditStreamImpl
*)AVIFILE_CreateEditStream(NULL
);
387 return AVIERR_MEMORY
;
389 hr
= IAVIEditStream_Paste((PAVIEDITSTREAM
)pEdit
, &start
, plLength
, &This
->IAVIStream_iface
,
390 *plStart
, *plStart
+ *plLength
);
393 IAVIEditStream_Release((PAVIEDITSTREAM
)pEdit
);
395 *ppResult
= &This
->IAVIStream_iface
;
400 static HRESULT WINAPI
IAVIEditStream_fnPaste(IAVIEditStream
*iface
,LONG
*plStart
,
401 LONG
*plLength
,PAVISTREAM pSource
,
402 LONG lStart
,LONG lLength
)
404 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
405 AVISTREAMINFOW srcInfo
;
406 IAVIEditStreamImpl
*pEdit
= NULL
;
408 DWORD startPos
, endPos
, streamNr
, nStreams
;
411 TRACE("(%p,%p,%p,%p,%d,%d)\n",iface
,plStart
,plLength
,
412 pSource
,lStart
,lLength
);
415 return AVIERR_BADHANDLE
;
416 if (plStart
== NULL
|| *plStart
< 0)
417 return AVIERR_BADPARAM
;
418 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< *plStart
)
419 return AVIERR_BADPARAM
; /* Can't paste with holes */
420 if (FAILED(IAVIStream_Info(pSource
, &srcInfo
, sizeof(srcInfo
))))
422 if (lStart
< srcInfo
.dwStart
|| lStart
>= srcInfo
.dwStart
+ srcInfo
.dwLength
)
423 return AVIERR_BADPARAM
;
424 if (This
->sInfo
.fccType
== 0) {
425 /* This stream is empty */
426 IAVIStream_Info(pSource
, &This
->sInfo
, sizeof(This
->sInfo
));
427 This
->sInfo
.dwStart
= *plStart
;
428 This
->sInfo
.dwLength
= 0;
430 if (This
->sInfo
.fccType
!= srcInfo
.fccType
)
431 return AVIERR_UNSUPPORTED
; /* different stream types */
432 if (lLength
== -1) /* Copy the hole stream */
433 lLength
= srcInfo
.dwLength
;
434 if (lStart
+ lLength
> srcInfo
.dwStart
+ srcInfo
.dwLength
)
435 lLength
= srcInfo
.dwStart
+ srcInfo
.dwLength
- lStart
;
436 if (lLength
+ *plStart
>= 0x80000000)
437 return AVIERR_MEMORY
;
439 /* streamtype specific tests */
440 if (srcInfo
.fccType
== streamtypeVIDEO
) {
443 size
= srcInfo
.rcFrame
.right
- srcInfo
.rcFrame
.left
;
444 if (size
!= This
->sInfo
.rcFrame
.right
- This
->sInfo
.rcFrame
.left
)
445 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
446 size
= srcInfo
.rcFrame
.bottom
- srcInfo
.rcFrame
.top
;
447 if (size
!= This
->sInfo
.rcFrame
.bottom
- This
->sInfo
.rcFrame
.top
)
448 return AVIERR_UNSUPPORTED
; /* FIXME: Can't GetFrame convert it? */
449 } else if (srcInfo
.fccType
== streamtypeAUDIO
) {
450 if (!AVIFILE_FormatsEqual(&This
->IAVIStream_iface
, pSource
))
451 return AVIERR_UNSUPPORTED
;
453 /* FIXME: streamtypeMIDI and streamtypeTEXT */
454 return AVIERR_UNSUPPORTED
;
457 /* try to get an IEditStreamInternal interface */
458 if (SUCCEEDED(IAVIStream_QueryInterface(pSource
, &IID_IEditStreamInternal
, (LPVOID
*)&pEdit
)))
459 IAVIEditStream_Release(&pEdit
->IAVIEditStream_iface
); /* pSource holds a reference */
461 /* for video must check for change of format */
462 if (This
->sInfo
.fccType
== streamtypeVIDEO
) {
463 if (! This
->bDecompress
) {
464 /* Need to decompress if any of the following conditions matches:
465 * - pSource is an editable stream which decompresses
466 * - the nearest keyframe of pSource isn't lStart
467 * - the nearest keyframe of this stream isn't *plStart
468 * - the format of pSource doesn't match this one
470 if ((pEdit
!= NULL
&& pEdit
->bDecompress
) ||
471 AVIStreamNearestKeyFrame(pSource
, lStart
) != lStart
||
472 AVIStreamNearestKeyFrame(&This
->IAVIStream_iface
, *plStart
) != *plStart
||
473 (This
->nStreams
> 0 && !AVIFILE_FormatsEqual(&This
->IAVIStream_iface
, pSource
))) {
474 /* Use first stream part to get format to convert everything to */
475 AVIFILE_ReadFrame(This
, This
->pStreams
[0].pStream
,
476 This
->pStreams
[0].dwStart
);
478 /* Check if we could convert the source streams to the desired format... */
480 if (FAILED(AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
481 &startPos
, &streamNr
, TRUE
)))
482 return AVIERR_INTERNAL
;
483 for (n
= lStart
; n
< lStart
+ lLength
; streamNr
++) {
484 if (AVIFILE_ReadFrame(This
, pEdit
->pStreams
[streamNr
].pStream
, startPos
) == NULL
)
485 return AVIERR_BADFORMAT
;
486 startPos
= pEdit
->pStreams
[streamNr
].dwStart
;
487 n
+= pEdit
->pStreams
[streamNr
].dwLength
;
489 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
490 return AVIERR_BADFORMAT
;
492 This
->bDecompress
= TRUE
;
493 This
->sInfo
.fccHandler
= 0;
495 } else if (AVIFILE_ReadFrame(This
, pSource
, lStart
) == NULL
)
496 return AVIERR_BADFORMAT
; /* Can't convert source to own format */
497 } /* FIXME: something special for the other formats? */
499 /* Make sure we have enough memory for parts */
503 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
504 &endPos
, &nLastStream
, TRUE
);
505 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
,
506 &startPos
, &streamNr
, FALSE
);
507 if (nLastStream
== streamNr
)
510 nStreams
= nLastStream
- streamNr
;
513 if (This
->nStreams
+ nStreams
+ 1 > This
->nTableSize
) {
514 n
= This
->nStreams
+ nStreams
+ 33;
516 This
->pStreams
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pStreams
, n
* sizeof(EditStreamTable
));
517 if (This
->pStreams
== NULL
)
518 return AVIERR_MEMORY
;
519 This
->nTableSize
= n
;
522 if (plLength
!= NULL
)
525 /* now do the real work */
526 if (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> *plStart
) {
527 AVIFILE_FindStreamInTable(This
, *plStart
, &pStream
,
528 &startPos
, &streamNr
, FALSE
);
529 if (startPos
!= This
->pStreams
[streamNr
].dwStart
) {
530 /* split stream streamNr at startPos */
531 memmove(This
->pStreams
+ streamNr
+ nStreams
+ 1,
532 This
->pStreams
+ streamNr
,
533 (This
->nStreams
+ nStreams
- streamNr
+ 1) * sizeof(EditStreamTable
));
535 This
->pStreams
[streamNr
+ 2].dwLength
=
536 EditStreamEnd(This
, streamNr
+ 2) - startPos
;
537 This
->pStreams
[streamNr
+ 2].dwStart
= startPos
;
538 This
->pStreams
[streamNr
].dwLength
=
539 startPos
- This
->pStreams
[streamNr
].dwStart
;
540 IAVIStream_AddRef(This
->pStreams
[streamNr
].pStream
);
543 /* insert before stream at streamNr */
544 memmove(This
->pStreams
+ streamNr
+ nStreams
, This
->pStreams
+ streamNr
,
545 (This
->nStreams
+ nStreams
- streamNr
) * sizeof(EditStreamTable
));
547 } else /* append the streams */
548 streamNr
= This
->nStreams
;
551 /* insert the parts of the editable stream instead of itself */
552 AVIFILE_FindStreamInTable(pEdit
, lStart
+ lLength
, &pStream
,
553 &endPos
, NULL
, FALSE
);
554 AVIFILE_FindStreamInTable(pEdit
, lStart
, &pStream
, &startPos
, &n
, FALSE
);
556 memcpy(This
->pStreams
+ streamNr
, pEdit
->pStreams
+ n
,
557 nStreams
* sizeof(EditStreamTable
));
558 if (This
->pStreams
[streamNr
].dwStart
< startPos
) {
559 This
->pStreams
[streamNr
].dwLength
=
560 EditStreamEnd(This
, streamNr
) - startPos
;
561 This
->pStreams
[streamNr
].dwStart
= startPos
;
563 if (endPos
< EditStreamEnd(This
, streamNr
+ nStreams
))
564 This
->pStreams
[streamNr
+ nStreams
].dwLength
=
565 endPos
- This
->pStreams
[streamNr
+ nStreams
].dwStart
;
567 /* a simple stream */
568 This
->pStreams
[streamNr
].pStream
= pSource
;
569 This
->pStreams
[streamNr
].dwStart
= lStart
;
570 This
->pStreams
[streamNr
].dwLength
= lLength
;
573 for (n
= 0; n
< nStreams
; n
++) {
574 IAVIStream_AddRef(This
->pStreams
[streamNr
+ n
].pStream
);
575 if (0 < streamNr
+ n
&&
576 This
->pStreams
[streamNr
+ n
- 1].pStream
!= This
->pStreams
[streamNr
+ n
].pStream
) {
577 This
->sInfo
.dwFlags
|= AVISTREAMINFO_FORMATCHANGES
;
578 This
->sInfo
.dwFormatChangeCount
++;
581 This
->sInfo
.dwEditCount
++;
582 This
->sInfo
.dwLength
+= lLength
;
583 This
->nStreams
+= nStreams
;
588 static HRESULT WINAPI
IAVIEditStream_fnClone(IAVIEditStream
*iface
,
591 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
592 IAVIEditStreamImpl
* pEdit
;
595 TRACE("(%p,%p)\n",iface
,ppResult
);
597 if (ppResult
== NULL
)
598 return AVIERR_BADPARAM
;
601 pEdit
= (IAVIEditStreamImpl
*)AVIFILE_CreateEditStream(NULL
);
603 return AVIERR_MEMORY
;
604 if (This
->nStreams
> pEdit
->nTableSize
) {
605 pEdit
->pStreams
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, pEdit
->pStreams
,
606 This
->nStreams
* sizeof(EditStreamTable
));
607 if (pEdit
->pStreams
== NULL
)
608 return AVIERR_MEMORY
;
609 pEdit
->nTableSize
= This
->nStreams
;
611 pEdit
->nStreams
= This
->nStreams
;
612 memcpy(pEdit
->pStreams
, This
->pStreams
,
613 This
->nStreams
* sizeof(EditStreamTable
));
614 memcpy(&pEdit
->sInfo
,&This
->sInfo
,sizeof(This
->sInfo
));
615 for (i
= 0; i
< This
->nStreams
; i
++) {
616 if (pEdit
->pStreams
[i
].pStream
!= NULL
)
617 IAVIStream_AddRef(pEdit
->pStreams
[i
].pStream
);
620 *ppResult
= &This
->IAVIStream_iface
;
625 static HRESULT WINAPI
IAVIEditStream_fnSetInfo(IAVIEditStream
*iface
,
626 LPAVISTREAMINFOW asi
,LONG size
)
628 IAVIEditStreamImpl
*This
= impl_from_IAVIEditStream(iface
);
630 TRACE("(%p,%p,%d)\n",iface
,asi
,size
);
632 /* check parameters */
633 if (size
>= 0 && size
< sizeof(AVISTREAMINFOW
))
634 return AVIERR_BADSIZE
;
636 This
->sInfo
.wLanguage
= asi
->wLanguage
;
637 This
->sInfo
.wPriority
= asi
->wPriority
;
638 This
->sInfo
.dwStart
= asi
->dwStart
;
639 This
->sInfo
.dwRate
= asi
->dwRate
;
640 This
->sInfo
.dwScale
= asi
->dwScale
;
641 This
->sInfo
.dwQuality
= asi
->dwQuality
;
642 CopyRect(&This
->sInfo
.rcFrame
, &asi
->rcFrame
);
643 memcpy(This
->sInfo
.szName
, asi
->szName
, sizeof(asi
->szName
));
644 This
->sInfo
.dwEditCount
++;
649 static const struct IAVIEditStreamVtbl ieditstream
= {
650 IAVIEditStream_fnQueryInterface
,
651 IAVIEditStream_fnAddRef
,
652 IAVIEditStream_fnRelease
,
653 IAVIEditStream_fnCut
,
654 IAVIEditStream_fnCopy
,
655 IAVIEditStream_fnPaste
,
656 IAVIEditStream_fnClone
,
657 IAVIEditStream_fnSetInfo
660 static HRESULT WINAPI
IEditAVIStream_fnQueryInterface(IAVIStream
*iface
,
661 REFIID refiid
,LPVOID
*obj
)
663 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
664 return IAVIEditStream_QueryInterface(&This
->IAVIEditStream_iface
,refiid
,obj
);
667 static ULONG WINAPI
IEditAVIStream_fnAddRef(IAVIStream
*iface
)
669 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
670 return IAVIEditStream_AddRef(&This
->IAVIEditStream_iface
);
673 static ULONG WINAPI
IEditAVIStream_fnRelease(IAVIStream
*iface
)
675 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
676 return IAVIEditStream_Release(&This
->IAVIEditStream_iface
);
679 static HRESULT WINAPI
IEditAVIStream_fnCreate(IAVIStream
*iface
,
680 LPARAM lParam1
,LPARAM lParam2
)
682 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
687 if (This
->pStreams
== NULL
) {
688 This
->pStreams
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, 256 * sizeof(EditStreamTable
));
689 if (This
->pStreams
== NULL
)
690 return AVIERR_MEMORY
;
691 This
->nTableSize
= 256;
695 IAVIStream_Info((PAVISTREAM
)lParam1
, &This
->sInfo
, sizeof(This
->sInfo
));
696 IAVIStream_AddRef((PAVISTREAM
)lParam1
);
697 This
->pStreams
[0].pStream
= (PAVISTREAM
)lParam1
;
698 This
->pStreams
[0].dwStart
= This
->sInfo
.dwStart
;
699 This
->pStreams
[0].dwLength
= This
->sInfo
.dwLength
;
705 static HRESULT WINAPI
IEditAVIStream_fnInfo(IAVIStream
*iface
,
706 AVISTREAMINFOW
*psi
,LONG size
)
708 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
710 TRACE("(%p,%p,%d)\n",iface
,psi
,size
);
713 return AVIERR_BADPARAM
;
715 return AVIERR_BADSIZE
;
717 if (This
->bDecompress
)
718 This
->sInfo
.fccHandler
= 0;
720 memcpy(psi
, &This
->sInfo
, min((DWORD
)size
, sizeof(This
->sInfo
)));
722 if ((DWORD
)size
< sizeof(This
->sInfo
))
723 return AVIERR_BUFFERTOOSMALL
;
727 static LONG WINAPI
IEditAVIStream_fnFindSample(IAVIStream
*iface
,LONG pos
,
730 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
732 DWORD streamPos
, streamNr
;
734 TRACE("(%p,%d,0x%08X)\n",iface
,pos
,flags
);
736 if (flags
& FIND_FROM_START
)
737 pos
= (LONG
)This
->sInfo
.dwStart
;
739 /* outside of stream? */
740 if (pos
< (LONG
)This
->sInfo
.dwStart
||
741 (LONG
)This
->sInfo
.dwStart
+ (LONG
)This
->sInfo
.dwLength
<= pos
)
744 /* map our position to a stream and position in it */
745 if (AVIFILE_FindStreamInTable(This
, pos
, &stream
, &streamPos
,
746 &streamNr
, TRUE
) != S_OK
)
747 return -1; /* doesn't exist */
749 if (This
->bDecompress
) {
750 /* only one stream -- format changes only at start */
751 if (flags
& FIND_FORMAT
)
752 return (flags
& FIND_NEXT
? -1 : 0);
754 /* FIXME: map positions back to us */
755 return IAVIStream_FindSample(stream
, streamPos
, flags
);
757 /* assume change of format every frame */
762 static HRESULT WINAPI
IEditAVIStream_fnReadFormat(IAVIStream
*iface
,LONG pos
,
763 LPVOID format
,LONG
*fmtsize
)
765 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
766 LPBITMAPINFOHEADER lp
;
771 TRACE("(%p,%d,%p,%p)\n",iface
,pos
,format
,fmtsize
);
773 if (fmtsize
== NULL
|| pos
< This
->sInfo
.dwStart
||
774 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
<= pos
)
775 return AVIERR_BADPARAM
;
777 /* find stream corresponding to position */
778 hr
= AVIFILE_FindStreamInTable(This
, pos
, &stream
, &n
, NULL
, FALSE
);
782 if (! This
->bDecompress
)
783 return IAVIStream_ReadFormat(stream
, n
, format
, fmtsize
);
785 lp
= AVIFILE_ReadFrame(This
, stream
, n
);
788 if (lp
->biBitCount
<= 8) {
789 n
= (lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
);
790 n
*= sizeof(RGBQUAD
);
795 memcpy(format
, lp
, min((LONG
)n
, *fmtsize
));
796 hr
= ((LONG
)n
> *fmtsize
? AVIERR_BUFFERTOOSMALL
: AVIERR_OK
);
802 static HRESULT WINAPI
IEditAVIStream_fnSetFormat(IAVIStream
*iface
,LONG pos
,
803 LPVOID format
,LONG formatsize
)
805 TRACE("(%p,%d,%p,%d)\n",iface
,pos
,format
,formatsize
);
807 return AVIERR_UNSUPPORTED
;
810 static HRESULT WINAPI
IEditAVIStream_fnRead(IAVIStream
*iface
,LONG start
,
811 LONG samples
,LPVOID buffer
,
812 LONG buffersize
,LONG
*bytesread
,
815 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
817 DWORD streamPos
, streamNr
;
818 LONG readBytes
, readSamples
, count
;
821 TRACE("(%p,%d,%d,%p,%d,%p,%p) -- 0x%08X\n",iface
,start
,samples
,
822 buffer
,buffersize
,bytesread
,samplesread
,This
->sInfo
.fccType
);
824 /* check parameters */
825 if (bytesread
!= NULL
)
827 if (samplesread
!= NULL
)
830 return AVIERR_BADSIZE
;
831 if ((DWORD
)start
< This
->sInfo
.dwStart
||
832 This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
< (DWORD
)start
)
833 return AVIERR_BADPARAM
;
835 if (! This
->bDecompress
) {
836 /* audio like data -- sample-based */
839 return AVIERR_OK
; /* nothing at all or already done */
841 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
842 &streamPos
, &streamNr
, FALSE
)))
845 /* limit to end of the stream */
847 if (streamPos
+ count
> EditStreamEnd(This
, streamNr
))
848 count
= EditStreamEnd(This
, streamNr
) - streamPos
;
850 hr
= IAVIStream_Read(stream
, streamPos
, count
, buffer
, buffersize
,
851 &readBytes
, &readSamples
);
854 if (readBytes
== 0 && readSamples
== 0 && count
!= 0)
855 return AVIERR_FILEREAD
; /* for bad stream implementations */
857 if (samplesread
!= NULL
)
858 *samplesread
+= readSamples
;
859 if (bytesread
!= NULL
)
860 *bytesread
+= readBytes
;
861 if (buffer
!= NULL
) {
862 buffer
= ((LPBYTE
)buffer
)+readBytes
;
863 buffersize
-= readBytes
;
867 } while (This
->sInfo
.dwStart
+ This
->sInfo
.dwLength
> start
);
869 /* video like data -- frame-based */
870 LPBITMAPINFOHEADER lp
;
875 if (FAILED(AVIFILE_FindStreamInTable(This
, start
, &stream
,
876 &streamPos
, &streamNr
, FALSE
)))
879 lp
= AVIFILE_ReadFrame(This
, stream
, streamPos
);
883 if (buffer
!= NULL
) {
884 /* need size of format to skip */
885 if (lp
->biBitCount
<= 8) {
886 count
= lp
->biClrUsed
> 0 ? lp
->biClrUsed
: 1 << lp
->biBitCount
;
887 count
*= sizeof(RGBQUAD
);
892 if (buffersize
< lp
->biSizeImage
)
893 return AVIERR_BUFFERTOOSMALL
;
894 memcpy(buffer
, (LPBYTE
)lp
+ count
, lp
->biSizeImage
);
897 if (bytesread
!= NULL
)
898 *bytesread
= lp
->biSizeImage
;
899 if (samplesread
!= NULL
)
906 static HRESULT WINAPI
IEditAVIStream_fnWrite(IAVIStream
*iface
,LONG start
,
907 LONG samples
,LPVOID buffer
,
908 LONG buffersize
,DWORD flags
,
909 LONG
*sampwritten
,LONG
*byteswritten
)
911 TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n",iface
,start
,samples
,buffer
,
912 buffersize
,flags
,sampwritten
,byteswritten
);
914 /* be sure return parameters have correct values */
915 if (sampwritten
!= NULL
)
917 if (byteswritten
!= NULL
)
920 return AVIERR_UNSUPPORTED
;
923 static HRESULT WINAPI
IEditAVIStream_fnDelete(IAVIStream
*iface
,LONG start
,
926 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
928 TRACE("(%p,%d,%d)\n",iface
,start
,samples
);
930 return IAVIEditStream_Cut(&This
->IAVIEditStream_iface
,&start
,&samples
,NULL
);
933 static HRESULT WINAPI
IEditAVIStream_fnReadData(IAVIStream
*iface
,DWORD fcc
,
934 LPVOID lp
,LONG
*lpread
)
936 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
939 TRACE("(%p,0x%08X,%p,%p)\n",iface
,fcc
,lp
,lpread
);
941 /* check parameters */
942 if (lp
== NULL
|| lpread
== NULL
)
943 return AVIERR_BADPARAM
;
945 /* simply ask every stream and return the first block found */
946 for (n
= 0; n
< This
->nStreams
; n
++) {
947 HRESULT hr
= IAVIStream_ReadData(This
->pStreams
[n
].pStream
,fcc
,lp
,lpread
);
954 return AVIERR_NODATA
;
957 static HRESULT WINAPI
IEditAVIStream_fnWriteData(IAVIStream
*iface
,DWORD fcc
,
960 TRACE("(%p,0x%08X,%p,%d)\n",iface
,fcc
,lp
,size
);
962 return AVIERR_UNSUPPORTED
;
965 static HRESULT WINAPI
IEditAVIStream_fnSetInfo(IAVIStream
*iface
,
966 AVISTREAMINFOW
*info
,LONG len
)
968 IAVIEditStreamImpl
*This
= impl_from_IAVIStream( iface
);
970 TRACE("(%p,%p,%d)\n",iface
,info
,len
);
972 return IAVIEditStream_SetInfo(&This
->IAVIEditStream_iface
,info
,len
);
975 static const struct IAVIStreamVtbl ieditstast
= {
976 IEditAVIStream_fnQueryInterface
,
977 IEditAVIStream_fnAddRef
,
978 IEditAVIStream_fnRelease
,
979 IEditAVIStream_fnCreate
,
980 IEditAVIStream_fnInfo
,
981 IEditAVIStream_fnFindSample
,
982 IEditAVIStream_fnReadFormat
,
983 IEditAVIStream_fnSetFormat
,
984 IEditAVIStream_fnRead
,
985 IEditAVIStream_fnWrite
,
986 IEditAVIStream_fnDelete
,
987 IEditAVIStream_fnReadData
,
988 IEditAVIStream_fnWriteData
,
989 IEditAVIStream_fnSetInfo
992 PAVIEDITSTREAM
AVIFILE_CreateEditStream(PAVISTREAM pstream
)
994 IAVIEditStreamImpl
*pedit
= NULL
;
996 pedit
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IAVIEditStreamImpl
));
1000 pedit
->IAVIEditStream_iface
.lpVtbl
= &ieditstream
;
1001 pedit
->IAVIStream_iface
.lpVtbl
= &ieditstast
;
1004 IAVIStream_Create(&pedit
->IAVIStream_iface
, (LPARAM
)pstream
, 0);
1006 return (PAVIEDITSTREAM
)pedit
;