Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/amstream/ddrawstream.c
4389 views
1
/*
2
* Primary DirectDraw video stream
3
*
4
* Copyright 2005, 2008, 2012 Christian Costa
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#define COBJMACROS
22
#include "amstream_private.h"
23
#include "wine/debug.h"
24
#include "wine/list.h"
25
#include "wine/strmbase.h"
26
27
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
28
29
static const WCHAR sink_id[] = L"I{A35FF56A-9FDA-11D0-8FDF-00C04FD9189D}";
30
31
struct format
32
{
33
DWORD flags;
34
DWORD width;
35
DWORD height;
36
DDPIXELFORMAT pf;
37
};
38
39
struct ddraw_stream
40
{
41
IAMMediaStream IAMMediaStream_iface;
42
IDirectDrawMediaStream IDirectDrawMediaStream_iface;
43
IMemInputPin IMemInputPin_iface;
44
IMemAllocator IMemAllocator_iface;
45
IPin IPin_iface;
46
LONG ref;
47
LONG sample_refs;
48
49
IMultiMediaStream* parent;
50
MSPID purpose_id;
51
STREAM_TYPE stream_type;
52
IDirectDraw *ddraw;
53
CRITICAL_SECTION cs;
54
IMediaStreamFilter *filter;
55
IFilterGraph *graph;
56
57
IPin *peer;
58
BOOL using_private_allocator;
59
AM_MEDIA_TYPE mt;
60
struct format format;
61
FILTER_STATE state;
62
REFERENCE_TIME segment_start;
63
BOOL eos;
64
BOOL flushing;
65
CONDITION_VARIABLE update_queued_cv;
66
struct list update_queue;
67
68
CONDITION_VARIABLE allocator_cv;
69
bool committed;
70
LONG buffer_count; /* Only used for properties. */
71
};
72
73
struct ddraw_sample
74
{
75
IDirectDrawStreamSample IDirectDrawStreamSample_iface;
76
LONG ref;
77
struct ddraw_stream *parent;
78
IMultiMediaStream *mmstream;
79
IDirectDrawSurface *surface;
80
DDSURFACEDESC surface_desc;
81
RECT rect;
82
STREAM_TIME start_time;
83
STREAM_TIME end_time;
84
BOOL continuous_update;
85
CONDITION_VARIABLE update_cv;
86
HANDLE external_event;
87
88
IMediaSample IMediaSample_iface;
89
unsigned int media_sample_refcount;
90
bool sync_point, preroll, discontinuity;
91
92
struct list entry;
93
HRESULT update_hr;
94
bool pending;
95
};
96
97
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
98
const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample);
99
100
static void remove_queued_update(struct ddraw_sample *sample)
101
{
102
sample->pending = false;
103
list_remove(&sample->entry);
104
WakeConditionVariable(&sample->update_cv);
105
if (sample->external_event)
106
SetEvent(sample->external_event);
107
}
108
109
static void flush_update_queue(struct ddraw_stream *stream, HRESULT update_hr)
110
{
111
struct list *entry;
112
while ((entry = list_head(&stream->update_queue)))
113
{
114
struct ddraw_sample *sample = LIST_ENTRY(entry, struct ddraw_sample, entry);
115
sample->update_hr = update_hr;
116
remove_queued_update(sample);
117
}
118
}
119
120
static HRESULT copy_sample(struct ddraw_sample *sample, int stride, BYTE *pointer,
121
STREAM_TIME start_time, STREAM_TIME end_time)
122
{
123
DDSURFACEDESC desc;
124
DWORD row_size;
125
const BYTE *src_row;
126
BYTE *dst_row;
127
DWORD row;
128
HRESULT hr;
129
130
desc.dwSize = sizeof(desc);
131
hr = IDirectDrawSurface_Lock(sample->surface, &sample->rect, &desc, DDLOCK_WAIT, NULL);
132
if (FAILED(hr))
133
return hr;
134
135
row_size = (sample->rect.right - sample->rect.left) * desc.ddpfPixelFormat.dwRGBBitCount / 8;
136
src_row = pointer;
137
dst_row = desc.lpSurface;
138
for (row = sample->rect.top; row < sample->rect.bottom; ++row)
139
{
140
memcpy(dst_row, src_row, row_size);
141
src_row += stride;
142
dst_row += desc.lPitch;
143
}
144
145
hr = IDirectDrawSurface_Unlock(sample->surface, desc.lpSurface);
146
if (FAILED(hr))
147
return hr;
148
149
sample->start_time = start_time;
150
sample->end_time = end_time;
151
152
return S_OK;
153
}
154
155
static BOOL is_format_compatible(struct ddraw_stream *stream,
156
DWORD width, DWORD height, const DDPIXELFORMAT *connection_pf)
157
{
158
if (stream->format.flags & DDSD_HEIGHT)
159
{
160
if (stream->format.width != width || stream->format.height != height)
161
return FALSE;
162
}
163
if (stream->format.flags & DDSD_PIXELFORMAT)
164
{
165
if (stream->format.pf.dwFlags & DDPF_FOURCC)
166
return FALSE;
167
if (stream->format.pf.dwRGBBitCount != connection_pf->dwRGBBitCount)
168
return FALSE;
169
if (stream->format.pf.dwRGBBitCount == 16 && stream->format.pf.dwGBitMask != connection_pf->dwGBitMask)
170
return FALSE;
171
}
172
return TRUE;
173
}
174
175
static inline struct ddraw_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
176
{
177
return CONTAINING_RECORD(iface, struct ddraw_stream, IAMMediaStream_iface);
178
}
179
180
/*** IUnknown methods ***/
181
static HRESULT WINAPI ddraw_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
182
REFIID riid, void **ret_iface)
183
{
184
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
185
186
TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
187
188
if (IsEqualGUID(riid, &IID_IUnknown) ||
189
IsEqualGUID(riid, &IID_IMediaStream) ||
190
IsEqualGUID(riid, &IID_IAMMediaStream))
191
{
192
IAMMediaStream_AddRef(iface);
193
*ret_iface = iface;
194
return S_OK;
195
}
196
else if (IsEqualGUID(riid, &IID_IDirectDrawMediaStream))
197
{
198
IAMMediaStream_AddRef(iface);
199
*ret_iface = &This->IDirectDrawMediaStream_iface;
200
return S_OK;
201
}
202
else if (IsEqualGUID(riid, &IID_IPin))
203
{
204
IAMMediaStream_AddRef(iface);
205
*ret_iface = &This->IPin_iface;
206
return S_OK;
207
}
208
else if (IsEqualGUID(riid, &IID_IMemInputPin))
209
{
210
IAMMediaStream_AddRef(iface);
211
*ret_iface = &This->IMemInputPin_iface;
212
return S_OK;
213
}
214
else if (IsEqualGUID(riid, &IID_IMemAllocator))
215
{
216
IAMMediaStream_AddRef(iface);
217
*ret_iface = &This->IMemAllocator_iface;
218
return S_OK;
219
}
220
221
ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
222
return E_NOINTERFACE;
223
}
224
225
static ULONG WINAPI ddraw_IAMMediaStream_AddRef(IAMMediaStream *iface)
226
{
227
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
228
ULONG ref = InterlockedIncrement(&This->ref);
229
230
TRACE("(%p/%p)->(): new ref = %lu\n", iface, This, ref);
231
232
return ref;
233
}
234
235
static ULONG WINAPI ddraw_IAMMediaStream_Release(IAMMediaStream *iface)
236
{
237
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
238
ULONG ref = InterlockedDecrement(&stream->ref);
239
240
TRACE("%p decreasing refcount to %lu.\n", stream, ref);
241
242
if (!ref)
243
{
244
DeleteCriticalSection(&stream->cs);
245
if (stream->ddraw)
246
IDirectDraw_Release(stream->ddraw);
247
free(stream);
248
}
249
250
return ref;
251
}
252
253
/*** IMediaStream methods ***/
254
static HRESULT WINAPI ddraw_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
255
IMultiMediaStream **mmstream)
256
{
257
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
258
259
TRACE("stream %p, mmstream %p.\n", stream, mmstream);
260
261
if (!mmstream)
262
return E_POINTER;
263
264
if (stream->parent)
265
IMultiMediaStream_AddRef(stream->parent);
266
*mmstream = stream->parent;
267
return S_OK;
268
}
269
270
static HRESULT WINAPI ddraw_IAMMediaStream_GetInformation(IAMMediaStream *iface,
271
MSPID *purpose_id, STREAM_TYPE *type)
272
{
273
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
274
275
TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
276
277
if (purpose_id)
278
*purpose_id = This->purpose_id;
279
if (type)
280
*type = This->stream_type;
281
282
return S_OK;
283
}
284
285
static HRESULT WINAPI ddraw_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
286
IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
287
{
288
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
289
290
FIXME("(%p/%p)->(%p,%lx) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
291
292
return S_FALSE;
293
}
294
295
static HRESULT WINAPI ddraw_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
296
DWORD flags, IStreamSample **sample)
297
{
298
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
299
300
FIXME("(%p/%p)->(%lx,%p) stub!\n", This, iface, flags, sample);
301
302
return S_FALSE;
303
}
304
305
static HRESULT WINAPI ddraw_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
306
IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
307
{
308
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
309
310
FIXME("(%p/%p)->(%p,%lx,%p) stub!\n", This, iface, existing_sample, flags, sample);
311
312
return S_FALSE;
313
}
314
315
static HRESULT WINAPI ddraw_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
316
{
317
struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
318
319
FIXME("(%p/%p)->(%lx) stub!\n", This, iface, flags);
320
321
return S_FALSE;
322
}
323
324
/*** IAMMediaStream methods ***/
325
static HRESULT WINAPI ddraw_IAMMediaStream_Initialize(IAMMediaStream *iface, IUnknown *source_object, DWORD flags,
326
REFMSPID purpose_id, const STREAM_TYPE stream_type)
327
{
328
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
329
HRESULT hr;
330
331
TRACE("stream %p, source_object %p, flags %lx, purpose_id %s, stream_type %u.\n", stream, source_object, flags,
332
debugstr_guid(purpose_id), stream_type);
333
334
if (!purpose_id)
335
return E_POINTER;
336
337
if (flags & AMMSF_CREATEPEER)
338
FIXME("AMMSF_CREATEPEER is not yet supported.\n");
339
340
stream->purpose_id = *purpose_id;
341
stream->stream_type = stream_type;
342
343
if (stream->ddraw)
344
IDirectDraw_Release(stream->ddraw);
345
stream->ddraw = NULL;
346
347
if (source_object
348
&& FAILED(hr = IUnknown_QueryInterface(source_object, &IID_IDirectDraw, (void **)&stream->ddraw)))
349
FIXME("Stream object doesn't implement IDirectDraw interface, hr %#lx.\n", hr);
350
351
if (!source_object)
352
{
353
if (FAILED(hr = DirectDrawCreate(NULL, &stream->ddraw, NULL)))
354
return hr;
355
IDirectDraw_SetCooperativeLevel(stream->ddraw, NULL, DDSCL_NORMAL);
356
}
357
358
return S_OK;
359
}
360
361
static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
362
{
363
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
364
365
TRACE("stream %p, state %u.\n", stream, state);
366
367
EnterCriticalSection(&stream->cs);
368
369
if (state == State_Stopped)
370
WakeConditionVariable(&stream->update_queued_cv);
371
if (stream->state == State_Stopped)
372
stream->eos = FALSE;
373
374
stream->state = state;
375
376
LeaveCriticalSection(&stream->cs);
377
378
return S_OK;
379
}
380
381
static HRESULT WINAPI ddraw_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface, IAMMultiMediaStream *mmstream)
382
{
383
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
384
385
TRACE("stream %p, mmstream %p.\n", stream, mmstream);
386
387
stream->parent = (IMultiMediaStream *)mmstream;
388
389
return S_OK;
390
}
391
392
static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
393
{
394
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
395
396
TRACE("iface %p, filter %p.\n", iface, filter);
397
398
stream->filter = filter;
399
400
return S_OK;
401
}
402
403
static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
404
{
405
struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
406
407
TRACE("stream %p, filtergraph %p.\n", stream, filtergraph);
408
409
stream->graph = filtergraph;
410
411
return S_OK;
412
}
413
414
static const struct IAMMediaStreamVtbl ddraw_IAMMediaStream_vtbl =
415
{
416
/*** IUnknown methods ***/
417
ddraw_IAMMediaStream_QueryInterface,
418
ddraw_IAMMediaStream_AddRef,
419
ddraw_IAMMediaStream_Release,
420
/*** IMediaStream methods ***/
421
ddraw_IAMMediaStream_GetMultiMediaStream,
422
ddraw_IAMMediaStream_GetInformation,
423
ddraw_IAMMediaStream_SetSameFormat,
424
ddraw_IAMMediaStream_AllocateSample,
425
ddraw_IAMMediaStream_CreateSharedSample,
426
ddraw_IAMMediaStream_SendEndOfStream,
427
/*** IAMMediaStream methods ***/
428
ddraw_IAMMediaStream_Initialize,
429
ddraw_IAMMediaStream_SetState,
430
ddraw_IAMMediaStream_JoinAMMultiMediaStream,
431
ddraw_IAMMediaStream_JoinFilter,
432
ddraw_IAMMediaStream_JoinFilterGraph
433
};
434
435
static inline struct ddraw_stream *impl_from_IDirectDrawMediaStream(IDirectDrawMediaStream *iface)
436
{
437
return CONTAINING_RECORD(iface, struct ddraw_stream, IDirectDrawMediaStream_iface);
438
}
439
440
/*** IUnknown methods ***/
441
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_QueryInterface(IDirectDrawMediaStream *iface,
442
REFIID riid, void **ret_iface)
443
{
444
struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
445
TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
446
return IAMMediaStream_QueryInterface(&This->IAMMediaStream_iface, riid, ret_iface);
447
}
448
449
static ULONG WINAPI ddraw_IDirectDrawMediaStream_AddRef(IDirectDrawMediaStream *iface)
450
{
451
struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
452
TRACE("(%p/%p)\n", iface, This);
453
return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
454
}
455
456
static ULONG WINAPI ddraw_IDirectDrawMediaStream_Release(IDirectDrawMediaStream *iface)
457
{
458
struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
459
TRACE("(%p/%p)\n", iface, This);
460
return IAMMediaStream_Release(&This->IAMMediaStream_iface);
461
}
462
463
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetMultiMediaStream(IDirectDrawMediaStream *iface,
464
IMultiMediaStream **mmstream)
465
{
466
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
467
return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
468
}
469
470
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetInformation(IDirectDrawMediaStream *iface,
471
MSPID *purpose_id, STREAM_TYPE *type)
472
{
473
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
474
return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
475
}
476
477
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetSameFormat(IDirectDrawMediaStream *iface,
478
IMediaStream *other, DWORD flags)
479
{
480
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
481
return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
482
}
483
484
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_AllocateSample(IDirectDrawMediaStream *iface,
485
DWORD flags, IStreamSample **sample)
486
{
487
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
488
return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
489
}
490
491
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSharedSample(IDirectDrawMediaStream *iface,
492
IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
493
{
494
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
495
return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
496
}
497
498
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SendEndOfStream(IDirectDrawMediaStream *iface, DWORD flags)
499
{
500
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
501
return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
502
}
503
504
/*** IDirectDrawMediaStream methods ***/
505
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetFormat(IDirectDrawMediaStream *iface,
506
DDSURFACEDESC *current_format, IDirectDrawPalette **palette,
507
DDSURFACEDESC *desired_format, DWORD *flags)
508
{
509
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
510
511
TRACE("stream %p, current_format %p, palette %p, desired_format %p, flags %p.\n", stream, current_format, palette,
512
desired_format, flags);
513
514
EnterCriticalSection(&stream->cs);
515
516
if (!stream->peer)
517
{
518
LeaveCriticalSection(&stream->cs);
519
return MS_E_NOSTREAM;
520
}
521
522
if (current_format)
523
{
524
current_format->dwFlags = stream->format.flags | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
525
current_format->dwWidth = stream->format.width;
526
current_format->dwHeight = stream->format.height;
527
current_format->ddpfPixelFormat = stream->format.pf;
528
current_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
529
}
530
531
if (palette)
532
*palette = NULL;
533
534
if (desired_format)
535
{
536
desired_format->dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
537
desired_format->dwWidth = stream->format.width;
538
desired_format->dwHeight = stream->format.height;
539
desired_format->ddpfPixelFormat = stream->format.pf;
540
desired_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
541
}
542
543
if (flags)
544
*flags = 0;
545
546
LeaveCriticalSection(&stream->cs);
547
548
return S_OK;
549
}
550
551
static unsigned int align(unsigned int n, unsigned int alignment)
552
{
553
return (n + alignment - 1) & ~(alignment - 1);
554
}
555
556
static void set_mt_from_desc(AM_MEDIA_TYPE *mt, const DDSURFACEDESC *format, unsigned int pitch)
557
{
558
VIDEOINFO *videoinfo = CoTaskMemAlloc(sizeof(VIDEOINFO));
559
560
memset(mt, 0, sizeof(*mt));
561
mt->majortype = MEDIATYPE_Video;
562
mt->formattype = FORMAT_VideoInfo;
563
mt->cbFormat = sizeof(VIDEOINFO);
564
mt->pbFormat = (BYTE *)videoinfo;
565
566
memset(videoinfo, 0, sizeof(*videoinfo));
567
SetRect(&videoinfo->rcSource, 0, 0, format->dwWidth, format->dwHeight);
568
SetRect(&videoinfo->rcTarget, 0, 0, format->dwWidth, format->dwHeight);
569
videoinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
570
videoinfo->bmiHeader.biWidth = pitch * 8 / format->ddpfPixelFormat.dwRGBBitCount;
571
videoinfo->bmiHeader.biHeight = -format->dwHeight;
572
videoinfo->bmiHeader.biBitCount = format->ddpfPixelFormat.dwRGBBitCount;
573
videoinfo->bmiHeader.biCompression = BI_RGB;
574
videoinfo->bmiHeader.biPlanes = 1;
575
videoinfo->bmiHeader.biSizeImage = align(pitch * format->dwHeight, 4);
576
577
mt->lSampleSize = videoinfo->bmiHeader.biSizeImage;
578
mt->bFixedSizeSamples = TRUE;
579
580
if (format->ddpfPixelFormat.dwRGBBitCount == 16 && format->ddpfPixelFormat.dwRBitMask == 0x7c00)
581
{
582
mt->subtype = MEDIASUBTYPE_RGB555;
583
}
584
else if (format->ddpfPixelFormat.dwRGBBitCount == 16 && format->ddpfPixelFormat.dwRBitMask == 0xf800)
585
{
586
mt->subtype = MEDIASUBTYPE_RGB565;
587
videoinfo = (VIDEOINFO *)mt->pbFormat;
588
videoinfo->bmiHeader.biCompression = BI_BITFIELDS;
589
videoinfo->dwBitMasks[iRED] = 0xf800;
590
videoinfo->dwBitMasks[iGREEN] = 0x07e0;
591
videoinfo->dwBitMasks[iBLUE] = 0x001f;
592
}
593
else if (format->ddpfPixelFormat.dwRGBBitCount == 24)
594
{
595
mt->subtype = MEDIASUBTYPE_RGB24;
596
}
597
else if (format->ddpfPixelFormat.dwRGBBitCount == 32)
598
{
599
mt->subtype = MEDIASUBTYPE_RGB32;
600
}
601
else if (format->ddpfPixelFormat.dwRGBBitCount == 8 && (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8))
602
{
603
mt->subtype = MEDIASUBTYPE_RGB8;
604
videoinfo->bmiHeader.biClrUsed = 256;
605
/* FIXME: Translate the palette. */
606
}
607
else
608
{
609
FIXME("Unknown flags %#lx, bit count %lu.\n",
610
format->ddpfPixelFormat.dwFlags, format->ddpfPixelFormat.dwRGBBitCount);
611
}
612
}
613
614
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetFormat(IDirectDrawMediaStream *iface,
615
const DDSURFACEDESC *format, IDirectDrawPalette *palette)
616
{
617
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
618
struct format old_format;
619
IPin *old_peer;
620
HRESULT hr;
621
622
TRACE("stream %p, format %p, palette %p.\n", stream, format, palette);
623
624
if (palette)
625
FIXME("Setting palette is not yet supported.\n");
626
627
if (!format)
628
return E_POINTER;
629
630
if (format->dwSize != sizeof(DDSURFACEDESC))
631
return E_INVALIDARG;
632
633
TRACE("flags %#lx, pixel format flags %#lx, bit count %lu, size %lux%lu.\n",
634
format->dwFlags, format->ddpfPixelFormat.dwFlags,
635
format->ddpfPixelFormat.dwRGBBitCount, format->dwWidth, format->dwHeight);
636
637
if (format->dwFlags & DDSD_PIXELFORMAT)
638
{
639
if (format->ddpfPixelFormat.dwSize != sizeof(DDPIXELFORMAT))
640
{
641
WARN("Invalid size %#lx, returning DDERR_INVALIDSURFACETYPE.\n", format->ddpfPixelFormat.dwSize);
642
return DDERR_INVALIDSURFACETYPE;
643
}
644
645
if (format->ddpfPixelFormat.dwFlags & DDPF_FOURCC)
646
{
647
if (!format->ddpfPixelFormat.dwRGBBitCount)
648
{
649
WARN("Invalid zero bit count, returning E_INVALIDARG.\n");
650
return E_INVALIDARG;
651
}
652
}
653
else
654
{
655
if (format->ddpfPixelFormat.dwFlags & (DDPF_YUV | DDPF_PALETTEINDEXED1 |
656
DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXEDTO8))
657
{
658
WARN("Rejecting flags %#lx.\n", format->ddpfPixelFormat.dwFlags);
659
return DDERR_INVALIDSURFACETYPE;
660
}
661
662
if (!(format->ddpfPixelFormat.dwFlags & DDPF_RGB))
663
{
664
WARN("Rejecting non-RGB flags %#lx.\n", format->ddpfPixelFormat.dwFlags);
665
return DDERR_INVALIDSURFACETYPE;
666
}
667
668
switch (format->ddpfPixelFormat.dwRGBBitCount)
669
{
670
case 8:
671
if (!(format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8))
672
{
673
WARN("Rejecting non-palettized 8-bit format.\n");
674
return DDERR_INVALIDSURFACETYPE;
675
}
676
break;
677
case 16:
678
if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
679
{
680
WARN("Rejecting palettized 16-bit format.\n");
681
return DDERR_INVALIDSURFACETYPE;
682
}
683
if ((format->ddpfPixelFormat.dwRBitMask != 0x7c00 ||
684
format->ddpfPixelFormat.dwGBitMask != 0x03e0 ||
685
format->ddpfPixelFormat.dwBBitMask != 0x001f) &&
686
(format->ddpfPixelFormat.dwRBitMask != 0xf800 ||
687
format->ddpfPixelFormat.dwGBitMask != 0x07e0 ||
688
format->ddpfPixelFormat.dwBBitMask != 0x001f))
689
{
690
WARN("Rejecting bit masks %08lx, %08lx, %08lx.\n",
691
format->ddpfPixelFormat.dwRBitMask,
692
format->ddpfPixelFormat.dwGBitMask,
693
format->ddpfPixelFormat.dwBBitMask);
694
return DDERR_INVALIDSURFACETYPE;
695
}
696
break;
697
case 24:
698
case 32:
699
if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
700
{
701
WARN("Rejecting palettized %lu-bit format.\n", format->ddpfPixelFormat.dwRGBBitCount);
702
return DDERR_INVALIDSURFACETYPE;
703
}
704
if (format->ddpfPixelFormat.dwRBitMask != 0xff0000 ||
705
format->ddpfPixelFormat.dwGBitMask != 0x00ff00 ||
706
format->ddpfPixelFormat.dwBBitMask != 0x0000ff)
707
{
708
WARN("Rejecting bit masks %08lx, %08lx, %08lx.\n",
709
format->ddpfPixelFormat.dwRBitMask,
710
format->ddpfPixelFormat.dwGBitMask,
711
format->ddpfPixelFormat.dwBBitMask);
712
return DDERR_INVALIDSURFACETYPE;
713
}
714
break;
715
default:
716
WARN("Unknown bit count %lu.\n", format->ddpfPixelFormat.dwRGBBitCount);
717
return DDERR_INVALIDSURFACETYPE;
718
}
719
}
720
}
721
722
EnterCriticalSection(&stream->cs);
723
724
old_format = stream->format;
725
stream->format.flags = format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
726
if (format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT))
727
{
728
stream->format.width = format->dwWidth;
729
stream->format.height = format->dwHeight;
730
}
731
if (format->dwFlags & DDSD_PIXELFORMAT)
732
stream->format.pf = format->ddpfPixelFormat;
733
734
if (stream->peer && !is_format_compatible(stream, old_format.width, old_format.height, &old_format.pf))
735
{
736
AM_MEDIA_TYPE new_mt;
737
738
if (stream->sample_refs > 0)
739
{
740
WARN("Outstanding sample references, returning MS_E_SAMPLEALLOC.\n");
741
stream->format = old_format;
742
LeaveCriticalSection(&stream->cs);
743
return MS_E_SAMPLEALLOC;
744
}
745
746
set_mt_from_desc(&new_mt, format, format->dwWidth * format->ddpfPixelFormat.dwRGBBitCount / 8);
747
748
if (!stream->using_private_allocator || IPin_QueryAccept(stream->peer, &new_mt) != S_OK)
749
{
750
AM_MEDIA_TYPE old_mt;
751
752
/* Reconnect. */
753
old_peer = stream->peer;
754
IPin_AddRef(old_peer);
755
CopyMediaType(&old_mt, &stream->mt);
756
757
IFilterGraph_Disconnect(stream->graph, stream->peer);
758
IFilterGraph_Disconnect(stream->graph, &stream->IPin_iface);
759
if (FAILED(hr = IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, NULL)))
760
{
761
stream->format = old_format;
762
IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, &old_mt);
763
IPin_Release(old_peer);
764
FreeMediaType(&old_mt);
765
FreeMediaType(&new_mt);
766
LeaveCriticalSection(&stream->cs);
767
return DDERR_INVALIDSURFACETYPE;
768
}
769
FreeMediaType(&old_mt);
770
IPin_Release(old_peer);
771
}
772
773
FreeMediaType(&new_mt);
774
}
775
776
LeaveCriticalSection(&stream->cs);
777
778
return S_OK;
779
}
780
781
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetDirectDraw(IDirectDrawMediaStream *iface,
782
IDirectDraw **ddraw)
783
{
784
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
785
786
TRACE("stream %p, ddraw %p.\n", stream, ddraw);
787
788
if (!ddraw)
789
return E_POINTER;
790
791
if (!stream->ddraw)
792
{
793
*ddraw = NULL;
794
return S_OK;
795
}
796
797
IDirectDraw_AddRef(stream->ddraw);
798
*ddraw = stream->ddraw;
799
800
return S_OK;
801
}
802
803
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetDirectDraw(IDirectDrawMediaStream *iface,
804
IDirectDraw *ddraw)
805
{
806
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
807
808
TRACE("stream %p, ddraw %p.\n", stream, ddraw);
809
810
EnterCriticalSection(&stream->cs);
811
812
if (stream->sample_refs)
813
{
814
HRESULT hr = (stream->ddraw == ddraw) ? S_OK : MS_E_SAMPLEALLOC;
815
LeaveCriticalSection(&stream->cs);
816
return hr;
817
}
818
819
if (stream->ddraw)
820
IDirectDraw_Release(stream->ddraw);
821
822
if (ddraw)
823
{
824
IDirectDraw_AddRef(ddraw);
825
stream->ddraw = ddraw;
826
}
827
else
828
stream->ddraw = NULL;
829
830
LeaveCriticalSection(&stream->cs);
831
832
return S_OK;
833
}
834
835
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSample(IDirectDrawMediaStream *iface,
836
IDirectDrawSurface *surface, const RECT *rect, DWORD flags,
837
IDirectDrawStreamSample **sample)
838
{
839
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
840
HRESULT hr;
841
842
TRACE("stream %p, surface %p, rect %s, flags %#lx, sample %p.\n",
843
stream, surface, wine_dbgstr_rect(rect), flags, sample);
844
845
if (!surface && rect)
846
return E_INVALIDARG;
847
848
EnterCriticalSection(&stream->cs);
849
hr = ddrawstreamsample_create(stream, surface, rect, sample);
850
LeaveCriticalSection(&stream->cs);
851
852
return hr;
853
}
854
855
static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetTimePerFrame(IDirectDrawMediaStream *iface,
856
STREAM_TIME *frame_time)
857
{
858
struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
859
860
TRACE("stream %p, frame_time %p.\n", stream, frame_time);
861
862
if (!frame_time)
863
return E_POINTER;
864
865
EnterCriticalSection(&stream->cs);
866
867
if (!stream->peer)
868
{
869
LeaveCriticalSection(&stream->cs);
870
return MS_E_NOSTREAM;
871
}
872
873
*frame_time = ((VIDEOINFO *)stream->mt.pbFormat)->AvgTimePerFrame;
874
875
LeaveCriticalSection(&stream->cs);
876
877
return S_OK;
878
}
879
880
static const struct IDirectDrawMediaStreamVtbl ddraw_IDirectDrawMediaStream_Vtbl =
881
{
882
/*** IUnknown methods ***/
883
ddraw_IDirectDrawMediaStream_QueryInterface,
884
ddraw_IDirectDrawMediaStream_AddRef,
885
ddraw_IDirectDrawMediaStream_Release,
886
/*** IMediaStream methods ***/
887
ddraw_IDirectDrawMediaStream_GetMultiMediaStream,
888
ddraw_IDirectDrawMediaStream_GetInformation,
889
ddraw_IDirectDrawMediaStream_SetSameFormat,
890
ddraw_IDirectDrawMediaStream_AllocateSample,
891
ddraw_IDirectDrawMediaStream_CreateSharedSample,
892
ddraw_IDirectDrawMediaStream_SendEndOfStream,
893
/*** IDirectDrawMediaStream methods ***/
894
ddraw_IDirectDrawMediaStream_GetFormat,
895
ddraw_IDirectDrawMediaStream_SetFormat,
896
ddraw_IDirectDrawMediaStream_GetDirectDraw,
897
ddraw_IDirectDrawMediaStream_SetDirectDraw,
898
ddraw_IDirectDrawMediaStream_CreateSample,
899
ddraw_IDirectDrawMediaStream_GetTimePerFrame
900
};
901
902
struct enum_media_types
903
{
904
IEnumMediaTypes IEnumMediaTypes_iface;
905
LONG refcount;
906
unsigned int index;
907
};
908
909
static const IEnumMediaTypesVtbl enum_media_types_vtbl;
910
911
static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
912
{
913
return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
914
}
915
916
static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
917
{
918
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
919
920
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
921
{
922
IEnumMediaTypes_AddRef(iface);
923
*out = iface;
924
return S_OK;
925
}
926
927
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
928
*out = NULL;
929
return E_NOINTERFACE;
930
}
931
932
static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
933
{
934
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
935
ULONG refcount = InterlockedIncrement(&enum_media_types->refcount);
936
TRACE("%p increasing refcount to %lu.\n", enum_media_types, refcount);
937
return refcount;
938
}
939
940
static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
941
{
942
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
943
ULONG refcount = InterlockedDecrement(&enum_media_types->refcount);
944
TRACE("%p decreasing refcount to %lu.\n", enum_media_types, refcount);
945
if (!refcount)
946
free(enum_media_types);
947
return refcount;
948
}
949
950
static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
951
{
952
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
953
954
TRACE("iface %p, count %lu, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
955
956
if (!ret_count)
957
return E_POINTER;
958
959
if (count && !enum_media_types->index)
960
{
961
mts[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
962
memset(mts[0], 0, sizeof(AM_MEDIA_TYPE));
963
mts[0]->majortype = MEDIATYPE_Video;
964
mts[0]->subtype = MEDIASUBTYPE_RGB8;
965
mts[0]->bFixedSizeSamples = TRUE;
966
mts[0]->lSampleSize = 10000;
967
++enum_media_types->index;
968
*ret_count = 1;
969
return count == 1 ? S_OK : S_FALSE;
970
}
971
972
*ret_count = 0;
973
return count ? S_FALSE : S_OK;
974
}
975
976
static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
977
{
978
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
979
980
TRACE("iface %p, count %lu.\n", iface, count);
981
982
enum_media_types->index += count;
983
984
return S_OK;
985
}
986
987
static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
988
{
989
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
990
991
TRACE("iface %p.\n", iface);
992
993
enum_media_types->index = 0;
994
return S_OK;
995
}
996
997
static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
998
{
999
struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
1000
struct enum_media_types *object;
1001
1002
TRACE("iface %p, out %p.\n", iface, out);
1003
1004
if (!(object = calloc(1, sizeof(*object))))
1005
return E_OUTOFMEMORY;
1006
1007
object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1008
object->refcount = 1;
1009
object->index = enum_media_types->index;
1010
1011
*out = &object->IEnumMediaTypes_iface;
1012
return S_OK;
1013
}
1014
1015
static const IEnumMediaTypesVtbl enum_media_types_vtbl =
1016
{
1017
enum_media_types_QueryInterface,
1018
enum_media_types_AddRef,
1019
enum_media_types_Release,
1020
enum_media_types_Next,
1021
enum_media_types_Skip,
1022
enum_media_types_Reset,
1023
enum_media_types_Clone,
1024
};
1025
1026
static inline struct ddraw_stream *impl_from_IPin(IPin *iface)
1027
{
1028
return CONTAINING_RECORD(iface, struct ddraw_stream, IPin_iface);
1029
}
1030
1031
static HRESULT WINAPI ddraw_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
1032
{
1033
struct ddraw_stream *stream = impl_from_IPin(iface);
1034
return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1035
}
1036
1037
static ULONG WINAPI ddraw_sink_AddRef(IPin *iface)
1038
{
1039
struct ddraw_stream *stream = impl_from_IPin(iface);
1040
return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1041
}
1042
1043
static ULONG WINAPI ddraw_sink_Release(IPin *iface)
1044
{
1045
struct ddraw_stream *stream = impl_from_IPin(iface);
1046
return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1047
}
1048
1049
static HRESULT WINAPI ddraw_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
1050
{
1051
WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
1052
return E_UNEXPECTED;
1053
}
1054
1055
static HRESULT WINAPI ddraw_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
1056
{
1057
struct ddraw_stream *stream = impl_from_IPin(iface);
1058
const VIDEOINFOHEADER *video_info;
1059
PIN_DIRECTION dir;
1060
DWORD width;
1061
DWORD height;
1062
DDPIXELFORMAT pf = {sizeof(DDPIXELFORMAT)};
1063
1064
TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
1065
strmbase_dump_media_type(mt);
1066
1067
EnterCriticalSection(&stream->cs);
1068
1069
if (stream->peer)
1070
{
1071
LeaveCriticalSection(&stream->cs);
1072
return VFW_E_ALREADY_CONNECTED;
1073
}
1074
1075
if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
1076
|| !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
1077
{
1078
LeaveCriticalSection(&stream->cs);
1079
return VFW_E_TYPE_NOT_ACCEPTED;
1080
}
1081
1082
video_info = (const VIDEOINFOHEADER *)mt->pbFormat;
1083
1084
width = video_info->bmiHeader.biWidth;
1085
height = abs(video_info->bmiHeader.biHeight);
1086
pf.dwFlags = DDPF_RGB;
1087
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8))
1088
{
1089
pf.dwFlags |= DDPF_PALETTEINDEXED8;
1090
pf.dwRGBBitCount = 8;
1091
}
1092
else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB555))
1093
{
1094
pf.dwRGBBitCount = 16;
1095
pf.dwRBitMask = 0x7c00;
1096
pf.dwGBitMask = 0x03e0;
1097
pf.dwBBitMask = 0x001f;
1098
}
1099
else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB565))
1100
{
1101
pf.dwRGBBitCount = 16;
1102
pf.dwRBitMask = 0xf800;
1103
pf.dwGBitMask = 0x07e0;
1104
pf.dwBBitMask = 0x001f;
1105
}
1106
else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB24))
1107
{
1108
pf.dwRGBBitCount = 24;
1109
pf.dwRBitMask = 0xff0000;
1110
pf.dwGBitMask = 0x00ff00;
1111
pf.dwBBitMask = 0x0000ff;
1112
}
1113
else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB32))
1114
{
1115
pf.dwRGBBitCount = 32;
1116
pf.dwRBitMask = 0xff0000;
1117
pf.dwGBitMask = 0x00ff00;
1118
pf.dwBBitMask = 0x0000ff;
1119
}
1120
else
1121
{
1122
LeaveCriticalSection(&stream->cs);
1123
return VFW_E_TYPE_NOT_ACCEPTED;
1124
}
1125
1126
if (!is_format_compatible(stream, width, height, &pf))
1127
{
1128
LeaveCriticalSection(&stream->cs);
1129
return VFW_E_TYPE_NOT_ACCEPTED;
1130
}
1131
1132
IPin_QueryDirection(peer, &dir);
1133
if (dir != PINDIR_OUTPUT)
1134
{
1135
WARN("Rejecting connection from input pin.\n");
1136
LeaveCriticalSection(&stream->cs);
1137
return VFW_E_INVALID_DIRECTION;
1138
}
1139
1140
CopyMediaType(&stream->mt, mt);
1141
IPin_AddRef(stream->peer = peer);
1142
1143
stream->format.width = width;
1144
stream->format.height = height;
1145
if (!(stream->format.flags & DDSD_PIXELFORMAT))
1146
stream->format.pf = pf;
1147
1148
LeaveCriticalSection(&stream->cs);
1149
1150
return S_OK;
1151
}
1152
1153
static HRESULT WINAPI ddraw_sink_Disconnect(IPin *iface)
1154
{
1155
struct ddraw_stream *stream = impl_from_IPin(iface);
1156
1157
TRACE("stream %p.\n", stream);
1158
1159
EnterCriticalSection(&stream->cs);
1160
1161
if (!stream->peer)
1162
{
1163
LeaveCriticalSection(&stream->cs);
1164
return S_FALSE;
1165
}
1166
1167
IPin_Release(stream->peer);
1168
stream->peer = NULL;
1169
FreeMediaType(&stream->mt);
1170
memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
1171
1172
LeaveCriticalSection(&stream->cs);
1173
1174
return S_OK;
1175
}
1176
1177
static HRESULT WINAPI ddraw_sink_ConnectedTo(IPin *iface, IPin **peer)
1178
{
1179
struct ddraw_stream *stream = impl_from_IPin(iface);
1180
HRESULT hr;
1181
1182
TRACE("stream %p, peer %p.\n", stream, peer);
1183
1184
EnterCriticalSection(&stream->cs);
1185
1186
if (stream->peer)
1187
{
1188
IPin_AddRef(*peer = stream->peer);
1189
hr = S_OK;
1190
}
1191
else
1192
{
1193
*peer = NULL;
1194
hr = VFW_E_NOT_CONNECTED;
1195
}
1196
1197
LeaveCriticalSection(&stream->cs);
1198
1199
return hr;
1200
}
1201
1202
static HRESULT WINAPI ddraw_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1203
{
1204
struct ddraw_stream *stream = impl_from_IPin(iface);
1205
HRESULT hr;
1206
1207
TRACE("stream %p, mt %p.\n", stream, mt);
1208
1209
EnterCriticalSection(&stream->cs);
1210
1211
if (stream->peer)
1212
{
1213
CopyMediaType(mt, &stream->mt);
1214
hr = S_OK;
1215
}
1216
else
1217
{
1218
memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1219
hr = VFW_E_NOT_CONNECTED;
1220
}
1221
1222
LeaveCriticalSection(&stream->cs);
1223
1224
return hr;
1225
}
1226
1227
static HRESULT WINAPI ddraw_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1228
{
1229
struct ddraw_stream *stream = impl_from_IPin(iface);
1230
1231
TRACE("stream %p, info %p.\n", stream, info);
1232
1233
IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1234
info->dir = PINDIR_INPUT;
1235
wcscpy(info->achName, sink_id);
1236
1237
return S_OK;
1238
}
1239
1240
static HRESULT WINAPI ddraw_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1241
{
1242
TRACE("iface %p, dir %p.\n", iface, dir);
1243
*dir = PINDIR_INPUT;
1244
return S_OK;
1245
}
1246
1247
static HRESULT WINAPI ddraw_sink_QueryId(IPin *iface, WCHAR **id)
1248
{
1249
TRACE("iface %p, id %p.\n", iface, id);
1250
1251
if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1252
return E_OUTOFMEMORY;
1253
1254
wcscpy(*id, sink_id);
1255
1256
return S_OK;
1257
}
1258
1259
static HRESULT WINAPI ddraw_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1260
{
1261
TRACE("iface %p, mt %p.\n", iface, mt);
1262
1263
if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
1264
&& IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8)
1265
&& IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
1266
return S_OK;
1267
1268
return VFW_E_TYPE_NOT_ACCEPTED;
1269
}
1270
1271
static HRESULT WINAPI ddraw_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1272
{
1273
struct enum_media_types *object;
1274
1275
TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1276
1277
if (!enum_media_types)
1278
return E_POINTER;
1279
1280
if (!(object = calloc(1, sizeof(*object))))
1281
return E_OUTOFMEMORY;
1282
1283
object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1284
object->refcount = 1;
1285
object->index = 0;
1286
1287
*enum_media_types = &object->IEnumMediaTypes_iface;
1288
return S_OK;
1289
}
1290
1291
static HRESULT WINAPI ddraw_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1292
{
1293
TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1294
return E_NOTIMPL;
1295
}
1296
1297
static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
1298
{
1299
struct ddraw_stream *stream = impl_from_IPin(iface);
1300
1301
TRACE("stream %p.\n", stream);
1302
1303
EnterCriticalSection(&stream->cs);
1304
1305
if (stream->eos || stream->flushing)
1306
{
1307
LeaveCriticalSection(&stream->cs);
1308
return E_FAIL;
1309
}
1310
1311
stream->eos = TRUE;
1312
1313
flush_update_queue(stream, MS_S_ENDOFSTREAM);
1314
1315
LeaveCriticalSection(&stream->cs);
1316
1317
/* Calling IMediaStreamFilter::EndOfStream() inside the critical section
1318
* would invert the locking order, so we must leave it first to avoid
1319
* the streaming thread deadlocking on the filter's critical section. */
1320
IMediaStreamFilter_EndOfStream(stream->filter);
1321
1322
return S_OK;
1323
}
1324
1325
static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface)
1326
{
1327
struct ddraw_stream *stream = impl_from_IPin(iface);
1328
BOOL cancel_eos;
1329
1330
TRACE("stream %p.\n", stream);
1331
1332
EnterCriticalSection(&stream->cs);
1333
1334
cancel_eos = stream->eos;
1335
1336
stream->flushing = TRUE;
1337
stream->eos = FALSE;
1338
WakeConditionVariable(&stream->update_queued_cv);
1339
1340
LeaveCriticalSection(&stream->cs);
1341
1342
/* Calling IMediaStreamFilter::Flush() inside the critical section would
1343
* invert the locking order, so we must leave it first to avoid the
1344
* application thread deadlocking on the filter's critical section. */
1345
IMediaStreamFilter_Flush(stream->filter, cancel_eos);
1346
1347
return S_OK;
1348
}
1349
1350
static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface)
1351
{
1352
struct ddraw_stream *stream = impl_from_IPin(iface);
1353
1354
TRACE("stream %p.\n", stream);
1355
1356
EnterCriticalSection(&stream->cs);
1357
1358
stream->flushing = FALSE;
1359
1360
LeaveCriticalSection(&stream->cs);
1361
1362
return S_OK;
1363
}
1364
1365
static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1366
{
1367
struct ddraw_stream *stream = impl_from_IPin(iface);
1368
1369
TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1370
stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1371
1372
EnterCriticalSection(&stream->cs);
1373
1374
stream->segment_start = start;
1375
1376
LeaveCriticalSection(&stream->cs);
1377
1378
return S_OK;
1379
}
1380
1381
static const IPinVtbl ddraw_sink_vtbl =
1382
{
1383
ddraw_sink_QueryInterface,
1384
ddraw_sink_AddRef,
1385
ddraw_sink_Release,
1386
ddraw_sink_Connect,
1387
ddraw_sink_ReceiveConnection,
1388
ddraw_sink_Disconnect,
1389
ddraw_sink_ConnectedTo,
1390
ddraw_sink_ConnectionMediaType,
1391
ddraw_sink_QueryPinInfo,
1392
ddraw_sink_QueryDirection,
1393
ddraw_sink_QueryId,
1394
ddraw_sink_QueryAccept,
1395
ddraw_sink_EnumMediaTypes,
1396
ddraw_sink_QueryInternalConnections,
1397
ddraw_sink_EndOfStream,
1398
ddraw_sink_BeginFlush,
1399
ddraw_sink_EndFlush,
1400
ddraw_sink_NewSegment,
1401
};
1402
1403
static struct ddraw_stream *impl_from_IMemAllocator(IMemAllocator *iface)
1404
{
1405
return CONTAINING_RECORD(iface, struct ddraw_stream, IMemAllocator_iface);
1406
}
1407
1408
static HRESULT WINAPI ddraw_mem_allocator_QueryInterface(IMemAllocator *iface, REFIID iid, void **out)
1409
{
1410
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1411
return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1412
}
1413
1414
static ULONG WINAPI ddraw_mem_allocator_AddRef(IMemAllocator *iface)
1415
{
1416
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1417
return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1418
}
1419
1420
static ULONG WINAPI ddraw_mem_allocator_Release(IMemAllocator *iface)
1421
{
1422
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1423
return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1424
}
1425
1426
static HRESULT WINAPI ddraw_mem_allocator_SetProperties(IMemAllocator *iface,
1427
ALLOCATOR_PROPERTIES *req_props, ALLOCATOR_PROPERTIES *ret_props)
1428
{
1429
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1430
1431
TRACE("stream %p, req_props %p, ret_props %p.\n", stream, req_props, ret_props);
1432
1433
TRACE("Requested %ld buffers, size %ld, prefix %ld, alignment %ld.\n",
1434
req_props->cBuffers, req_props->cbBuffer, req_props->cbPrefix, req_props->cbAlign);
1435
1436
if (!req_props->cbAlign)
1437
return VFW_E_BADALIGN;
1438
1439
EnterCriticalSection(&stream->cs);
1440
1441
if (stream->committed)
1442
{
1443
LeaveCriticalSection(&stream->cs);
1444
return VFW_E_ALREADY_COMMITTED;
1445
}
1446
1447
stream->buffer_count = max(req_props->cBuffers, 1);
1448
1449
ret_props->cBuffers = stream->buffer_count;
1450
ret_props->cbBuffer = stream->format.width * stream->format.height * stream->format.pf.dwRGBBitCount / 8;
1451
ret_props->cbAlign = 1;
1452
ret_props->cbPrefix = 0;
1453
1454
LeaveCriticalSection(&stream->cs);
1455
1456
return S_OK;
1457
}
1458
1459
static HRESULT WINAPI ddraw_mem_allocator_GetProperties(IMemAllocator *iface, ALLOCATOR_PROPERTIES *props)
1460
{
1461
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1462
1463
TRACE("stream %p, props %p.\n", stream, props);
1464
1465
EnterCriticalSection(&stream->cs);
1466
props->cBuffers = stream->buffer_count;
1467
props->cbBuffer = stream->format.width * stream->format.height * stream->format.pf.dwRGBBitCount / 8;
1468
props->cbAlign = 1;
1469
props->cbPrefix = 0;
1470
LeaveCriticalSection(&stream->cs);
1471
1472
return S_OK;
1473
}
1474
1475
static HRESULT WINAPI ddraw_mem_allocator_Commit(IMemAllocator *iface)
1476
{
1477
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1478
1479
TRACE("stream %p.\n", stream);
1480
1481
EnterCriticalSection(&stream->cs);
1482
stream->committed = true;
1483
/* We have nothing to actually commit; all of our samples are created by
1484
* CreateSample(). */
1485
LeaveCriticalSection(&stream->cs);
1486
1487
return S_OK;
1488
}
1489
1490
static HRESULT WINAPI ddraw_mem_allocator_Decommit(IMemAllocator *iface)
1491
{
1492
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1493
1494
TRACE("stream %p.\n", stream);
1495
1496
EnterCriticalSection(&stream->cs);
1497
stream->committed = false;
1498
WakeAllConditionVariable(&stream->allocator_cv);
1499
/* We have nothing to actually decommit; all of our samples are created by
1500
* CreateSample(). */
1501
LeaveCriticalSection(&stream->cs);
1502
1503
return S_OK;
1504
}
1505
1506
static struct ddraw_sample *get_pending_sample(struct ddraw_stream *stream)
1507
{
1508
struct ddraw_sample *sample;
1509
1510
LIST_FOR_EACH_ENTRY(sample, &stream->update_queue, struct ddraw_sample, entry)
1511
{
1512
if (!sample->media_sample_refcount)
1513
return sample;
1514
}
1515
1516
return NULL;
1517
}
1518
1519
static HRESULT WINAPI ddraw_mem_allocator_GetBuffer(IMemAllocator *iface,
1520
IMediaSample **ret_sample, REFERENCE_TIME *start, REFERENCE_TIME *end, DWORD flags)
1521
{
1522
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1523
struct ddraw_sample *sample;
1524
HRESULT hr;
1525
1526
TRACE("stream %p, ret_sample %p, start %p, end %p, flags %#lx.\n", stream, ret_sample, start, end, flags);
1527
1528
EnterCriticalSection(&stream->cs);
1529
1530
while (stream->committed && !(sample = get_pending_sample(stream)))
1531
SleepConditionVariableCS(&stream->allocator_cv, &stream->cs, INFINITE);
1532
1533
if (!stream->committed)
1534
{
1535
LeaveCriticalSection(&stream->cs);
1536
return VFW_E_NOT_COMMITTED;
1537
}
1538
1539
sample->surface_desc.dwSize = sizeof(DDSURFACEDESC);
1540
if ((FAILED(hr = IDirectDrawSurface_Lock(sample->surface,
1541
&sample->rect, &sample->surface_desc, DDLOCK_WAIT, NULL))))
1542
{
1543
LeaveCriticalSection(&stream->cs);
1544
return hr;
1545
}
1546
1547
/* Only these fields are reset. */
1548
sample->sync_point = true;
1549
sample->discontinuity = false;
1550
1551
sample->media_sample_refcount = 1;
1552
1553
LeaveCriticalSection(&stream->cs);
1554
1555
*ret_sample = &sample->IMediaSample_iface;
1556
return S_OK;
1557
}
1558
1559
static HRESULT WINAPI ddraw_mem_allocator_ReleaseBuffer(IMemAllocator *iface, IMediaSample *sample)
1560
{
1561
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1562
1563
FIXME("stream %p, sample %p, stub!\n", stream, sample);
1564
1565
return E_NOTIMPL;
1566
}
1567
1568
static const IMemAllocatorVtbl ddraw_mem_allocator_vtbl =
1569
{
1570
ddraw_mem_allocator_QueryInterface,
1571
ddraw_mem_allocator_AddRef,
1572
ddraw_mem_allocator_Release,
1573
ddraw_mem_allocator_SetProperties,
1574
ddraw_mem_allocator_GetProperties,
1575
ddraw_mem_allocator_Commit,
1576
ddraw_mem_allocator_Decommit,
1577
ddraw_mem_allocator_GetBuffer,
1578
ddraw_mem_allocator_ReleaseBuffer,
1579
};
1580
1581
static inline struct ddraw_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1582
{
1583
return CONTAINING_RECORD(iface, struct ddraw_stream, IMemInputPin_iface);
1584
}
1585
1586
static HRESULT WINAPI ddraw_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1587
{
1588
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1589
return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1590
}
1591
1592
static ULONG WINAPI ddraw_meminput_AddRef(IMemInputPin *iface)
1593
{
1594
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1595
return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1596
}
1597
1598
static ULONG WINAPI ddraw_meminput_Release(IMemInputPin *iface)
1599
{
1600
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1601
return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1602
}
1603
1604
static HRESULT WINAPI ddraw_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1605
{
1606
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1607
1608
TRACE("stream %p, allocator %p.\n", stream, allocator);
1609
1610
IMemAllocator_AddRef(*allocator = &stream->IMemAllocator_iface);
1611
return S_OK;
1612
}
1613
1614
static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1615
{
1616
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1617
1618
TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1619
1620
if (!allocator)
1621
return E_POINTER;
1622
1623
stream->using_private_allocator = (allocator == &stream->IMemAllocator_iface);
1624
1625
return S_OK;
1626
}
1627
1628
static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1629
{
1630
TRACE("iface %p, props %p.\n", iface, props);
1631
return E_NOTIMPL;
1632
}
1633
1634
static struct ddraw_sample *get_update_sample(struct ddraw_stream *stream, IMediaSample *buffer)
1635
{
1636
const BITMAPINFOHEADER *bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader;
1637
STREAM_TIME start_stream_time, end_stream_time;
1638
REFERENCE_TIME start_time = 0, end_time = 0;
1639
struct ddraw_sample *sample;
1640
BYTE *top_down_pointer;
1641
int top_down_stride;
1642
BYTE *pointer;
1643
int stride;
1644
1645
/* Is it any of the samples we gave out from GetBuffer()? */
1646
LIST_FOR_EACH_ENTRY(sample, &stream->update_queue, struct ddraw_sample, entry)
1647
{
1648
if (buffer == &sample->IMediaSample_iface)
1649
{
1650
sample->update_hr = S_OK;
1651
return sample;
1652
}
1653
}
1654
1655
/* Find an unused sample and blit to it. */
1656
1657
IMediaSample_GetPointer(buffer, &pointer);
1658
IMediaSample_GetTime(buffer, &start_time, &end_time);
1659
1660
start_stream_time = start_time + stream->segment_start;
1661
end_stream_time = end_time + stream->segment_start;
1662
1663
stride = ((bitmap_info->biWidth * bitmap_info->biBitCount + 31) & ~31) / 8;
1664
if (bitmap_info->biHeight < 0)
1665
{
1666
top_down_stride = stride;
1667
top_down_pointer = pointer;
1668
}
1669
else
1670
{
1671
top_down_stride = -stride;
1672
top_down_pointer = pointer + stride * (bitmap_info->biHeight - 1);
1673
}
1674
1675
if ((sample = get_pending_sample(stream)))
1676
{
1677
sample->update_hr = copy_sample(sample, top_down_stride, top_down_pointer,
1678
start_stream_time, end_stream_time);
1679
return sample;
1680
}
1681
1682
/* We don't have a sample yet. */
1683
return NULL;
1684
}
1685
1686
static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *buffer)
1687
{
1688
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1689
REFERENCE_TIME start_time = 0, end_time = 0;
1690
IMediaStreamFilter *filter;
1691
STREAM_TIME current_time;
1692
1693
TRACE("stream %p, buffer %p.\n", stream, buffer);
1694
1695
IMediaSample_GetTime(buffer, &start_time, &end_time);
1696
1697
EnterCriticalSection(&stream->cs);
1698
1699
if (stream->state == State_Stopped)
1700
{
1701
LeaveCriticalSection(&stream->cs);
1702
return S_OK;
1703
}
1704
if (stream->flushing)
1705
{
1706
LeaveCriticalSection(&stream->cs);
1707
return S_FALSE;
1708
}
1709
1710
filter = stream->filter;
1711
1712
LeaveCriticalSection(&stream->cs);
1713
if (S_OK == IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time)
1714
&& start_time >= current_time + 10000)
1715
IMediaStreamFilter_WaitUntil(filter, start_time);
1716
EnterCriticalSection(&stream->cs);
1717
1718
for (;;)
1719
{
1720
struct ddraw_sample *sample;
1721
IQualityControl *qc;
1722
1723
if (stream->state == State_Stopped)
1724
{
1725
LeaveCriticalSection(&stream->cs);
1726
return S_OK;
1727
}
1728
if (stream->flushing)
1729
{
1730
LeaveCriticalSection(&stream->cs);
1731
return S_FALSE;
1732
}
1733
1734
if ((sample = get_update_sample(stream, buffer)))
1735
{
1736
if (sample->continuous_update && SUCCEEDED(sample->update_hr))
1737
{
1738
list_remove(&sample->entry);
1739
list_add_tail(&sample->parent->update_queue, &sample->entry);
1740
}
1741
else
1742
{
1743
remove_queued_update(sample);
1744
}
1745
1746
if (IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time) == S_OK
1747
&& SUCCEEDED(IPin_QueryInterface(stream->peer, &IID_IQualityControl, (void **)&qc)))
1748
{
1749
Quality q;
1750
q.Type = Famine;
1751
q.Proportion = 1000;
1752
q.Late = current_time - start_time;
1753
q.TimeStamp = start_time;
1754
IQualityControl_Notify(qc, (IBaseFilter *)stream->filter, q);
1755
IQualityControl_Release(qc);
1756
}
1757
1758
LeaveCriticalSection(&stream->cs);
1759
return S_OK;
1760
}
1761
1762
SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE);
1763
}
1764
}
1765
1766
static HRESULT WINAPI ddraw_meminput_ReceiveMultiple(IMemInputPin *iface,
1767
IMediaSample **samples, LONG count, LONG *processed)
1768
{
1769
FIXME("iface %p, samples %p, count %lu, processed %p, stub!\n", iface, samples, count, processed);
1770
return E_NOTIMPL;
1771
}
1772
1773
static HRESULT WINAPI ddraw_meminput_ReceiveCanBlock(IMemInputPin *iface)
1774
{
1775
TRACE("iface %p.\n", iface);
1776
return S_OK;
1777
}
1778
1779
static const IMemInputPinVtbl ddraw_meminput_vtbl =
1780
{
1781
ddraw_meminput_QueryInterface,
1782
ddraw_meminput_AddRef,
1783
ddraw_meminput_Release,
1784
ddraw_meminput_GetAllocator,
1785
ddraw_meminput_NotifyAllocator,
1786
ddraw_meminput_GetAllocatorRequirements,
1787
ddraw_meminput_Receive,
1788
ddraw_meminput_ReceiveMultiple,
1789
ddraw_meminput_ReceiveCanBlock,
1790
};
1791
1792
HRESULT ddraw_stream_create(IUnknown *outer, void **out)
1793
{
1794
struct ddraw_stream *object;
1795
1796
if (outer)
1797
return CLASS_E_NOAGGREGATION;
1798
1799
if (!(object = calloc(1, sizeof(*object))))
1800
return E_OUTOFMEMORY;
1801
1802
object->IAMMediaStream_iface.lpVtbl = &ddraw_IAMMediaStream_vtbl;
1803
object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl;
1804
object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl;
1805
object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl;
1806
object->IPin_iface.lpVtbl = &ddraw_sink_vtbl;
1807
object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl;
1808
object->ref = 1;
1809
1810
object->format.width = 100;
1811
object->format.height = 100;
1812
1813
object->using_private_allocator = TRUE;
1814
InitializeConditionVariable(&object->allocator_cv);
1815
object->buffer_count = 1;
1816
1817
InitializeCriticalSection(&object->cs);
1818
InitializeConditionVariable(&object->update_queued_cv);
1819
list_init(&object->update_queue);
1820
1821
TRACE("Created ddraw stream %p.\n", object);
1822
1823
*out = &object->IAMMediaStream_iface;
1824
1825
return S_OK;
1826
}
1827
1828
static inline struct ddraw_sample *impl_from_IDirectDrawStreamSample(IDirectDrawStreamSample *iface)
1829
{
1830
return CONTAINING_RECORD(iface, struct ddraw_sample, IDirectDrawStreamSample_iface);
1831
}
1832
1833
/*** IUnknown methods ***/
1834
static HRESULT WINAPI ddraw_sample_QueryInterface(IDirectDrawStreamSample *iface,
1835
REFIID riid, void **ret_iface)
1836
{
1837
TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
1838
1839
if (IsEqualGUID(riid, &IID_IUnknown) ||
1840
IsEqualGUID(riid, &IID_IStreamSample) ||
1841
IsEqualGUID(riid, &IID_IDirectDrawStreamSample))
1842
{
1843
IDirectDrawStreamSample_AddRef(iface);
1844
*ret_iface = iface;
1845
return S_OK;
1846
}
1847
1848
*ret_iface = NULL;
1849
1850
ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
1851
return E_NOINTERFACE;
1852
}
1853
1854
static ULONG WINAPI ddraw_sample_AddRef(IDirectDrawStreamSample *iface)
1855
{
1856
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1857
ULONG ref = InterlockedIncrement(&sample->ref);
1858
1859
TRACE("(%p)->(): new ref = %lu\n", iface, ref);
1860
1861
return ref;
1862
}
1863
1864
static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
1865
{
1866
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1867
ULONG ref = InterlockedDecrement(&sample->ref);
1868
1869
TRACE("(%p)->(): new ref = %lu\n", iface, ref);
1870
1871
if (!ref)
1872
{
1873
EnterCriticalSection(&sample->parent->cs);
1874
1875
if (sample->pending)
1876
remove_queued_update(sample);
1877
1878
while (sample->media_sample_refcount)
1879
SleepConditionVariableCS(&sample->parent->allocator_cv, &sample->parent->cs, INFINITE);
1880
1881
--sample->parent->sample_refs;
1882
LeaveCriticalSection(&sample->parent->cs);
1883
1884
if (sample->mmstream)
1885
IMultiMediaStream_Release(sample->mmstream);
1886
IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
1887
1888
if (sample->surface)
1889
IDirectDrawSurface_Release(sample->surface);
1890
free(sample);
1891
}
1892
1893
return ref;
1894
}
1895
1896
/*** IStreamSample methods ***/
1897
static HRESULT WINAPI ddraw_sample_GetMediaStream(IDirectDrawStreamSample *iface, IMediaStream **media_stream)
1898
{
1899
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1900
1901
TRACE("sample %p, media_stream %p.\n", sample, media_stream);
1902
1903
if (!media_stream)
1904
return E_POINTER;
1905
1906
IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
1907
*media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
1908
1909
return S_OK;
1910
}
1911
1912
static HRESULT WINAPI ddraw_sample_GetSampleTimes(IDirectDrawStreamSample *iface, STREAM_TIME *start_time,
1913
STREAM_TIME *end_time, STREAM_TIME *current_time)
1914
{
1915
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1916
1917
TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
1918
1919
if (current_time)
1920
IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
1921
1922
if (start_time)
1923
*start_time = sample->start_time;
1924
if (end_time)
1925
*end_time = sample->end_time;
1926
1927
return S_OK;
1928
}
1929
1930
static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface, const STREAM_TIME *start_time,
1931
const STREAM_TIME *end_time)
1932
{
1933
FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
1934
1935
return E_NOTIMPL;
1936
}
1937
1938
static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
1939
DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
1940
{
1941
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1942
1943
TRACE("sample %p, flags %#lx, event %p, apc_func %p, apc_data %#lx.\n",
1944
sample, flags, event, apc_func, apc_data);
1945
1946
if (event && apc_func)
1947
return E_INVALIDARG;
1948
1949
if (apc_func)
1950
{
1951
FIXME("APC support is not implemented!\n");
1952
return E_NOTIMPL;
1953
}
1954
1955
EnterCriticalSection(&sample->parent->cs);
1956
1957
if (sample->parent->state != State_Running)
1958
{
1959
LeaveCriticalSection(&sample->parent->cs);
1960
return MS_E_NOTRUNNING;
1961
}
1962
if (!sample->parent->peer || sample->parent->eos)
1963
{
1964
sample->update_hr = MS_S_ENDOFSTREAM;
1965
LeaveCriticalSection(&sample->parent->cs);
1966
return MS_S_ENDOFSTREAM;
1967
}
1968
if (sample->pending || sample->media_sample_refcount)
1969
{
1970
LeaveCriticalSection(&sample->parent->cs);
1971
return MS_E_BUSY;
1972
}
1973
1974
sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
1975
1976
sample->update_hr = MS_S_NOUPDATE;
1977
sample->pending = true;
1978
sample->external_event = event;
1979
list_add_tail(&sample->parent->update_queue, &sample->entry);
1980
WakeConditionVariable(&sample->parent->update_queued_cv);
1981
WakeConditionVariable(&sample->parent->allocator_cv);
1982
1983
if ((flags & SSUPDATE_ASYNC) || event)
1984
{
1985
LeaveCriticalSection(&sample->parent->cs);
1986
return MS_S_PENDING;
1987
}
1988
1989
while (sample->pending || sample->media_sample_refcount)
1990
SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
1991
1992
LeaveCriticalSection(&sample->parent->cs);
1993
1994
return sample->update_hr;
1995
}
1996
1997
static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds)
1998
{
1999
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
2000
HRESULT hr;
2001
2002
TRACE("sample %p, flags %#lx, milliseconds %lu.\n", sample, flags, milliseconds);
2003
2004
EnterCriticalSection(&sample->parent->cs);
2005
2006
if (sample->pending || sample->media_sample_refcount)
2007
{
2008
if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
2009
{
2010
if (!sample->media_sample_refcount)
2011
remove_queued_update(sample);
2012
}
2013
else if (flags & COMPSTAT_WAIT)
2014
{
2015
DWORD start_time = GetTickCount();
2016
DWORD elapsed = 0;
2017
sample->continuous_update = FALSE;
2018
while ((sample->pending || sample->media_sample_refcount) && elapsed < milliseconds)
2019
{
2020
DWORD sleep_time = milliseconds - elapsed;
2021
if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
2022
break;
2023
elapsed = GetTickCount() - start_time;
2024
}
2025
}
2026
}
2027
2028
if (sample->pending || sample->media_sample_refcount)
2029
hr = MS_S_PENDING;
2030
else
2031
hr = sample->update_hr;
2032
2033
LeaveCriticalSection(&sample->parent->cs);
2034
2035
return hr;
2036
}
2037
2038
/*** IDirectDrawStreamSample methods ***/
2039
static HRESULT WINAPI ddraw_sample_GetSurface(IDirectDrawStreamSample *iface, IDirectDrawSurface **ddraw_surface,
2040
RECT *rect)
2041
{
2042
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
2043
2044
TRACE("(%p)->(%p,%p)\n", iface, ddraw_surface, rect);
2045
2046
if (ddraw_surface)
2047
{
2048
*ddraw_surface = sample->surface;
2049
if (*ddraw_surface)
2050
IDirectDrawSurface_AddRef(*ddraw_surface);
2051
}
2052
2053
if (rect)
2054
*rect = sample->rect;
2055
2056
return S_OK;
2057
}
2058
2059
static HRESULT WINAPI ddraw_sample_SetRect(IDirectDrawStreamSample *iface, const RECT *rect)
2060
{
2061
FIXME("(%p)->(%p): stub\n", iface, rect);
2062
2063
return E_NOTIMPL;
2064
}
2065
2066
static const struct IDirectDrawStreamSampleVtbl DirectDrawStreamSample_Vtbl =
2067
{
2068
/*** IUnknown methods ***/
2069
ddraw_sample_QueryInterface,
2070
ddraw_sample_AddRef,
2071
ddraw_sample_Release,
2072
/*** IStreamSample methods ***/
2073
ddraw_sample_GetMediaStream,
2074
ddraw_sample_GetSampleTimes,
2075
ddraw_sample_SetSampleTimes,
2076
ddraw_sample_Update,
2077
ddraw_sample_CompletionStatus,
2078
/*** IDirectDrawStreamSample methods ***/
2079
ddraw_sample_GetSurface,
2080
ddraw_sample_SetRect
2081
};
2082
2083
static struct ddraw_sample *impl_from_IMediaSample(IMediaSample *iface)
2084
{
2085
return CONTAINING_RECORD(iface, struct ddraw_sample, IMediaSample_iface);
2086
}
2087
2088
static HRESULT WINAPI media_sample_QueryInterface(IMediaSample *iface, REFIID iid, void **out)
2089
{
2090
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2091
2092
TRACE("sample %p, iid %s, out %p.\n", sample, debugstr_guid(iid), out);
2093
2094
if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IMediaSample))
2095
{
2096
IMediaSample_AddRef(iface);
2097
*out = iface;
2098
return S_OK;
2099
}
2100
2101
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2102
*out = NULL;
2103
return E_NOINTERFACE;
2104
}
2105
2106
static ULONG WINAPI media_sample_AddRef(IMediaSample *iface)
2107
{
2108
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2109
ULONG refcount;
2110
2111
EnterCriticalSection(&sample->parent->cs);
2112
refcount = ++sample->media_sample_refcount;
2113
LeaveCriticalSection(&sample->parent->cs);
2114
2115
TRACE("%p increasing refcount to %lu.\n", sample, refcount);
2116
2117
return refcount;
2118
}
2119
2120
static ULONG WINAPI media_sample_Release(IMediaSample *iface)
2121
{
2122
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2123
ULONG refcount;
2124
2125
EnterCriticalSection(&sample->parent->cs);
2126
2127
/* This is not InterlockedDecrement(), because it's used in GetBuffer()
2128
* among other functions and therefore needs to be protected by the CS
2129
* anyway. */
2130
refcount = --sample->media_sample_refcount;
2131
2132
TRACE("%p decreasing refcount to %lu.\n", sample, refcount);
2133
2134
if (!refcount)
2135
{
2136
IDirectDrawSurface_Unlock(sample->surface, NULL);
2137
2138
WakeConditionVariable(&sample->update_cv);
2139
2140
/* This sample is not released back to the pool if it's no longer
2141
* pending an update.
2142
*
2143
* Use WakeAll, even though we're only releasing one sample, because we
2144
* also potentially need to wake up a thread stuck in
2145
* IDirectDrawStreamSample::Release().
2146
* This is arguably wasteful, but in practice we're unlikely to have
2147
* more than one thread in GetBuffer() at a time anyway. */
2148
if (sample->pending)
2149
WakeAllConditionVariable(&sample->parent->allocator_cv);
2150
}
2151
2152
LeaveCriticalSection(&sample->parent->cs);
2153
return refcount;
2154
}
2155
2156
static unsigned int get_sample_size(struct ddraw_sample *sample)
2157
{
2158
return sample->surface_desc.lPitch * sample->surface_desc.dwHeight;
2159
}
2160
2161
static HRESULT WINAPI media_sample_GetPointer(IMediaSample *iface, BYTE **data)
2162
{
2163
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2164
2165
TRACE("sample %p, data %p.\n", sample, data);
2166
2167
*data = sample->surface_desc.lpSurface;
2168
return S_OK;
2169
}
2170
2171
static LONG WINAPI media_sample_GetSize(IMediaSample *iface)
2172
{
2173
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2174
2175
TRACE("sample %p.\n", sample);
2176
2177
return get_sample_size(sample);
2178
}
2179
2180
static HRESULT WINAPI media_sample_GetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end)
2181
{
2182
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2183
2184
TRACE("sample %p, start %p, end %p.\n", sample, start, end);
2185
2186
EnterCriticalSection(&sample->parent->cs);
2187
*start = sample->start_time;
2188
*end = sample->end_time;
2189
LeaveCriticalSection(&sample->parent->cs);
2190
2191
return S_OK;
2192
}
2193
2194
static HRESULT WINAPI media_sample_SetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end)
2195
{
2196
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2197
2198
TRACE("sample %p, start %p, end %p.\n", sample, start, end);
2199
2200
EnterCriticalSection(&sample->parent->cs);
2201
if (start)
2202
sample->start_time = *start;
2203
if (end)
2204
sample->end_time = *end;
2205
LeaveCriticalSection(&sample->parent->cs);
2206
2207
return S_OK;
2208
}
2209
2210
static HRESULT WINAPI media_sample_IsSyncPoint(IMediaSample *iface)
2211
{
2212
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2213
HRESULT hr;
2214
2215
TRACE("sample %p.\n", sample);
2216
2217
EnterCriticalSection(&sample->parent->cs);
2218
hr = sample->sync_point ? S_OK : S_FALSE;
2219
LeaveCriticalSection(&sample->parent->cs);
2220
2221
return hr;
2222
}
2223
2224
static HRESULT WINAPI media_sample_SetSyncPoint(IMediaSample *iface, BOOL sync_point)
2225
{
2226
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2227
2228
TRACE("sample %p, sync_point %d.\n", sample, sync_point);
2229
2230
EnterCriticalSection(&sample->parent->cs);
2231
sample->sync_point = sync_point;
2232
LeaveCriticalSection(&sample->parent->cs);
2233
2234
return S_OK;
2235
}
2236
2237
static HRESULT WINAPI media_sample_IsPreroll(IMediaSample *iface)
2238
{
2239
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2240
HRESULT hr;
2241
2242
TRACE("sample %p.\n", sample);
2243
2244
EnterCriticalSection(&sample->parent->cs);
2245
hr = sample->preroll ? S_OK : S_FALSE;
2246
LeaveCriticalSection(&sample->parent->cs);
2247
2248
return hr;
2249
}
2250
2251
static HRESULT WINAPI media_sample_SetPreroll(IMediaSample *iface, BOOL preroll)
2252
{
2253
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2254
2255
TRACE("sample %p, preroll %d.\n", sample, preroll);
2256
2257
EnterCriticalSection(&sample->parent->cs);
2258
sample->preroll = preroll;
2259
LeaveCriticalSection(&sample->parent->cs);
2260
2261
return S_OK;
2262
}
2263
2264
static LONG WINAPI media_sample_GetActualDataLength(IMediaSample *iface)
2265
{
2266
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2267
2268
TRACE("sample %p.\n", sample);
2269
2270
return get_sample_size(sample);
2271
}
2272
2273
static HRESULT WINAPI media_sample_SetActualDataLength(IMediaSample *iface, LONG length)
2274
{
2275
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2276
2277
TRACE("sample %p, length %ld.\n", sample, length);
2278
2279
return (length == get_sample_size(sample) ? S_OK : E_FAIL);
2280
}
2281
2282
static HRESULT WINAPI media_sample_GetMediaType(IMediaSample *iface, AM_MEDIA_TYPE **ret_mt)
2283
{
2284
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2285
2286
TRACE("sample %p, ret_mt %p.\n", sample, ret_mt);
2287
2288
if (!(*ret_mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
2289
return E_OUTOFMEMORY;
2290
set_mt_from_desc(*ret_mt, &sample->surface_desc, sample->surface_desc.lPitch);
2291
return S_OK;
2292
}
2293
2294
static HRESULT WINAPI media_sample_SetMediaType(IMediaSample *iface, AM_MEDIA_TYPE *mt)
2295
{
2296
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2297
2298
FIXME("sample %p, mt %p, stub!\n", sample, mt);
2299
strmbase_dump_media_type(mt);
2300
2301
return E_NOTIMPL;
2302
}
2303
2304
static HRESULT WINAPI media_sample_IsDiscontinuity(IMediaSample *iface)
2305
{
2306
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2307
HRESULT hr;
2308
2309
TRACE("sample %p.\n", sample);
2310
2311
EnterCriticalSection(&sample->parent->cs);
2312
hr = sample->discontinuity ? S_OK : S_FALSE;
2313
LeaveCriticalSection(&sample->parent->cs);
2314
2315
return hr;
2316
}
2317
2318
static HRESULT WINAPI media_sample_SetDiscontinuity(IMediaSample *iface, BOOL discontinuity)
2319
{
2320
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2321
2322
TRACE("sample %p, discontinuity %d.\n", sample, discontinuity);
2323
2324
EnterCriticalSection(&sample->parent->cs);
2325
sample->discontinuity = discontinuity;
2326
LeaveCriticalSection(&sample->parent->cs);
2327
2328
return S_OK;
2329
}
2330
2331
static HRESULT WINAPI media_sample_GetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end)
2332
{
2333
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2334
2335
TRACE("sample %p, start %p, end %p, not implemented.\n", sample, start, end);
2336
2337
return E_NOTIMPL;
2338
}
2339
2340
static HRESULT WINAPI media_sample_SetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end)
2341
{
2342
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2343
2344
TRACE("sample %p, start %p, end %p, not implemented.\n", sample, start, end);
2345
2346
return E_NOTIMPL;
2347
}
2348
2349
static const struct IMediaSampleVtbl media_sample_vtbl =
2350
{
2351
media_sample_QueryInterface,
2352
media_sample_AddRef,
2353
media_sample_Release,
2354
media_sample_GetPointer,
2355
media_sample_GetSize,
2356
media_sample_GetTime,
2357
media_sample_SetTime,
2358
media_sample_IsSyncPoint,
2359
media_sample_SetSyncPoint,
2360
media_sample_IsPreroll,
2361
media_sample_SetPreroll,
2362
media_sample_GetActualDataLength,
2363
media_sample_SetActualDataLength,
2364
media_sample_GetMediaType,
2365
media_sample_SetMediaType,
2366
media_sample_IsDiscontinuity,
2367
media_sample_SetDiscontinuity,
2368
media_sample_GetMediaTime,
2369
media_sample_SetMediaTime,
2370
};
2371
2372
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
2373
const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample)
2374
{
2375
struct ddraw_sample *object;
2376
DDSURFACEDESC desc;
2377
HRESULT hr;
2378
2379
TRACE("(%p)\n", ddraw_stream_sample);
2380
2381
if (surface)
2382
{
2383
desc.dwSize = sizeof(desc);
2384
if (FAILED(hr = IDirectDrawSurface_GetSurfaceDesc(surface, &desc)))
2385
return hr;
2386
2387
if (rect)
2388
{
2389
desc.dwWidth = rect->right - rect->left;
2390
desc.dwHeight = rect->bottom - rect->top;
2391
}
2392
2393
if (FAILED(hr = IDirectDrawMediaStream_SetFormat(&parent->IDirectDrawMediaStream_iface, &desc, NULL)))
2394
return hr;
2395
}
2396
2397
if (!(object = calloc(1, sizeof(*object))))
2398
return E_OUTOFMEMORY;
2399
2400
object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl;
2401
object->IMediaSample_iface.lpVtbl = &media_sample_vtbl;
2402
object->ref = 1;
2403
object->parent = parent;
2404
object->mmstream = parent->parent;
2405
InitializeConditionVariable(&object->update_cv);
2406
IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
2407
if (object->mmstream)
2408
IMultiMediaStream_AddRef(object->mmstream);
2409
++parent->sample_refs;
2410
2411
if (surface)
2412
{
2413
object->surface = surface;
2414
IDirectDrawSurface_AddRef(surface);
2415
2416
if (rect)
2417
object->rect = *rect;
2418
else
2419
SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight);
2420
}
2421
else
2422
{
2423
IDirectDraw *ddraw;
2424
2425
hr = IDirectDrawMediaStream_GetDirectDraw(&parent->IDirectDrawMediaStream_iface, &ddraw);
2426
if (FAILED(hr))
2427
{
2428
IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
2429
return hr;
2430
}
2431
2432
desc.dwSize = sizeof(desc);
2433
desc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
2434
desc.dwHeight = parent->format.height;
2435
desc.dwWidth = parent->format.width;
2436
if (parent->format.flags & DDSD_PIXELFORMAT)
2437
{
2438
desc.ddpfPixelFormat = parent->format.pf;
2439
}
2440
else
2441
{
2442
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
2443
desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
2444
desc.ddpfPixelFormat.dwRGBBitCount = 32;
2445
desc.ddpfPixelFormat.dwRBitMask = 0xff0000;
2446
desc.ddpfPixelFormat.dwGBitMask = 0x00ff00;
2447
desc.ddpfPixelFormat.dwBBitMask = 0x0000ff;
2448
desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
2449
}
2450
desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN;
2451
desc.lpSurface = NULL;
2452
2453
hr = IDirectDraw_CreateSurface(ddraw, &desc, &object->surface, NULL);
2454
IDirectDraw_Release(ddraw);
2455
if (FAILED(hr))
2456
{
2457
ERR("failed to create surface, 0x%08lx\n", hr);
2458
IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
2459
return hr;
2460
}
2461
}
2462
2463
*ddraw_stream_sample = &object->IDirectDrawStreamSample_iface;
2464
2465
return S_OK;
2466
}
2467
2468