Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/amstream/ddrawstream.c
8748 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
/* Don't pass the sample rect here; the upstream filter is expected to
1541
* deal with it. */
1542
if ((FAILED(hr = IDirectDrawSurface_Lock(sample->surface,
1543
NULL, &sample->surface_desc, DDLOCK_WAIT, NULL))))
1544
{
1545
LeaveCriticalSection(&stream->cs);
1546
return hr;
1547
}
1548
1549
/* Only these fields are reset. */
1550
sample->sync_point = true;
1551
sample->discontinuity = false;
1552
1553
sample->media_sample_refcount = 1;
1554
1555
LeaveCriticalSection(&stream->cs);
1556
1557
*ret_sample = &sample->IMediaSample_iface;
1558
return S_OK;
1559
}
1560
1561
static HRESULT WINAPI ddraw_mem_allocator_ReleaseBuffer(IMemAllocator *iface, IMediaSample *sample)
1562
{
1563
struct ddraw_stream *stream = impl_from_IMemAllocator(iface);
1564
1565
FIXME("stream %p, sample %p, stub!\n", stream, sample);
1566
1567
return E_NOTIMPL;
1568
}
1569
1570
static const IMemAllocatorVtbl ddraw_mem_allocator_vtbl =
1571
{
1572
ddraw_mem_allocator_QueryInterface,
1573
ddraw_mem_allocator_AddRef,
1574
ddraw_mem_allocator_Release,
1575
ddraw_mem_allocator_SetProperties,
1576
ddraw_mem_allocator_GetProperties,
1577
ddraw_mem_allocator_Commit,
1578
ddraw_mem_allocator_Decommit,
1579
ddraw_mem_allocator_GetBuffer,
1580
ddraw_mem_allocator_ReleaseBuffer,
1581
};
1582
1583
static inline struct ddraw_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1584
{
1585
return CONTAINING_RECORD(iface, struct ddraw_stream, IMemInputPin_iface);
1586
}
1587
1588
static HRESULT WINAPI ddraw_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1589
{
1590
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1591
return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1592
}
1593
1594
static ULONG WINAPI ddraw_meminput_AddRef(IMemInputPin *iface)
1595
{
1596
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1597
return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1598
}
1599
1600
static ULONG WINAPI ddraw_meminput_Release(IMemInputPin *iface)
1601
{
1602
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1603
return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1604
}
1605
1606
static HRESULT WINAPI ddraw_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1607
{
1608
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1609
1610
TRACE("stream %p, allocator %p.\n", stream, allocator);
1611
1612
IMemAllocator_AddRef(*allocator = &stream->IMemAllocator_iface);
1613
return S_OK;
1614
}
1615
1616
static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1617
{
1618
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1619
1620
TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1621
1622
if (!allocator)
1623
return E_POINTER;
1624
1625
stream->using_private_allocator = (allocator == &stream->IMemAllocator_iface);
1626
1627
return S_OK;
1628
}
1629
1630
static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1631
{
1632
TRACE("iface %p, props %p.\n", iface, props);
1633
return E_NOTIMPL;
1634
}
1635
1636
static struct ddraw_sample *get_update_sample(struct ddraw_stream *stream, IMediaSample *buffer)
1637
{
1638
const BITMAPINFOHEADER *bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader;
1639
STREAM_TIME start_stream_time, end_stream_time;
1640
REFERENCE_TIME start_time = 0, end_time = 0;
1641
struct ddraw_sample *sample;
1642
BYTE *top_down_pointer;
1643
int top_down_stride;
1644
BYTE *pointer;
1645
int stride;
1646
1647
/* Is it any of the samples we gave out from GetBuffer()? */
1648
LIST_FOR_EACH_ENTRY(sample, &stream->update_queue, struct ddraw_sample, entry)
1649
{
1650
if (buffer == &sample->IMediaSample_iface)
1651
{
1652
sample->update_hr = S_OK;
1653
return sample;
1654
}
1655
}
1656
1657
/* Find an unused sample and blit to it. */
1658
1659
IMediaSample_GetPointer(buffer, &pointer);
1660
IMediaSample_GetTime(buffer, &start_time, &end_time);
1661
1662
start_stream_time = start_time + stream->segment_start;
1663
end_stream_time = end_time + stream->segment_start;
1664
1665
stride = ((bitmap_info->biWidth * bitmap_info->biBitCount + 31) & ~31) / 8;
1666
if (bitmap_info->biHeight < 0)
1667
{
1668
top_down_stride = stride;
1669
top_down_pointer = pointer;
1670
}
1671
else
1672
{
1673
top_down_stride = -stride;
1674
top_down_pointer = pointer + stride * (bitmap_info->biHeight - 1);
1675
}
1676
1677
if ((sample = get_pending_sample(stream)))
1678
{
1679
sample->update_hr = copy_sample(sample, top_down_stride, top_down_pointer,
1680
start_stream_time, end_stream_time);
1681
return sample;
1682
}
1683
1684
/* We don't have a sample yet. */
1685
return NULL;
1686
}
1687
1688
static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *buffer)
1689
{
1690
struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1691
REFERENCE_TIME start_time = 0, end_time = 0;
1692
IMediaStreamFilter *filter;
1693
STREAM_TIME current_time;
1694
1695
TRACE("stream %p, buffer %p.\n", stream, buffer);
1696
1697
IMediaSample_GetTime(buffer, &start_time, &end_time);
1698
1699
EnterCriticalSection(&stream->cs);
1700
1701
if (stream->state == State_Stopped)
1702
{
1703
LeaveCriticalSection(&stream->cs);
1704
return S_OK;
1705
}
1706
if (stream->flushing)
1707
{
1708
LeaveCriticalSection(&stream->cs);
1709
return S_FALSE;
1710
}
1711
1712
filter = stream->filter;
1713
1714
LeaveCriticalSection(&stream->cs);
1715
if (S_OK == IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time)
1716
&& start_time >= current_time + 10000)
1717
IMediaStreamFilter_WaitUntil(filter, start_time);
1718
EnterCriticalSection(&stream->cs);
1719
1720
for (;;)
1721
{
1722
struct ddraw_sample *sample;
1723
IQualityControl *qc;
1724
1725
if (stream->state == State_Stopped)
1726
{
1727
LeaveCriticalSection(&stream->cs);
1728
return S_OK;
1729
}
1730
if (stream->flushing)
1731
{
1732
LeaveCriticalSection(&stream->cs);
1733
return S_FALSE;
1734
}
1735
1736
if ((sample = get_update_sample(stream, buffer)))
1737
{
1738
if (sample->continuous_update && SUCCEEDED(sample->update_hr))
1739
{
1740
list_remove(&sample->entry);
1741
list_add_tail(&sample->parent->update_queue, &sample->entry);
1742
}
1743
else
1744
{
1745
remove_queued_update(sample);
1746
}
1747
1748
if (IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time) == S_OK
1749
&& SUCCEEDED(IPin_QueryInterface(stream->peer, &IID_IQualityControl, (void **)&qc)))
1750
{
1751
Quality q;
1752
q.Type = Famine;
1753
q.Proportion = 1000;
1754
q.Late = current_time - start_time;
1755
q.TimeStamp = start_time;
1756
IQualityControl_Notify(qc, (IBaseFilter *)stream->filter, q);
1757
IQualityControl_Release(qc);
1758
}
1759
1760
LeaveCriticalSection(&stream->cs);
1761
return S_OK;
1762
}
1763
1764
SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE);
1765
}
1766
}
1767
1768
static HRESULT WINAPI ddraw_meminput_ReceiveMultiple(IMemInputPin *iface,
1769
IMediaSample **samples, LONG count, LONG *processed)
1770
{
1771
FIXME("iface %p, samples %p, count %lu, processed %p, stub!\n", iface, samples, count, processed);
1772
return E_NOTIMPL;
1773
}
1774
1775
static HRESULT WINAPI ddraw_meminput_ReceiveCanBlock(IMemInputPin *iface)
1776
{
1777
TRACE("iface %p.\n", iface);
1778
return S_OK;
1779
}
1780
1781
static const IMemInputPinVtbl ddraw_meminput_vtbl =
1782
{
1783
ddraw_meminput_QueryInterface,
1784
ddraw_meminput_AddRef,
1785
ddraw_meminput_Release,
1786
ddraw_meminput_GetAllocator,
1787
ddraw_meminput_NotifyAllocator,
1788
ddraw_meminput_GetAllocatorRequirements,
1789
ddraw_meminput_Receive,
1790
ddraw_meminput_ReceiveMultiple,
1791
ddraw_meminput_ReceiveCanBlock,
1792
};
1793
1794
HRESULT ddraw_stream_create(IUnknown *outer, void **out)
1795
{
1796
struct ddraw_stream *object;
1797
1798
if (outer)
1799
return CLASS_E_NOAGGREGATION;
1800
1801
if (!(object = calloc(1, sizeof(*object))))
1802
return E_OUTOFMEMORY;
1803
1804
object->IAMMediaStream_iface.lpVtbl = &ddraw_IAMMediaStream_vtbl;
1805
object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl;
1806
object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl;
1807
object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl;
1808
object->IPin_iface.lpVtbl = &ddraw_sink_vtbl;
1809
object->IMemAllocator_iface.lpVtbl = &ddraw_mem_allocator_vtbl;
1810
object->ref = 1;
1811
1812
object->format.width = 100;
1813
object->format.height = 100;
1814
1815
object->using_private_allocator = TRUE;
1816
InitializeConditionVariable(&object->allocator_cv);
1817
object->buffer_count = 1;
1818
1819
InitializeCriticalSection(&object->cs);
1820
InitializeConditionVariable(&object->update_queued_cv);
1821
list_init(&object->update_queue);
1822
1823
TRACE("Created ddraw stream %p.\n", object);
1824
1825
*out = &object->IAMMediaStream_iface;
1826
1827
return S_OK;
1828
}
1829
1830
static inline struct ddraw_sample *impl_from_IDirectDrawStreamSample(IDirectDrawStreamSample *iface)
1831
{
1832
return CONTAINING_RECORD(iface, struct ddraw_sample, IDirectDrawStreamSample_iface);
1833
}
1834
1835
/*** IUnknown methods ***/
1836
static HRESULT WINAPI ddraw_sample_QueryInterface(IDirectDrawStreamSample *iface,
1837
REFIID riid, void **ret_iface)
1838
{
1839
TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
1840
1841
if (IsEqualGUID(riid, &IID_IUnknown) ||
1842
IsEqualGUID(riid, &IID_IStreamSample) ||
1843
IsEqualGUID(riid, &IID_IDirectDrawStreamSample))
1844
{
1845
IDirectDrawStreamSample_AddRef(iface);
1846
*ret_iface = iface;
1847
return S_OK;
1848
}
1849
1850
*ret_iface = NULL;
1851
1852
ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
1853
return E_NOINTERFACE;
1854
}
1855
1856
static ULONG WINAPI ddraw_sample_AddRef(IDirectDrawStreamSample *iface)
1857
{
1858
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1859
ULONG ref = InterlockedIncrement(&sample->ref);
1860
1861
TRACE("(%p)->(): new ref = %lu\n", iface, ref);
1862
1863
return ref;
1864
}
1865
1866
static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
1867
{
1868
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1869
ULONG ref = InterlockedDecrement(&sample->ref);
1870
1871
TRACE("(%p)->(): new ref = %lu\n", iface, ref);
1872
1873
if (!ref)
1874
{
1875
EnterCriticalSection(&sample->parent->cs);
1876
1877
if (sample->pending)
1878
remove_queued_update(sample);
1879
1880
while (sample->media_sample_refcount)
1881
SleepConditionVariableCS(&sample->parent->allocator_cv, &sample->parent->cs, INFINITE);
1882
1883
--sample->parent->sample_refs;
1884
LeaveCriticalSection(&sample->parent->cs);
1885
1886
if (sample->mmstream)
1887
IMultiMediaStream_Release(sample->mmstream);
1888
IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
1889
1890
if (sample->surface)
1891
IDirectDrawSurface_Release(sample->surface);
1892
free(sample);
1893
}
1894
1895
return ref;
1896
}
1897
1898
/*** IStreamSample methods ***/
1899
static HRESULT WINAPI ddraw_sample_GetMediaStream(IDirectDrawStreamSample *iface, IMediaStream **media_stream)
1900
{
1901
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1902
1903
TRACE("sample %p, media_stream %p.\n", sample, media_stream);
1904
1905
if (!media_stream)
1906
return E_POINTER;
1907
1908
IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
1909
*media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
1910
1911
return S_OK;
1912
}
1913
1914
static HRESULT WINAPI ddraw_sample_GetSampleTimes(IDirectDrawStreamSample *iface, STREAM_TIME *start_time,
1915
STREAM_TIME *end_time, STREAM_TIME *current_time)
1916
{
1917
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1918
1919
TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
1920
1921
if (current_time)
1922
IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
1923
1924
if (start_time)
1925
*start_time = sample->start_time;
1926
if (end_time)
1927
*end_time = sample->end_time;
1928
1929
return S_OK;
1930
}
1931
1932
static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface, const STREAM_TIME *start_time,
1933
const STREAM_TIME *end_time)
1934
{
1935
FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
1936
1937
return E_NOTIMPL;
1938
}
1939
1940
static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
1941
DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
1942
{
1943
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1944
1945
TRACE("sample %p, flags %#lx, event %p, apc_func %p, apc_data %#lx.\n",
1946
sample, flags, event, apc_func, apc_data);
1947
1948
if (event && apc_func)
1949
return E_INVALIDARG;
1950
1951
if (apc_func)
1952
{
1953
FIXME("APC support is not implemented!\n");
1954
return E_NOTIMPL;
1955
}
1956
1957
EnterCriticalSection(&sample->parent->cs);
1958
1959
if (sample->parent->state != State_Running)
1960
{
1961
LeaveCriticalSection(&sample->parent->cs);
1962
return MS_E_NOTRUNNING;
1963
}
1964
if (!sample->parent->peer || sample->parent->eos)
1965
{
1966
sample->update_hr = MS_S_ENDOFSTREAM;
1967
LeaveCriticalSection(&sample->parent->cs);
1968
return MS_S_ENDOFSTREAM;
1969
}
1970
if (sample->pending || sample->media_sample_refcount)
1971
{
1972
LeaveCriticalSection(&sample->parent->cs);
1973
return MS_E_BUSY;
1974
}
1975
1976
sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
1977
1978
sample->update_hr = MS_S_NOUPDATE;
1979
sample->pending = true;
1980
sample->external_event = event;
1981
list_add_tail(&sample->parent->update_queue, &sample->entry);
1982
WakeConditionVariable(&sample->parent->update_queued_cv);
1983
WakeConditionVariable(&sample->parent->allocator_cv);
1984
1985
if ((flags & SSUPDATE_ASYNC) || event)
1986
{
1987
LeaveCriticalSection(&sample->parent->cs);
1988
return MS_S_PENDING;
1989
}
1990
1991
while (sample->pending || sample->media_sample_refcount)
1992
SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
1993
1994
LeaveCriticalSection(&sample->parent->cs);
1995
1996
return sample->update_hr;
1997
}
1998
1999
static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds)
2000
{
2001
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
2002
HRESULT hr;
2003
2004
TRACE("sample %p, flags %#lx, milliseconds %lu.\n", sample, flags, milliseconds);
2005
2006
EnterCriticalSection(&sample->parent->cs);
2007
2008
if (sample->pending || sample->media_sample_refcount)
2009
{
2010
if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
2011
{
2012
if (!sample->media_sample_refcount)
2013
remove_queued_update(sample);
2014
}
2015
else if (flags & COMPSTAT_WAIT)
2016
{
2017
DWORD start_time = GetTickCount();
2018
DWORD elapsed = 0;
2019
sample->continuous_update = FALSE;
2020
while ((sample->pending || sample->media_sample_refcount) && elapsed < milliseconds)
2021
{
2022
DWORD sleep_time = milliseconds - elapsed;
2023
if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
2024
break;
2025
elapsed = GetTickCount() - start_time;
2026
}
2027
}
2028
}
2029
2030
if (sample->pending || sample->media_sample_refcount)
2031
hr = MS_S_PENDING;
2032
else
2033
hr = sample->update_hr;
2034
2035
LeaveCriticalSection(&sample->parent->cs);
2036
2037
return hr;
2038
}
2039
2040
/*** IDirectDrawStreamSample methods ***/
2041
static HRESULT WINAPI ddraw_sample_GetSurface(IDirectDrawStreamSample *iface, IDirectDrawSurface **ddraw_surface,
2042
RECT *rect)
2043
{
2044
struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
2045
2046
TRACE("(%p)->(%p,%p)\n", iface, ddraw_surface, rect);
2047
2048
if (ddraw_surface)
2049
{
2050
*ddraw_surface = sample->surface;
2051
if (*ddraw_surface)
2052
IDirectDrawSurface_AddRef(*ddraw_surface);
2053
}
2054
2055
if (rect)
2056
*rect = sample->rect;
2057
2058
return S_OK;
2059
}
2060
2061
static HRESULT WINAPI ddraw_sample_SetRect(IDirectDrawStreamSample *iface, const RECT *rect)
2062
{
2063
FIXME("(%p)->(%p): stub\n", iface, rect);
2064
2065
return E_NOTIMPL;
2066
}
2067
2068
static const struct IDirectDrawStreamSampleVtbl DirectDrawStreamSample_Vtbl =
2069
{
2070
/*** IUnknown methods ***/
2071
ddraw_sample_QueryInterface,
2072
ddraw_sample_AddRef,
2073
ddraw_sample_Release,
2074
/*** IStreamSample methods ***/
2075
ddraw_sample_GetMediaStream,
2076
ddraw_sample_GetSampleTimes,
2077
ddraw_sample_SetSampleTimes,
2078
ddraw_sample_Update,
2079
ddraw_sample_CompletionStatus,
2080
/*** IDirectDrawStreamSample methods ***/
2081
ddraw_sample_GetSurface,
2082
ddraw_sample_SetRect
2083
};
2084
2085
static struct ddraw_sample *impl_from_IMediaSample(IMediaSample *iface)
2086
{
2087
return CONTAINING_RECORD(iface, struct ddraw_sample, IMediaSample_iface);
2088
}
2089
2090
static HRESULT WINAPI media_sample_QueryInterface(IMediaSample *iface, REFIID iid, void **out)
2091
{
2092
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2093
2094
TRACE("sample %p, iid %s, out %p.\n", sample, debugstr_guid(iid), out);
2095
2096
if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IMediaSample))
2097
{
2098
IMediaSample_AddRef(iface);
2099
*out = iface;
2100
return S_OK;
2101
}
2102
2103
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
2104
*out = NULL;
2105
return E_NOINTERFACE;
2106
}
2107
2108
static ULONG WINAPI media_sample_AddRef(IMediaSample *iface)
2109
{
2110
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2111
ULONG refcount;
2112
2113
EnterCriticalSection(&sample->parent->cs);
2114
refcount = ++sample->media_sample_refcount;
2115
LeaveCriticalSection(&sample->parent->cs);
2116
2117
TRACE("%p increasing refcount to %lu.\n", sample, refcount);
2118
2119
return refcount;
2120
}
2121
2122
static ULONG WINAPI media_sample_Release(IMediaSample *iface)
2123
{
2124
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2125
ULONG refcount;
2126
2127
EnterCriticalSection(&sample->parent->cs);
2128
2129
/* This is not InterlockedDecrement(), because it's used in GetBuffer()
2130
* among other functions and therefore needs to be protected by the CS
2131
* anyway. */
2132
refcount = --sample->media_sample_refcount;
2133
2134
TRACE("%p decreasing refcount to %lu.\n", sample, refcount);
2135
2136
if (!refcount)
2137
{
2138
IDirectDrawSurface_Unlock(sample->surface, NULL);
2139
2140
WakeConditionVariable(&sample->update_cv);
2141
2142
/* This sample is not released back to the pool if it's no longer
2143
* pending an update.
2144
*
2145
* Use WakeAll, even though we're only releasing one sample, because we
2146
* also potentially need to wake up a thread stuck in
2147
* IDirectDrawStreamSample::Release().
2148
* This is arguably wasteful, but in practice we're unlikely to have
2149
* more than one thread in GetBuffer() at a time anyway. */
2150
if (sample->pending)
2151
WakeAllConditionVariable(&sample->parent->allocator_cv);
2152
}
2153
2154
LeaveCriticalSection(&sample->parent->cs);
2155
return refcount;
2156
}
2157
2158
static unsigned int get_sample_size(struct ddraw_sample *sample)
2159
{
2160
return sample->surface_desc.lPitch * sample->surface_desc.dwHeight;
2161
}
2162
2163
static HRESULT WINAPI media_sample_GetPointer(IMediaSample *iface, BYTE **data)
2164
{
2165
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2166
2167
TRACE("sample %p, data %p.\n", sample, data);
2168
2169
*data = sample->surface_desc.lpSurface;
2170
return S_OK;
2171
}
2172
2173
static LONG WINAPI media_sample_GetSize(IMediaSample *iface)
2174
{
2175
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2176
2177
TRACE("sample %p.\n", sample);
2178
2179
return get_sample_size(sample);
2180
}
2181
2182
static HRESULT WINAPI media_sample_GetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end)
2183
{
2184
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2185
2186
TRACE("sample %p, start %p, end %p.\n", sample, start, end);
2187
2188
EnterCriticalSection(&sample->parent->cs);
2189
*start = sample->start_time;
2190
*end = sample->end_time;
2191
LeaveCriticalSection(&sample->parent->cs);
2192
2193
return S_OK;
2194
}
2195
2196
static HRESULT WINAPI media_sample_SetTime(IMediaSample *iface, REFERENCE_TIME *start, REFERENCE_TIME *end)
2197
{
2198
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2199
2200
TRACE("sample %p, start %p, end %p.\n", sample, start, end);
2201
2202
EnterCriticalSection(&sample->parent->cs);
2203
if (start)
2204
sample->start_time = *start;
2205
if (end)
2206
sample->end_time = *end;
2207
LeaveCriticalSection(&sample->parent->cs);
2208
2209
return S_OK;
2210
}
2211
2212
static HRESULT WINAPI media_sample_IsSyncPoint(IMediaSample *iface)
2213
{
2214
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2215
HRESULT hr;
2216
2217
TRACE("sample %p.\n", sample);
2218
2219
EnterCriticalSection(&sample->parent->cs);
2220
hr = sample->sync_point ? S_OK : S_FALSE;
2221
LeaveCriticalSection(&sample->parent->cs);
2222
2223
return hr;
2224
}
2225
2226
static HRESULT WINAPI media_sample_SetSyncPoint(IMediaSample *iface, BOOL sync_point)
2227
{
2228
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2229
2230
TRACE("sample %p, sync_point %d.\n", sample, sync_point);
2231
2232
EnterCriticalSection(&sample->parent->cs);
2233
sample->sync_point = sync_point;
2234
LeaveCriticalSection(&sample->parent->cs);
2235
2236
return S_OK;
2237
}
2238
2239
static HRESULT WINAPI media_sample_IsPreroll(IMediaSample *iface)
2240
{
2241
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2242
HRESULT hr;
2243
2244
TRACE("sample %p.\n", sample);
2245
2246
EnterCriticalSection(&sample->parent->cs);
2247
hr = sample->preroll ? S_OK : S_FALSE;
2248
LeaveCriticalSection(&sample->parent->cs);
2249
2250
return hr;
2251
}
2252
2253
static HRESULT WINAPI media_sample_SetPreroll(IMediaSample *iface, BOOL preroll)
2254
{
2255
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2256
2257
TRACE("sample %p, preroll %d.\n", sample, preroll);
2258
2259
EnterCriticalSection(&sample->parent->cs);
2260
sample->preroll = preroll;
2261
LeaveCriticalSection(&sample->parent->cs);
2262
2263
return S_OK;
2264
}
2265
2266
static LONG WINAPI media_sample_GetActualDataLength(IMediaSample *iface)
2267
{
2268
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2269
2270
TRACE("sample %p.\n", sample);
2271
2272
return get_sample_size(sample);
2273
}
2274
2275
static HRESULT WINAPI media_sample_SetActualDataLength(IMediaSample *iface, LONG length)
2276
{
2277
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2278
2279
TRACE("sample %p, length %ld.\n", sample, length);
2280
2281
return (length == get_sample_size(sample) ? S_OK : E_FAIL);
2282
}
2283
2284
static HRESULT WINAPI media_sample_GetMediaType(IMediaSample *iface, AM_MEDIA_TYPE **ret_mt)
2285
{
2286
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2287
VIDEOINFOHEADER *video_info;
2288
2289
TRACE("sample %p, ret_mt %p.\n", sample, ret_mt);
2290
2291
/* Note that this usually matches the media type we pass to QueryAccept(),
2292
* but not if there's a sub-rect.
2293
* That's amstream just breaking the DirectShow rules.
2294
* The type we pass to QueryAccept() just uses the size of the sub-rect for
2295
* everything. The type we return from GetMediaType() uses the size of the
2296
* surface for everything except rcSource/rcTarget. */
2297
if (!(*ret_mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
2298
return E_OUTOFMEMORY;
2299
set_mt_from_desc(*ret_mt, &sample->surface_desc, sample->surface_desc.lPitch);
2300
video_info = (VIDEOINFOHEADER *)(*ret_mt)->pbFormat;
2301
SetRect(&video_info->rcSource, 0, 0, sample->rect.right - sample->rect.left,
2302
sample->rect.bottom - sample->rect.top);
2303
video_info->rcTarget = sample->rect;
2304
return S_OK;
2305
}
2306
2307
static HRESULT WINAPI media_sample_SetMediaType(IMediaSample *iface, AM_MEDIA_TYPE *mt)
2308
{
2309
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2310
2311
FIXME("sample %p, mt %p, stub!\n", sample, mt);
2312
strmbase_dump_media_type(mt);
2313
2314
return E_NOTIMPL;
2315
}
2316
2317
static HRESULT WINAPI media_sample_IsDiscontinuity(IMediaSample *iface)
2318
{
2319
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2320
HRESULT hr;
2321
2322
TRACE("sample %p.\n", sample);
2323
2324
EnterCriticalSection(&sample->parent->cs);
2325
hr = sample->discontinuity ? S_OK : S_FALSE;
2326
LeaveCriticalSection(&sample->parent->cs);
2327
2328
return hr;
2329
}
2330
2331
static HRESULT WINAPI media_sample_SetDiscontinuity(IMediaSample *iface, BOOL discontinuity)
2332
{
2333
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2334
2335
TRACE("sample %p, discontinuity %d.\n", sample, discontinuity);
2336
2337
EnterCriticalSection(&sample->parent->cs);
2338
sample->discontinuity = discontinuity;
2339
LeaveCriticalSection(&sample->parent->cs);
2340
2341
return S_OK;
2342
}
2343
2344
static HRESULT WINAPI media_sample_GetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end)
2345
{
2346
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2347
2348
TRACE("sample %p, start %p, end %p, not implemented.\n", sample, start, end);
2349
2350
return E_NOTIMPL;
2351
}
2352
2353
static HRESULT WINAPI media_sample_SetMediaTime(IMediaSample *iface, LONGLONG *start, LONGLONG *end)
2354
{
2355
struct ddraw_sample *sample = impl_from_IMediaSample(iface);
2356
2357
TRACE("sample %p, start %p, end %p, not implemented.\n", sample, start, end);
2358
2359
return E_NOTIMPL;
2360
}
2361
2362
static const struct IMediaSampleVtbl media_sample_vtbl =
2363
{
2364
media_sample_QueryInterface,
2365
media_sample_AddRef,
2366
media_sample_Release,
2367
media_sample_GetPointer,
2368
media_sample_GetSize,
2369
media_sample_GetTime,
2370
media_sample_SetTime,
2371
media_sample_IsSyncPoint,
2372
media_sample_SetSyncPoint,
2373
media_sample_IsPreroll,
2374
media_sample_SetPreroll,
2375
media_sample_GetActualDataLength,
2376
media_sample_SetActualDataLength,
2377
media_sample_GetMediaType,
2378
media_sample_SetMediaType,
2379
media_sample_IsDiscontinuity,
2380
media_sample_SetDiscontinuity,
2381
media_sample_GetMediaTime,
2382
media_sample_SetMediaTime,
2383
};
2384
2385
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
2386
const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample)
2387
{
2388
struct ddraw_sample *object;
2389
DDSURFACEDESC desc;
2390
HRESULT hr;
2391
2392
TRACE("(%p)\n", ddraw_stream_sample);
2393
2394
if (surface)
2395
{
2396
desc.dwSize = sizeof(desc);
2397
if (FAILED(hr = IDirectDrawSurface_GetSurfaceDesc(surface, &desc)))
2398
return hr;
2399
2400
if (rect)
2401
{
2402
desc.dwWidth = rect->right - rect->left;
2403
desc.dwHeight = rect->bottom - rect->top;
2404
}
2405
2406
if (FAILED(hr = IDirectDrawMediaStream_SetFormat(&parent->IDirectDrawMediaStream_iface, &desc, NULL)))
2407
return hr;
2408
}
2409
2410
if (!(object = calloc(1, sizeof(*object))))
2411
return E_OUTOFMEMORY;
2412
2413
object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl;
2414
object->IMediaSample_iface.lpVtbl = &media_sample_vtbl;
2415
object->ref = 1;
2416
object->parent = parent;
2417
object->mmstream = parent->parent;
2418
InitializeConditionVariable(&object->update_cv);
2419
IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
2420
if (object->mmstream)
2421
IMultiMediaStream_AddRef(object->mmstream);
2422
++parent->sample_refs;
2423
2424
if (surface)
2425
{
2426
object->surface = surface;
2427
IDirectDrawSurface_AddRef(surface);
2428
2429
if (rect)
2430
object->rect = *rect;
2431
else
2432
SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight);
2433
}
2434
else
2435
{
2436
IDirectDraw *ddraw;
2437
2438
hr = IDirectDrawMediaStream_GetDirectDraw(&parent->IDirectDrawMediaStream_iface, &ddraw);
2439
if (FAILED(hr))
2440
{
2441
IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
2442
return hr;
2443
}
2444
2445
desc.dwSize = sizeof(desc);
2446
desc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
2447
desc.dwHeight = parent->format.height;
2448
desc.dwWidth = parent->format.width;
2449
if (parent->format.flags & DDSD_PIXELFORMAT)
2450
{
2451
desc.ddpfPixelFormat = parent->format.pf;
2452
}
2453
else
2454
{
2455
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
2456
desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
2457
desc.ddpfPixelFormat.dwRGBBitCount = 32;
2458
desc.ddpfPixelFormat.dwRBitMask = 0xff0000;
2459
desc.ddpfPixelFormat.dwGBitMask = 0x00ff00;
2460
desc.ddpfPixelFormat.dwBBitMask = 0x0000ff;
2461
desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
2462
}
2463
desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN;
2464
desc.lpSurface = NULL;
2465
2466
hr = IDirectDraw_CreateSurface(ddraw, &desc, &object->surface, NULL);
2467
IDirectDraw_Release(ddraw);
2468
if (FAILED(hr))
2469
{
2470
ERR("failed to create surface, 0x%08lx\n", hr);
2471
IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
2472
return hr;
2473
}
2474
2475
SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight);
2476
}
2477
2478
*ddraw_stream_sample = &object->IDirectDrawStreamSample_iface;
2479
2480
return S_OK;
2481
}
2482
2483