Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/avifil32/editstream.c
4388 views
1
/*
2
* Copyright 2003 Michael Günnewig
3
*
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
8
*
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
13
*
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17
*/
18
19
#include <assert.h>
20
#include <stdarg.h>
21
22
#include "windef.h"
23
#include "winbase.h"
24
#include "winuser.h"
25
#include "wingdi.h"
26
#include "winerror.h"
27
#include "mmsystem.h"
28
#include "vfw.h"
29
30
#include "avifile_private.h"
31
#include "extrachunk.h"
32
33
#include "wine/debug.h"
34
#include "initguid.h"
35
36
WINE_DEFAULT_DEBUG_CHANNEL(avifile);
37
38
/***********************************************************************/
39
40
/* internal interface to get access to table of stream in an editable stream */
41
42
DEFINE_AVIGUID(IID_IEditStreamInternal, 0x0002000A,0,0);
43
44
typedef struct _EditStreamTable {
45
PAVISTREAM pStream; /* stream which contains the data */
46
DWORD dwStart; /* where starts the part which is also our */
47
DWORD dwLength; /* how many is also in this stream */
48
} EditStreamTable;
49
50
#define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
51
(This)->pStreams[streamNr].dwLength)
52
53
typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
54
55
struct _IAVIEditStreamImpl {
56
IAVIEditStream IAVIEditStream_iface;
57
IAVIStream IAVIStream_iface;
58
59
LONG ref;
60
61
AVISTREAMINFOW sInfo;
62
63
EditStreamTable *pStreams;
64
DWORD nStreams; /* current fill level of pStreams table */
65
DWORD nTableSize; /* size of pStreams table */
66
67
BOOL bDecompress;
68
PAVISTREAM pCurStream;
69
PGETFRAME pg; /* IGetFrame for pCurStream */
70
LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
71
};
72
73
static IAVIEditStreamImpl *AVIFILE_CreateEditStream(IAVIStream *stream);
74
75
static inline IAVIEditStreamImpl *impl_from_IAVIEditStream(IAVIEditStream *iface)
76
{
77
return CONTAINING_RECORD(iface, IAVIEditStreamImpl, IAVIEditStream_iface);
78
}
79
80
static inline IAVIEditStreamImpl *impl_from_IAVIStream(IAVIStream *iface)
81
{
82
return CONTAINING_RECORD(iface, IAVIEditStreamImpl, IAVIStream_iface);
83
}
84
85
/***********************************************************************/
86
87
static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
88
DWORD pos,PAVISTREAM *ppStream,
89
DWORD* streamPos,
90
DWORD* streamNr,BOOL bFindSample)
91
{
92
DWORD n;
93
94
TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
95
streamNr,bFindSample);
96
97
if (pos < This->sInfo.dwStart)
98
return AVIERR_BADPARAM;
99
100
pos -= This->sInfo.dwStart;
101
for (n = 0; n < This->nStreams; n++) {
102
if (pos < This->pStreams[n].dwLength) {
103
*ppStream = This->pStreams[n].pStream;
104
*streamPos = This->pStreams[n].dwStart + pos;
105
if (streamNr != NULL)
106
*streamNr = n;
107
108
return AVIERR_OK;
109
}
110
pos -= This->pStreams[n].dwLength;
111
}
112
if (pos == 0 && bFindSample) {
113
*ppStream = This->pStreams[--n].pStream;
114
*streamPos = EditStreamEnd(This, n);
115
if (streamNr != NULL)
116
*streamNr = n;
117
118
TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
119
return AVIERR_OK;
120
} else {
121
*ppStream = NULL;
122
*streamPos = 0;
123
if (streamNr != NULL)
124
*streamNr = 0;
125
126
TRACE(" -> ERROR (NULL,0,0)\n");
127
return AVIERR_BADPARAM;
128
}
129
}
130
131
static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
132
PAVISTREAM pstream, LONG pos)
133
{
134
PGETFRAME pg;
135
136
TRACE("(%p,%p,%ld)\n",This,pstream,pos);
137
138
if (pstream == NULL)
139
return NULL;
140
141
/* if stream changes make sure that only palette changes */
142
if (This->pCurStream != pstream) {
143
pg = AVIStreamGetFrameOpen(pstream, NULL);
144
if (pg == NULL)
145
return NULL;
146
if (This->pg != NULL) {
147
if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1) != S_OK) {
148
AVIStreamGetFrameClose(pg);
149
ERR(": IGetFrame_SetFormat failed\n");
150
return NULL;
151
}
152
AVIStreamGetFrameClose(This->pg);
153
}
154
This->pg = pg;
155
This->pCurStream = pstream;
156
}
157
158
/* now get the decompressed frame */
159
This->lpFrame = AVIStreamGetFrame(This->pg, pos);
160
if (This->lpFrame != NULL)
161
This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
162
163
return This->lpFrame;
164
}
165
166
static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
167
{
168
assert(This != NULL);
169
assert(nr < This->nStreams);
170
171
/* remove part nr */
172
IAVIStream_Release(This->pStreams[nr].pStream);
173
This->nStreams--;
174
if (nr < This->nStreams)
175
memmove(&This->pStreams[nr], &This->pStreams[nr + 1],
176
(This->nStreams - nr) * sizeof(This->pStreams[0]));
177
This->pStreams[This->nStreams].pStream = NULL;
178
This->pStreams[This->nStreams].dwStart = 0;
179
This->pStreams[This->nStreams].dwLength = 0;
180
181
/* try to merge the part before the deleted one and the one after it */
182
if (0 < nr && 0 < This->nStreams &&
183
This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
184
if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
185
This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
186
return AVIFILE_RemoveStream(This, nr);
187
}
188
}
189
190
return AVIERR_OK;
191
}
192
193
static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
194
{
195
LPVOID fmt1 = NULL, fmt2 = NULL;
196
LONG size1, size2, start1, start2;
197
BOOL status = FALSE;
198
199
assert(avi1 != NULL && avi2 != NULL);
200
201
/* get stream starts and check format sizes */
202
start1 = AVIStreamStart(avi1);
203
start2 = AVIStreamStart(avi2);
204
if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
205
return FALSE;
206
if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
207
return FALSE;
208
if (size1 != size2)
209
return FALSE;
210
211
/* sizes match, now get formats and compare them */
212
fmt1 = malloc(size1);
213
if (fmt1 == NULL)
214
return FALSE;
215
if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
216
fmt2 = malloc(size1);
217
if (fmt2 != NULL) {
218
if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
219
status = (memcmp(fmt1, fmt2, size1) == 0);
220
}
221
}
222
223
free(fmt2);
224
free(fmt1);
225
226
return status;
227
}
228
229
/***********************************************************************/
230
231
static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
232
{
233
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
234
235
TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
236
237
if (IsEqualGUID(&IID_IUnknown, refiid) ||
238
IsEqualGUID(&IID_IAVIEditStream, refiid) ||
239
IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
240
*obj = iface;
241
IAVIEditStream_AddRef(iface);
242
243
return S_OK;
244
} else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
245
*obj = &This->IAVIStream_iface;
246
IAVIEditStream_AddRef(iface);
247
248
return S_OK;
249
}
250
251
return E_NOINTERFACE;
252
}
253
254
static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
255
{
256
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
257
ULONG ref = InterlockedIncrement(&This->ref);
258
259
TRACE("(%p) -> %ld\n", iface, ref);
260
261
return ref;
262
}
263
264
static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
265
{
266
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
267
DWORD i;
268
ULONG ref = InterlockedDecrement(&This->ref);
269
270
TRACE("(%p) -> %ld\n", iface, ref);
271
272
if (!ref) {
273
/* release memory */
274
if (This->pg != NULL)
275
AVIStreamGetFrameClose(This->pg);
276
if (This->pStreams != NULL) {
277
for (i = 0; i < This->nStreams; i++) {
278
if (This->pStreams[i].pStream != NULL)
279
IAVIStream_Release(This->pStreams[i].pStream);
280
}
281
free(This->pStreams);
282
}
283
284
free(This);
285
}
286
return ref;
287
}
288
289
static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
290
LONG*plLength,PAVISTREAM*ppResult)
291
{
292
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
293
PAVISTREAM stream;
294
DWORD start, len, streamPos, streamNr;
295
HRESULT hr;
296
297
TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
298
299
if (ppResult != NULL)
300
*ppResult = NULL;
301
if (plStart == NULL || plLength == NULL || *plStart < 0)
302
return AVIERR_BADPARAM;
303
304
/* if asked for cut part copy it before deleting */
305
if (ppResult != NULL) {
306
hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
307
if (FAILED(hr))
308
return hr;
309
}
310
311
start = *plStart;
312
len = *plLength;
313
314
/* now delete the requested part */
315
while (len > 0) {
316
hr = AVIFILE_FindStreamInTable(This, start, &stream,
317
&streamPos, &streamNr, FALSE);
318
if (FAILED(hr))
319
return hr;
320
if (This->pStreams[streamNr].dwStart == streamPos) {
321
/* deleting from start of part */
322
if (len < This->pStreams[streamNr].dwLength) {
323
start += len;
324
This->pStreams[streamNr].dwStart += len;
325
This->pStreams[streamNr].dwLength -= len;
326
This->sInfo.dwLength -= len;
327
len = 0;
328
329
/* we must return decompressed data now */
330
This->bDecompress = TRUE;
331
} else {
332
/* deleting hole part */
333
len -= This->pStreams[streamNr].dwLength;
334
AVIFILE_RemoveStream(This,streamNr);
335
}
336
} else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
337
/* deleting at end of a part */
338
DWORD count = EditStreamEnd(This, streamNr) - streamPos;
339
This->sInfo.dwLength -= count;
340
len -= count;
341
This->pStreams[streamNr].dwLength =
342
streamPos - This->pStreams[streamNr].dwStart;
343
} else {
344
/* splitting */
345
if (This->nStreams + 1 >= This->nTableSize) {
346
This->pStreams = _recalloc(This->pStreams, This->nTableSize + 32, sizeof(EditStreamTable));
347
if (This->pStreams == NULL)
348
return AVIERR_MEMORY;
349
This->nTableSize += 32;
350
}
351
memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
352
(This->nStreams - streamNr) * sizeof(EditStreamTable));
353
This->nStreams++;
354
355
IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
356
This->pStreams[streamNr + 1].dwStart = streamPos + len;
357
This->pStreams[streamNr + 1].dwLength =
358
EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
359
360
This->pStreams[streamNr].dwLength =
361
streamPos - This->pStreams[streamNr].dwStart;
362
This->sInfo.dwLength -= len;
363
len = 0;
364
}
365
}
366
367
This->sInfo.dwEditCount++;
368
369
return AVIERR_OK;
370
}
371
372
static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
373
LONG*plLength,PAVISTREAM*ppResult)
374
{
375
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
376
IAVIEditStreamImpl* pEdit;
377
HRESULT hr;
378
LONG start = 0;
379
380
TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
381
382
if (ppResult == NULL)
383
return AVIERR_BADPARAM;
384
*ppResult = NULL;
385
if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
386
return AVIERR_BADPARAM;
387
388
/* check bounds */
389
if (*(LPDWORD)plLength > This->sInfo.dwLength)
390
*(LPDWORD)plLength = This->sInfo.dwLength;
391
if (*(LPDWORD)plStart < This->sInfo.dwStart) {
392
*(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
393
*(LPDWORD)plStart = This->sInfo.dwStart;
394
if (*plLength < 0)
395
return AVIERR_BADPARAM;
396
}
397
if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
398
*(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
399
*(LPDWORD)plStart;
400
401
pEdit = AVIFILE_CreateEditStream(NULL);
402
if (pEdit == NULL)
403
return AVIERR_MEMORY;
404
405
hr = IAVIEditStream_Paste(&pEdit->IAVIEditStream_iface, &start, plLength, &This->IAVIStream_iface,
406
*plStart, *plStart + *plLength);
407
*plStart = start;
408
if (FAILED(hr))
409
IAVIEditStream_Release(&pEdit->IAVIEditStream_iface);
410
else
411
*ppResult = &This->IAVIStream_iface;
412
413
return hr;
414
}
415
416
static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
417
LONG*plLength,PAVISTREAM pSource,
418
LONG lStart,LONG lLength)
419
{
420
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
421
AVISTREAMINFOW srcInfo;
422
IAVIEditStreamImpl *pEdit = NULL;
423
PAVISTREAM pStream;
424
DWORD startPos, endPos, streamNr, nStreams;
425
ULONG n;
426
427
TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
428
pSource,lStart,lLength);
429
430
if (pSource == NULL)
431
return AVIERR_BADHANDLE;
432
if (plStart == NULL || *plStart < 0)
433
return AVIERR_BADPARAM;
434
if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
435
return AVIERR_BADPARAM; /* Can't paste with holes */
436
if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
437
return AVIERR_ERROR;
438
if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
439
return AVIERR_BADPARAM;
440
if (This->sInfo.fccType == 0) {
441
/* This stream is empty */
442
IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
443
This->sInfo.dwStart = *plStart;
444
This->sInfo.dwLength = 0;
445
}
446
if (This->sInfo.fccType != srcInfo.fccType)
447
return AVIERR_UNSUPPORTED; /* different stream types */
448
if (lLength == -1) /* Copy the hole stream */
449
lLength = srcInfo.dwLength;
450
if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
451
lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
452
if (lLength + *plStart >= 0x80000000)
453
return AVIERR_MEMORY;
454
455
/* streamtype specific tests */
456
if (srcInfo.fccType == streamtypeVIDEO) {
457
LONG size;
458
459
size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
460
if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
461
return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
462
size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
463
if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
464
return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
465
} else if (srcInfo.fccType == streamtypeAUDIO) {
466
if (!AVIFILE_FormatsEqual(&This->IAVIStream_iface, pSource))
467
return AVIERR_UNSUPPORTED;
468
} else {
469
/* FIXME: streamtypeMIDI and streamtypeTEXT */
470
return AVIERR_UNSUPPORTED;
471
}
472
473
/* try to get an IEditStreamInternal interface */
474
if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal, (LPVOID*)&pEdit)))
475
IAVIEditStream_Release(&pEdit->IAVIEditStream_iface); /* pSource holds a reference */
476
477
/* for video must check for change of format */
478
if (This->sInfo.fccType == streamtypeVIDEO) {
479
if (! This->bDecompress) {
480
/* Need to decompress if any of the following conditions matches:
481
* - pSource is an editable stream which decompresses
482
* - the nearest keyframe of pSource isn't lStart
483
* - the nearest keyframe of this stream isn't *plStart
484
* - the format of pSource doesn't match this one
485
*/
486
if ((pEdit != NULL && pEdit->bDecompress) ||
487
AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
488
AVIStreamNearestKeyFrame(&This->IAVIStream_iface, *plStart) != *plStart ||
489
(This->nStreams > 0 && !AVIFILE_FormatsEqual(&This->IAVIStream_iface, pSource))) {
490
/* Use first stream part to get format to convert everything to */
491
AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
492
This->pStreams[0].dwStart);
493
494
/* Check if we could convert the source streams to the desired format... */
495
if (pEdit != NULL) {
496
if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
497
&startPos, &streamNr, TRUE)))
498
return AVIERR_INTERNAL;
499
for (n = lStart; n < lStart + lLength; streamNr++) {
500
if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
501
return AVIERR_BADFORMAT;
502
startPos = pEdit->pStreams[streamNr].dwStart;
503
n += pEdit->pStreams[streamNr].dwLength;
504
}
505
} else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
506
return AVIERR_BADFORMAT;
507
508
This->bDecompress = TRUE;
509
This->sInfo.fccHandler = 0;
510
}
511
} else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
512
return AVIERR_BADFORMAT; /* Can't convert source to own format */
513
} /* FIXME: something special for the other formats? */
514
515
/* Make sure we have enough memory for parts */
516
if (pEdit != NULL) {
517
DWORD nLastStream;
518
519
AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
520
&endPos, &nLastStream, TRUE);
521
AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
522
&startPos, &streamNr, FALSE);
523
if (nLastStream == streamNr)
524
nLastStream++;
525
526
nStreams = nLastStream - streamNr;
527
} else
528
nStreams = 1;
529
if (This->nStreams + nStreams + 1 > This->nTableSize) {
530
n = This->nStreams + nStreams + 33;
531
532
This->pStreams = _recalloc(This->pStreams, n, sizeof(EditStreamTable));
533
if (This->pStreams == NULL)
534
return AVIERR_MEMORY;
535
This->nTableSize = n;
536
}
537
538
if (plLength != NULL)
539
*plLength = lLength;
540
541
/* now do the real work */
542
if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
543
AVIFILE_FindStreamInTable(This, *plStart, &pStream,
544
&startPos, &streamNr, FALSE);
545
if (startPos != This->pStreams[streamNr].dwStart) {
546
/* split stream streamNr at startPos */
547
memmove(This->pStreams + streamNr + nStreams + 1,
548
This->pStreams + streamNr,
549
(This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
550
551
This->pStreams[streamNr + 2].dwLength =
552
EditStreamEnd(This, streamNr + 2) - startPos;
553
This->pStreams[streamNr + 2].dwStart = startPos;
554
This->pStreams[streamNr].dwLength =
555
startPos - This->pStreams[streamNr].dwStart;
556
IAVIStream_AddRef(This->pStreams[streamNr].pStream);
557
streamNr++;
558
} else {
559
/* insert before stream at streamNr */
560
memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
561
(This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
562
}
563
} else /* append the streams */
564
streamNr = This->nStreams;
565
566
if (pEdit != NULL) {
567
/* insert the parts of the editable stream instead of itself */
568
AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
569
&endPos, NULL, FALSE);
570
AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
571
572
memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
573
nStreams * sizeof(EditStreamTable));
574
if (This->pStreams[streamNr].dwStart < startPos) {
575
This->pStreams[streamNr].dwLength =
576
EditStreamEnd(This, streamNr) - startPos;
577
This->pStreams[streamNr].dwStart = startPos;
578
}
579
if (endPos < EditStreamEnd(This, streamNr + nStreams))
580
This->pStreams[streamNr + nStreams].dwLength =
581
endPos - This->pStreams[streamNr + nStreams].dwStart;
582
} else {
583
/* a simple stream */
584
This->pStreams[streamNr].pStream = pSource;
585
This->pStreams[streamNr].dwStart = lStart;
586
This->pStreams[streamNr].dwLength = lLength;
587
}
588
589
for (n = 0; n < nStreams; n++) {
590
IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
591
if (0 < streamNr + n &&
592
This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
593
This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
594
This->sInfo.dwFormatChangeCount++;
595
}
596
}
597
This->sInfo.dwEditCount++;
598
This->sInfo.dwLength += lLength;
599
This->nStreams += nStreams;
600
601
return AVIERR_OK;
602
}
603
604
static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
605
PAVISTREAM*ppResult)
606
{
607
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
608
IAVIEditStreamImpl* pEdit;
609
DWORD i;
610
611
TRACE("(%p,%p)\n",iface,ppResult);
612
613
if (ppResult == NULL)
614
return AVIERR_BADPARAM;
615
*ppResult = NULL;
616
617
pEdit = AVIFILE_CreateEditStream(NULL);
618
if (pEdit == NULL)
619
return AVIERR_MEMORY;
620
if (This->nStreams > pEdit->nTableSize) {
621
pEdit->pStreams = _recalloc(pEdit->pStreams, This->nStreams, sizeof(EditStreamTable));
622
if (pEdit->pStreams == NULL)
623
return AVIERR_MEMORY;
624
pEdit->nTableSize = This->nStreams;
625
}
626
pEdit->nStreams = This->nStreams;
627
memcpy(pEdit->pStreams, This->pStreams,
628
This->nStreams * sizeof(EditStreamTable));
629
memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
630
for (i = 0; i < This->nStreams; i++) {
631
if (pEdit->pStreams[i].pStream != NULL)
632
IAVIStream_AddRef(pEdit->pStreams[i].pStream);
633
}
634
635
*ppResult = &This->IAVIStream_iface;
636
637
return AVIERR_OK;
638
}
639
640
static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
641
LPAVISTREAMINFOW asi,LONG size)
642
{
643
IAVIEditStreamImpl *This = impl_from_IAVIEditStream(iface);
644
645
TRACE("(%p,%p,%ld)\n",iface,asi,size);
646
647
/* check parameters */
648
if (size >= 0 && size < sizeof(AVISTREAMINFOW))
649
return AVIERR_BADSIZE;
650
651
This->sInfo.wLanguage = asi->wLanguage;
652
This->sInfo.wPriority = asi->wPriority;
653
This->sInfo.dwStart = asi->dwStart;
654
This->sInfo.dwRate = asi->dwRate;
655
This->sInfo.dwScale = asi->dwScale;
656
This->sInfo.dwQuality = asi->dwQuality;
657
This->sInfo.rcFrame = asi->rcFrame;
658
memcpy(This->sInfo.szName, asi->szName, sizeof(asi->szName));
659
This->sInfo.dwEditCount++;
660
661
return AVIERR_OK;
662
}
663
664
static const struct IAVIEditStreamVtbl ieditstream = {
665
IAVIEditStream_fnQueryInterface,
666
IAVIEditStream_fnAddRef,
667
IAVIEditStream_fnRelease,
668
IAVIEditStream_fnCut,
669
IAVIEditStream_fnCopy,
670
IAVIEditStream_fnPaste,
671
IAVIEditStream_fnClone,
672
IAVIEditStream_fnSetInfo
673
};
674
675
static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
676
REFIID refiid,LPVOID*obj)
677
{
678
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
679
return IAVIEditStream_QueryInterface(&This->IAVIEditStream_iface,refiid,obj);
680
}
681
682
static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
683
{
684
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
685
return IAVIEditStream_AddRef(&This->IAVIEditStream_iface);
686
}
687
688
static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
689
{
690
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
691
return IAVIEditStream_Release(&This->IAVIEditStream_iface);
692
}
693
694
static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
695
LPARAM lParam1,LPARAM lParam2)
696
{
697
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
698
699
if (lParam2 != 0)
700
return AVIERR_ERROR;
701
702
if (This->pStreams == NULL) {
703
This->pStreams = calloc(256, sizeof(EditStreamTable));
704
if (This->pStreams == NULL)
705
return AVIERR_MEMORY;
706
This->nTableSize = 256;
707
}
708
709
if (lParam1 != 0) {
710
IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
711
IAVIStream_AddRef((PAVISTREAM)lParam1);
712
This->pStreams[0].pStream = (PAVISTREAM)lParam1;
713
This->pStreams[0].dwStart = This->sInfo.dwStart;
714
This->pStreams[0].dwLength = This->sInfo.dwLength;
715
This->nStreams = 1;
716
}
717
return AVIERR_OK;
718
}
719
720
static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
721
AVISTREAMINFOW *psi,LONG size)
722
{
723
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
724
725
TRACE("(%p,%p,%ld)\n",iface,psi,size);
726
727
if (psi == NULL)
728
return AVIERR_BADPARAM;
729
if (size < 0)
730
return AVIERR_BADSIZE;
731
732
if (This->bDecompress)
733
This->sInfo.fccHandler = 0;
734
735
memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
736
737
if ((DWORD)size < sizeof(This->sInfo))
738
return AVIERR_BUFFERTOOSMALL;
739
return AVIERR_OK;
740
}
741
742
static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
743
LONG flags)
744
{
745
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
746
PAVISTREAM stream;
747
DWORD streamPos, streamNr;
748
749
TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
750
751
if (flags & FIND_FROM_START)
752
pos = (LONG)This->sInfo.dwStart;
753
754
/* outside of stream? */
755
if (pos < (LONG)This->sInfo.dwStart ||
756
(LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
757
return -1;
758
759
/* map our position to a stream and position in it */
760
if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
761
&streamNr, TRUE) != S_OK)
762
return -1; /* doesn't exist */
763
764
if (This->bDecompress) {
765
/* only one stream -- format changes only at start */
766
if (flags & FIND_FORMAT)
767
return (flags & FIND_NEXT ? -1 : 0);
768
769
/* FIXME: map positions back to us */
770
return IAVIStream_FindSample(stream, streamPos, flags);
771
} else {
772
/* assume change of format every frame */
773
return pos;
774
}
775
}
776
777
static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
778
LPVOID format,LONG*fmtsize)
779
{
780
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
781
LPBITMAPINFOHEADER lp;
782
PAVISTREAM stream;
783
DWORD n;
784
HRESULT hr;
785
786
TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
787
788
if (fmtsize == NULL || pos < This->sInfo.dwStart ||
789
This->sInfo.dwStart + This->sInfo.dwLength <= pos)
790
return AVIERR_BADPARAM;
791
792
/* find stream corresponding to position */
793
hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
794
if (FAILED(hr))
795
return hr;
796
797
if (! This->bDecompress)
798
return IAVIStream_ReadFormat(stream, n, format, fmtsize);
799
800
lp = AVIFILE_ReadFrame(This, stream, n);
801
if (lp == NULL)
802
return AVIERR_ERROR;
803
if (lp->biBitCount <= 8) {
804
n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
805
n *= sizeof(RGBQUAD);
806
} else
807
n = 0;
808
n += lp->biSize;
809
810
memcpy(format, lp, min((LONG)n, *fmtsize));
811
hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
812
*fmtsize = n;
813
814
return hr;
815
}
816
817
static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
818
LPVOID format,LONG formatsize)
819
{
820
TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
821
822
return AVIERR_UNSUPPORTED;
823
}
824
825
static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
826
LONG samples,LPVOID buffer,
827
LONG buffersize,LONG*bytesread,
828
LONG*samplesread)
829
{
830
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
831
PAVISTREAM stream;
832
DWORD streamPos, streamNr;
833
LONG readBytes, readSamples, count;
834
HRESULT hr;
835
836
TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
837
buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
838
839
/* check parameters */
840
if (bytesread != NULL)
841
*bytesread = 0;
842
if (samplesread != NULL)
843
*samplesread = 0;
844
if (buffersize < 0)
845
return AVIERR_BADSIZE;
846
if ((DWORD)start < This->sInfo.dwStart ||
847
This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
848
return AVIERR_BADPARAM;
849
850
if (! This->bDecompress) {
851
/* audio like data -- sample-based */
852
do {
853
if (samples == 0)
854
return AVIERR_OK; /* nothing at all or already done */
855
856
if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
857
&streamPos, &streamNr, FALSE)))
858
return AVIERR_ERROR;
859
860
/* limit to end of the stream */
861
count = samples;
862
if (streamPos + count > EditStreamEnd(This, streamNr))
863
count = EditStreamEnd(This, streamNr) - streamPos;
864
865
hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
866
&readBytes, &readSamples);
867
if (FAILED(hr))
868
return hr;
869
if (readBytes == 0 && readSamples == 0 && count != 0)
870
return AVIERR_FILEREAD; /* for bad stream implementations */
871
872
if (samplesread != NULL)
873
*samplesread += readSamples;
874
if (bytesread != NULL)
875
*bytesread += readBytes;
876
if (buffer != NULL) {
877
buffer = ((LPBYTE)buffer)+readBytes;
878
buffersize -= readBytes;
879
}
880
start += count;
881
samples -= count;
882
} while (This->sInfo.dwStart + This->sInfo.dwLength > start);
883
} else {
884
/* video like data -- frame-based */
885
LPBITMAPINFOHEADER lp;
886
887
if (samples == 0)
888
return AVIERR_OK;
889
890
if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
891
&streamPos, &streamNr, FALSE)))
892
return AVIERR_ERROR;
893
894
lp = AVIFILE_ReadFrame(This, stream, streamPos);
895
if (lp == NULL)
896
return AVIERR_ERROR;
897
898
if (buffer != NULL) {
899
/* need size of format to skip */
900
if (lp->biBitCount <= 8) {
901
count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
902
count *= sizeof(RGBQUAD);
903
} else
904
count = 0;
905
count += lp->biSize;
906
907
if (buffersize < lp->biSizeImage)
908
return AVIERR_BUFFERTOOSMALL;
909
memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
910
}
911
912
if (bytesread != NULL)
913
*bytesread = lp->biSizeImage;
914
if (samplesread != NULL)
915
*samplesread = 1;
916
}
917
918
return AVIERR_OK;
919
}
920
921
static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
922
LONG samples,LPVOID buffer,
923
LONG buffersize,DWORD flags,
924
LONG*sampwritten,LONG*byteswritten)
925
{
926
TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
927
buffersize,flags,sampwritten,byteswritten);
928
929
/* be sure return parameters have correct values */
930
if (sampwritten != NULL)
931
*sampwritten = 0;
932
if (byteswritten != NULL)
933
*byteswritten = 0;
934
935
return AVIERR_UNSUPPORTED;
936
}
937
938
static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
939
LONG samples)
940
{
941
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
942
943
TRACE("(%p,%ld,%ld)\n",iface,start,samples);
944
945
return IAVIEditStream_Cut(&This->IAVIEditStream_iface,&start,&samples,NULL);
946
}
947
948
static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
949
LPVOID lp,LONG *lpread)
950
{
951
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
952
DWORD n;
953
954
TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
955
956
/* check parameters */
957
if (lp == NULL || lpread == NULL)
958
return AVIERR_BADPARAM;
959
960
/* simply ask every stream and return the first block found */
961
for (n = 0; n < This->nStreams; n++) {
962
HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
963
964
if (SUCCEEDED(hr))
965
return hr;
966
}
967
968
*lpread = 0;
969
return AVIERR_NODATA;
970
}
971
972
static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
973
LPVOID lp,LONG size)
974
{
975
TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
976
977
return AVIERR_UNSUPPORTED;
978
}
979
980
static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
981
AVISTREAMINFOW*info,LONG len)
982
{
983
IAVIEditStreamImpl *This = impl_from_IAVIStream( iface );
984
985
TRACE("(%p,%p,%ld)\n",iface,info,len);
986
987
return IAVIEditStream_SetInfo(&This->IAVIEditStream_iface,info,len);
988
}
989
990
static const struct IAVIStreamVtbl ieditstast = {
991
IEditAVIStream_fnQueryInterface,
992
IEditAVIStream_fnAddRef,
993
IEditAVIStream_fnRelease,
994
IEditAVIStream_fnCreate,
995
IEditAVIStream_fnInfo,
996
IEditAVIStream_fnFindSample,
997
IEditAVIStream_fnReadFormat,
998
IEditAVIStream_fnSetFormat,
999
IEditAVIStream_fnRead,
1000
IEditAVIStream_fnWrite,
1001
IEditAVIStream_fnDelete,
1002
IEditAVIStream_fnReadData,
1003
IEditAVIStream_fnWriteData,
1004
IEditAVIStream_fnSetInfo
1005
};
1006
1007
static IAVIEditStreamImpl *AVIFILE_CreateEditStream(IAVIStream *pstream)
1008
{
1009
IAVIEditStreamImpl *pedit = NULL;
1010
1011
pedit = calloc(1, sizeof(IAVIEditStreamImpl));
1012
if (pedit == NULL)
1013
return NULL;
1014
1015
pedit->IAVIEditStream_iface.lpVtbl = &ieditstream;
1016
pedit->IAVIStream_iface.lpVtbl = &ieditstast;
1017
pedit->ref = 1;
1018
1019
IAVIStream_Create(&pedit->IAVIStream_iface, (LPARAM)pstream, 0);
1020
1021
return pedit;
1022
}
1023
1024
/***********************************************************************
1025
* CreateEditableStream (AVIFIL32.@)
1026
*/
1027
HRESULT WINAPI CreateEditableStream(IAVIStream **editable, IAVIStream *src)
1028
{
1029
IAVIEditStream *edit = NULL;
1030
IAVIEditStreamImpl *editobj;
1031
HRESULT hr;
1032
1033
TRACE("(%p,%p)\n", editable, src);
1034
1035
if (!editable)
1036
return AVIERR_BADPARAM;
1037
*editable = NULL;
1038
1039
if (src) {
1040
hr = IAVIStream_QueryInterface(src, &IID_IAVIEditStream, (void**)&edit);
1041
if (SUCCEEDED(hr) && edit) {
1042
hr = IAVIEditStream_Clone(edit, editable);
1043
IAVIEditStream_Release(edit);
1044
1045
return hr;
1046
}
1047
}
1048
1049
/* Need own implementation of IAVIEditStream */
1050
editobj = AVIFILE_CreateEditStream(src);
1051
if (!editobj)
1052
return AVIERR_MEMORY;
1053
*editable = &editobj->IAVIStream_iface;
1054
1055
return S_OK;
1056
}
1057
1058