hid: Rewrite HidP_SetUsageValue using enum_value_caps.
[wine.git] / dlls / amstream / ddrawstream.c
blob150e622ad33e876d67f01c3a2ab241348273b116
1 /*
2 * Primary DirectDraw video stream
4 * Copyright 2005, 2008, 2012 Christian Costa
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.
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.
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
21 #define NONAMELESSUNION
22 #define COBJMACROS
23 #include "amstream_private.h"
24 #include "wine/debug.h"
25 #include "wine/strmbase.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(amstream);
29 static const WCHAR sink_id[] = L"I{A35FF56A-9FDA-11D0-8FDF-00C04FD9189D}";
31 struct format
33 DWORD flags;
34 DWORD width;
35 DWORD height;
36 DDPIXELFORMAT pf;
39 struct ddraw_stream
41 IAMMediaStream IAMMediaStream_iface;
42 IDirectDrawMediaStream IDirectDrawMediaStream_iface;
43 IMemInputPin IMemInputPin_iface;
44 IPin IPin_iface;
45 LONG ref;
46 LONG sample_refs;
48 IMultiMediaStream* parent;
49 MSPID purpose_id;
50 STREAM_TYPE stream_type;
51 IDirectDraw *ddraw;
52 CRITICAL_SECTION cs;
53 IMediaStreamFilter *filter;
54 IFilterGraph *graph;
56 IPin *peer;
57 IMemAllocator *allocator;
58 AM_MEDIA_TYPE mt;
59 struct format format;
60 FILTER_STATE state;
61 REFERENCE_TIME segment_start;
62 BOOL eos;
63 BOOL flushing;
64 CONDITION_VARIABLE update_queued_cv;
65 struct list update_queue;
68 struct ddraw_sample
70 IDirectDrawStreamSample IDirectDrawStreamSample_iface;
71 LONG ref;
72 struct ddraw_stream *parent;
73 IMultiMediaStream *mmstream;
74 IDirectDrawSurface *surface;
75 RECT rect;
76 STREAM_TIME start_time;
77 STREAM_TIME end_time;
78 BOOL continuous_update;
79 CONDITION_VARIABLE update_cv;
80 HANDLE external_event;
82 struct list entry;
83 HRESULT update_hr;
84 BOOL busy;
87 static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
88 const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample);
90 static void remove_queued_update(struct ddraw_sample *sample)
92 sample->busy = FALSE;
93 list_remove(&sample->entry);
94 WakeConditionVariable(&sample->update_cv);
95 if (sample->external_event)
96 SetEvent(sample->external_event);
99 static void flush_update_queue(struct ddraw_stream *stream, HRESULT update_hr)
101 struct list *entry;
102 while ((entry = list_head(&stream->update_queue)))
104 struct ddraw_sample *sample = LIST_ENTRY(entry, struct ddraw_sample, entry);
105 sample->update_hr = update_hr;
106 remove_queued_update(sample);
110 static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *pointer,
111 STREAM_TIME start_time, STREAM_TIME end_time)
113 DDSURFACEDESC desc;
114 DWORD row_size;
115 const BYTE *src_row;
116 BYTE *dst_row;
117 DWORD row;
118 HRESULT hr;
120 desc.dwSize = sizeof(desc);
121 hr = IDirectDrawSurface_Lock(sample->surface, &sample->rect, &desc, DDLOCK_WAIT, NULL);
122 if (FAILED(hr))
123 return hr;
125 row_size = (sample->rect.right - sample->rect.left) * desc.ddpfPixelFormat.u1.dwRGBBitCount / 8;
126 src_row = pointer;
127 dst_row = desc.lpSurface;
128 for (row = sample->rect.top; row < sample->rect.bottom; ++row)
130 memcpy(dst_row, src_row, row_size);
131 src_row += stride;
132 dst_row += desc.u1.lPitch;
135 hr = IDirectDrawSurface_Unlock(sample->surface, desc.lpSurface);
136 if (FAILED(hr))
137 return hr;
139 sample->start_time = start_time;
140 sample->end_time = end_time;
142 return S_OK;
145 static BOOL is_format_compatible(struct ddraw_stream *stream,
146 DWORD width, DWORD height, const DDPIXELFORMAT *connection_pf)
148 if (stream->format.flags & DDSD_HEIGHT)
150 if (stream->format.width != width || stream->format.height != height)
151 return FALSE;
153 if (stream->format.flags & DDSD_PIXELFORMAT)
155 if (stream->format.pf.dwFlags & DDPF_FOURCC)
156 return FALSE;
157 if (stream->format.pf.u1.dwRGBBitCount != connection_pf->u1.dwRGBBitCount)
158 return FALSE;
159 if (stream->format.pf.u1.dwRGBBitCount == 16 && stream->format.pf.u3.dwGBitMask != connection_pf->u3.dwGBitMask)
160 return FALSE;
162 return TRUE;
165 static inline struct ddraw_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
167 return CONTAINING_RECORD(iface, struct ddraw_stream, IAMMediaStream_iface);
170 /*** IUnknown methods ***/
171 static HRESULT WINAPI ddraw_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
172 REFIID riid, void **ret_iface)
174 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
176 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
178 if (IsEqualGUID(riid, &IID_IUnknown) ||
179 IsEqualGUID(riid, &IID_IMediaStream) ||
180 IsEqualGUID(riid, &IID_IAMMediaStream))
182 IAMMediaStream_AddRef(iface);
183 *ret_iface = iface;
184 return S_OK;
186 else if (IsEqualGUID(riid, &IID_IDirectDrawMediaStream))
188 IAMMediaStream_AddRef(iface);
189 *ret_iface = &This->IDirectDrawMediaStream_iface;
190 return S_OK;
192 else if (IsEqualGUID(riid, &IID_IPin))
194 IAMMediaStream_AddRef(iface);
195 *ret_iface = &This->IPin_iface;
196 return S_OK;
198 else if (IsEqualGUID(riid, &IID_IMemInputPin))
200 IAMMediaStream_AddRef(iface);
201 *ret_iface = &This->IMemInputPin_iface;
202 return S_OK;
205 ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
206 return E_NOINTERFACE;
209 static ULONG WINAPI ddraw_IAMMediaStream_AddRef(IAMMediaStream *iface)
211 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
212 ULONG ref = InterlockedIncrement(&This->ref);
214 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
216 return ref;
219 static ULONG WINAPI ddraw_IAMMediaStream_Release(IAMMediaStream *iface)
221 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
222 ULONG ref = InterlockedDecrement(&stream->ref);
224 TRACE("%p decreasing refcount to %u.\n", stream, ref);
226 if (!ref)
228 DeleteCriticalSection(&stream->cs);
229 if (stream->ddraw)
230 IDirectDraw_Release(stream->ddraw);
231 HeapFree(GetProcessHeap(), 0, stream);
234 return ref;
237 /*** IMediaStream methods ***/
238 static HRESULT WINAPI ddraw_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
239 IMultiMediaStream **mmstream)
241 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
243 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
245 if (!mmstream)
246 return E_POINTER;
248 if (stream->parent)
249 IMultiMediaStream_AddRef(stream->parent);
250 *mmstream = stream->parent;
251 return S_OK;
254 static HRESULT WINAPI ddraw_IAMMediaStream_GetInformation(IAMMediaStream *iface,
255 MSPID *purpose_id, STREAM_TYPE *type)
257 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
259 TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
261 if (purpose_id)
262 *purpose_id = This->purpose_id;
263 if (type)
264 *type = This->stream_type;
266 return S_OK;
269 static HRESULT WINAPI ddraw_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
270 IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
272 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
274 FIXME("(%p/%p)->(%p,%x) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
276 return S_FALSE;
279 static HRESULT WINAPI ddraw_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
280 DWORD flags, IStreamSample **sample)
282 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
284 FIXME("(%p/%p)->(%x,%p) stub!\n", This, iface, flags, sample);
286 return S_FALSE;
289 static HRESULT WINAPI ddraw_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
290 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
292 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
294 FIXME("(%p/%p)->(%p,%x,%p) stub!\n", This, iface, existing_sample, flags, sample);
296 return S_FALSE;
299 static HRESULT WINAPI ddraw_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
301 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
303 FIXME("(%p/%p)->(%x) stub!\n", This, iface, flags);
305 return S_FALSE;
308 /*** IAMMediaStream methods ***/
309 static HRESULT WINAPI ddraw_IAMMediaStream_Initialize(IAMMediaStream *iface, IUnknown *source_object, DWORD flags,
310 REFMSPID purpose_id, const STREAM_TYPE stream_type)
312 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
313 HRESULT hr;
315 TRACE("stream %p, source_object %p, flags %x, purpose_id %s, stream_type %u.\n", stream, source_object, flags,
316 debugstr_guid(purpose_id), stream_type);
318 if (!purpose_id)
319 return E_POINTER;
321 if (flags & AMMSF_CREATEPEER)
322 FIXME("AMMSF_CREATEPEER is not yet supported.\n");
324 stream->purpose_id = *purpose_id;
325 stream->stream_type = stream_type;
327 if (source_object
328 && FAILED(hr = IUnknown_QueryInterface(source_object, &IID_IDirectDraw, (void **)&stream->ddraw)))
329 FIXME("Stream object doesn't implement IDirectDraw interface, hr %#x.\n", hr);
331 if (!source_object)
333 if (FAILED(hr = DirectDrawCreate(NULL, &stream->ddraw, NULL)))
334 return hr;
335 IDirectDraw_SetCooperativeLevel(stream->ddraw, NULL, DDSCL_NORMAL);
338 return S_OK;
341 static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
343 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
345 TRACE("stream %p, state %u.\n", stream, state);
347 EnterCriticalSection(&stream->cs);
349 if (state == State_Stopped)
350 WakeConditionVariable(&stream->update_queued_cv);
351 if (stream->state == State_Stopped)
352 stream->eos = FALSE;
354 stream->state = state;
356 LeaveCriticalSection(&stream->cs);
358 return S_OK;
361 static HRESULT WINAPI ddraw_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface, IAMMultiMediaStream *mmstream)
363 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
365 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
367 stream->parent = (IMultiMediaStream *)mmstream;
369 return S_OK;
372 static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
374 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
376 TRACE("iface %p, filter %p.\n", iface, filter);
378 stream->filter = filter;
380 return S_OK;
383 static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
385 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
387 TRACE("stream %p, filtergraph %p.\n", stream, filtergraph);
389 stream->graph = filtergraph;
391 return S_OK;
394 static const struct IAMMediaStreamVtbl ddraw_IAMMediaStream_vtbl =
396 /*** IUnknown methods ***/
397 ddraw_IAMMediaStream_QueryInterface,
398 ddraw_IAMMediaStream_AddRef,
399 ddraw_IAMMediaStream_Release,
400 /*** IMediaStream methods ***/
401 ddraw_IAMMediaStream_GetMultiMediaStream,
402 ddraw_IAMMediaStream_GetInformation,
403 ddraw_IAMMediaStream_SetSameFormat,
404 ddraw_IAMMediaStream_AllocateSample,
405 ddraw_IAMMediaStream_CreateSharedSample,
406 ddraw_IAMMediaStream_SendEndOfStream,
407 /*** IAMMediaStream methods ***/
408 ddraw_IAMMediaStream_Initialize,
409 ddraw_IAMMediaStream_SetState,
410 ddraw_IAMMediaStream_JoinAMMultiMediaStream,
411 ddraw_IAMMediaStream_JoinFilter,
412 ddraw_IAMMediaStream_JoinFilterGraph
415 static inline struct ddraw_stream *impl_from_IDirectDrawMediaStream(IDirectDrawMediaStream *iface)
417 return CONTAINING_RECORD(iface, struct ddraw_stream, IDirectDrawMediaStream_iface);
420 /*** IUnknown methods ***/
421 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_QueryInterface(IDirectDrawMediaStream *iface,
422 REFIID riid, void **ret_iface)
424 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
425 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
426 return IAMMediaStream_QueryInterface(&This->IAMMediaStream_iface, riid, ret_iface);
429 static ULONG WINAPI ddraw_IDirectDrawMediaStream_AddRef(IDirectDrawMediaStream *iface)
431 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
432 TRACE("(%p/%p)\n", iface, This);
433 return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
436 static ULONG WINAPI ddraw_IDirectDrawMediaStream_Release(IDirectDrawMediaStream *iface)
438 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
439 TRACE("(%p/%p)\n", iface, This);
440 return IAMMediaStream_Release(&This->IAMMediaStream_iface);
443 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetMultiMediaStream(IDirectDrawMediaStream *iface,
444 IMultiMediaStream **mmstream)
446 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
447 return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
450 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetInformation(IDirectDrawMediaStream *iface,
451 MSPID *purpose_id, STREAM_TYPE *type)
453 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
454 return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
457 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetSameFormat(IDirectDrawMediaStream *iface,
458 IMediaStream *other, DWORD flags)
460 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
461 return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
464 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_AllocateSample(IDirectDrawMediaStream *iface,
465 DWORD flags, IStreamSample **sample)
467 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
468 return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
471 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSharedSample(IDirectDrawMediaStream *iface,
472 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
474 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
475 return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
478 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SendEndOfStream(IDirectDrawMediaStream *iface, DWORD flags)
480 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
481 return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
484 /*** IDirectDrawMediaStream methods ***/
485 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetFormat(IDirectDrawMediaStream *iface,
486 DDSURFACEDESC *current_format, IDirectDrawPalette **palette,
487 DDSURFACEDESC *desired_format, DWORD *flags)
489 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
491 TRACE("stream %p, current_format %p, palette %p, desired_format %p, flags %p.\n", stream, current_format, palette,
492 desired_format, flags);
494 EnterCriticalSection(&stream->cs);
496 if (!stream->peer)
498 LeaveCriticalSection(&stream->cs);
499 return MS_E_NOSTREAM;
502 if (current_format)
504 current_format->dwFlags = stream->format.flags | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
505 current_format->dwWidth = stream->format.width;
506 current_format->dwHeight = stream->format.height;
507 current_format->ddpfPixelFormat = stream->format.pf;
508 current_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
511 if (palette)
512 *palette = NULL;
514 if (desired_format)
516 desired_format->dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
517 desired_format->dwWidth = stream->format.width;
518 desired_format->dwHeight = stream->format.height;
519 desired_format->ddpfPixelFormat = stream->format.pf;
520 desired_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
523 if (flags)
524 *flags = 0;
526 LeaveCriticalSection(&stream->cs);
528 return S_OK;
531 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetFormat(IDirectDrawMediaStream *iface,
532 const DDSURFACEDESC *format, IDirectDrawPalette *palette)
534 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
535 AM_MEDIA_TYPE old_media_type;
536 struct format old_format;
537 IPin *old_peer;
538 HRESULT hr;
540 TRACE("stream %p, format %p, palette %p.\n", stream, format, palette);
542 if (palette)
543 FIXME("Setting palette is not yet supported.\n");
545 if (!format)
546 return E_POINTER;
548 if (format->dwSize != sizeof(DDSURFACEDESC))
549 return E_INVALIDARG;
551 if (format->dwFlags & DDSD_PIXELFORMAT)
553 if (format->ddpfPixelFormat.dwSize != sizeof(DDPIXELFORMAT))
554 return DDERR_INVALIDSURFACETYPE;
556 if (format->ddpfPixelFormat.dwFlags & DDPF_FOURCC)
558 if (!format->ddpfPixelFormat.u1.dwRGBBitCount)
559 return E_INVALIDARG;
561 else
563 if (format->ddpfPixelFormat.dwFlags & (DDPF_YUV | DDPF_PALETTEINDEXED1 |
564 DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXEDTO8))
565 return DDERR_INVALIDSURFACETYPE;
567 if (!(format->ddpfPixelFormat.dwFlags & DDPF_RGB))
568 return DDERR_INVALIDSURFACETYPE;
570 switch (format->ddpfPixelFormat.u1.dwRGBBitCount)
572 case 8:
573 if (!(format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8))
574 return DDERR_INVALIDSURFACETYPE;
575 break;
576 case 16:
577 if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
578 return DDERR_INVALIDSURFACETYPE;
579 if ((format->ddpfPixelFormat.u2.dwRBitMask != 0x7c00 ||
580 format->ddpfPixelFormat.u3.dwGBitMask != 0x03e0 ||
581 format->ddpfPixelFormat.u4.dwBBitMask != 0x001f) &&
582 (format->ddpfPixelFormat.u2.dwRBitMask != 0xf800 ||
583 format->ddpfPixelFormat.u3.dwGBitMask != 0x07e0 ||
584 format->ddpfPixelFormat.u4.dwBBitMask != 0x001f))
585 return DDERR_INVALIDSURFACETYPE;
586 break;
587 case 24:
588 case 32:
589 if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
590 return DDERR_INVALIDSURFACETYPE;
591 if (format->ddpfPixelFormat.u2.dwRBitMask != 0xff0000 ||
592 format->ddpfPixelFormat.u3.dwGBitMask != 0x00ff00 ||
593 format->ddpfPixelFormat.u4.dwBBitMask != 0x0000ff)
594 return DDERR_INVALIDSURFACETYPE;
595 break;
596 default:
597 return DDERR_INVALIDSURFACETYPE;
602 EnterCriticalSection(&stream->cs);
604 old_format = stream->format;
605 stream->format.flags = format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
606 if (format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT))
608 stream->format.width = format->dwWidth;
609 stream->format.height = format->dwHeight;
611 if (format->dwFlags & DDSD_PIXELFORMAT)
612 stream->format.pf = format->ddpfPixelFormat;
614 if (stream->peer && !is_format_compatible(stream, old_format.width, old_format.height, &old_format.pf))
616 hr = CopyMediaType(&old_media_type, &stream->mt);
617 if (FAILED(hr))
619 stream->format = old_format;
620 LeaveCriticalSection(&stream->cs);
621 return hr;
623 old_peer = stream->peer;
624 IPin_AddRef(old_peer);
626 IFilterGraph_Disconnect(stream->graph, stream->peer);
627 IFilterGraph_Disconnect(stream->graph, &stream->IPin_iface);
628 hr = IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, NULL);
629 if (FAILED(hr))
631 stream->format = old_format;
632 IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, &old_media_type);
633 IPin_Release(old_peer);
634 FreeMediaType(&old_media_type);
635 LeaveCriticalSection(&stream->cs);
636 return DDERR_INVALIDSURFACETYPE;
639 IPin_Release(old_peer);
640 FreeMediaType(&old_media_type);
643 LeaveCriticalSection(&stream->cs);
645 return S_OK;
648 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetDirectDraw(IDirectDrawMediaStream *iface,
649 IDirectDraw **ddraw)
651 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
653 TRACE("stream %p, ddraw %p.\n", stream, ddraw);
655 if (!ddraw)
656 return E_POINTER;
658 if (!stream->ddraw)
660 *ddraw = NULL;
661 return S_OK;
664 IDirectDraw_AddRef(stream->ddraw);
665 *ddraw = stream->ddraw;
667 return S_OK;
670 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetDirectDraw(IDirectDrawMediaStream *iface,
671 IDirectDraw *ddraw)
673 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
675 TRACE("stream %p, ddraw %p.\n", stream, ddraw);
677 EnterCriticalSection(&stream->cs);
679 if (stream->sample_refs)
681 HRESULT hr = (stream->ddraw == ddraw) ? S_OK : MS_E_SAMPLEALLOC;
682 LeaveCriticalSection(&stream->cs);
683 return hr;
686 if (stream->ddraw)
687 IDirectDraw_Release(stream->ddraw);
689 if (ddraw)
691 IDirectDraw_AddRef(ddraw);
692 stream->ddraw = ddraw;
694 else
695 stream->ddraw = NULL;
697 LeaveCriticalSection(&stream->cs);
699 return S_OK;
702 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSample(IDirectDrawMediaStream *iface,
703 IDirectDrawSurface *surface, const RECT *rect, DWORD flags,
704 IDirectDrawStreamSample **sample)
706 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
707 HRESULT hr;
709 TRACE("stream %p, surface %p, rect %s, flags %#x, sample %p.\n",
710 stream, surface, wine_dbgstr_rect(rect), flags, sample);
712 if (!surface && rect)
713 return E_INVALIDARG;
715 EnterCriticalSection(&stream->cs);
716 hr = ddrawstreamsample_create(stream, surface, rect, sample);
717 LeaveCriticalSection(&stream->cs);
719 return hr;
722 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetTimePerFrame(IDirectDrawMediaStream *iface,
723 STREAM_TIME *frame_time)
725 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
727 TRACE("stream %p, frame_time %p.\n", stream, frame_time);
729 if (!frame_time)
730 return E_POINTER;
732 EnterCriticalSection(&stream->cs);
734 if (!stream->peer)
736 LeaveCriticalSection(&stream->cs);
737 return MS_E_NOSTREAM;
740 *frame_time = ((VIDEOINFO *)stream->mt.pbFormat)->AvgTimePerFrame;
742 LeaveCriticalSection(&stream->cs);
744 return S_OK;
747 static const struct IDirectDrawMediaStreamVtbl ddraw_IDirectDrawMediaStream_Vtbl =
749 /*** IUnknown methods ***/
750 ddraw_IDirectDrawMediaStream_QueryInterface,
751 ddraw_IDirectDrawMediaStream_AddRef,
752 ddraw_IDirectDrawMediaStream_Release,
753 /*** IMediaStream methods ***/
754 ddraw_IDirectDrawMediaStream_GetMultiMediaStream,
755 ddraw_IDirectDrawMediaStream_GetInformation,
756 ddraw_IDirectDrawMediaStream_SetSameFormat,
757 ddraw_IDirectDrawMediaStream_AllocateSample,
758 ddraw_IDirectDrawMediaStream_CreateSharedSample,
759 ddraw_IDirectDrawMediaStream_SendEndOfStream,
760 /*** IDirectDrawMediaStream methods ***/
761 ddraw_IDirectDrawMediaStream_GetFormat,
762 ddraw_IDirectDrawMediaStream_SetFormat,
763 ddraw_IDirectDrawMediaStream_GetDirectDraw,
764 ddraw_IDirectDrawMediaStream_SetDirectDraw,
765 ddraw_IDirectDrawMediaStream_CreateSample,
766 ddraw_IDirectDrawMediaStream_GetTimePerFrame
769 struct enum_media_types
771 IEnumMediaTypes IEnumMediaTypes_iface;
772 LONG refcount;
773 unsigned int index;
776 static const IEnumMediaTypesVtbl enum_media_types_vtbl;
778 static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
780 return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
783 static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
785 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
787 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
789 IEnumMediaTypes_AddRef(iface);
790 *out = iface;
791 return S_OK;
794 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
795 *out = NULL;
796 return E_NOINTERFACE;
799 static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
801 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
802 ULONG refcount = InterlockedIncrement(&enum_media_types->refcount);
803 TRACE("%p increasing refcount to %u.\n", enum_media_types, refcount);
804 return refcount;
807 static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
809 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
810 ULONG refcount = InterlockedDecrement(&enum_media_types->refcount);
811 TRACE("%p decreasing refcount to %u.\n", enum_media_types, refcount);
812 if (!refcount)
813 heap_free(enum_media_types);
814 return refcount;
817 static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
819 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
821 TRACE("iface %p, count %u, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
823 if (!ret_count)
824 return E_POINTER;
826 if (count && !enum_media_types->index)
828 mts[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
829 memset(mts[0], 0, sizeof(AM_MEDIA_TYPE));
830 mts[0]->majortype = MEDIATYPE_Video;
831 mts[0]->subtype = MEDIASUBTYPE_RGB8;
832 mts[0]->bFixedSizeSamples = TRUE;
833 mts[0]->lSampleSize = 10000;
834 ++enum_media_types->index;
835 *ret_count = 1;
836 return count == 1 ? S_OK : S_FALSE;
839 *ret_count = 0;
840 return count ? S_FALSE : S_OK;
843 static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
845 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
847 TRACE("iface %p, count %u.\n", iface, count);
849 enum_media_types->index += count;
851 return S_OK;
854 static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
856 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
858 TRACE("iface %p.\n", iface);
860 enum_media_types->index = 0;
861 return S_OK;
864 static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
866 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
867 struct enum_media_types *object;
869 TRACE("iface %p, out %p.\n", iface, out);
871 if (!(object = heap_alloc(sizeof(*object))))
872 return E_OUTOFMEMORY;
874 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
875 object->refcount = 1;
876 object->index = enum_media_types->index;
878 *out = &object->IEnumMediaTypes_iface;
879 return S_OK;
882 static const IEnumMediaTypesVtbl enum_media_types_vtbl =
884 enum_media_types_QueryInterface,
885 enum_media_types_AddRef,
886 enum_media_types_Release,
887 enum_media_types_Next,
888 enum_media_types_Skip,
889 enum_media_types_Reset,
890 enum_media_types_Clone,
893 static inline struct ddraw_stream *impl_from_IPin(IPin *iface)
895 return CONTAINING_RECORD(iface, struct ddraw_stream, IPin_iface);
898 static HRESULT WINAPI ddraw_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
900 struct ddraw_stream *stream = impl_from_IPin(iface);
901 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
904 static ULONG WINAPI ddraw_sink_AddRef(IPin *iface)
906 struct ddraw_stream *stream = impl_from_IPin(iface);
907 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
910 static ULONG WINAPI ddraw_sink_Release(IPin *iface)
912 struct ddraw_stream *stream = impl_from_IPin(iface);
913 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
916 static HRESULT WINAPI ddraw_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
918 WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
919 return E_UNEXPECTED;
922 static HRESULT WINAPI ddraw_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
924 struct ddraw_stream *stream = impl_from_IPin(iface);
925 const VIDEOINFOHEADER *video_info;
926 PIN_DIRECTION dir;
927 DWORD width;
928 DWORD height;
929 DDPIXELFORMAT pf = {sizeof(DDPIXELFORMAT)};
931 TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
933 EnterCriticalSection(&stream->cs);
935 if (stream->peer)
937 LeaveCriticalSection(&stream->cs);
938 return VFW_E_ALREADY_CONNECTED;
941 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
942 || !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
944 LeaveCriticalSection(&stream->cs);
945 return VFW_E_TYPE_NOT_ACCEPTED;
948 video_info = (const VIDEOINFOHEADER *)mt->pbFormat;
950 width = video_info->bmiHeader.biWidth;
951 height = abs(video_info->bmiHeader.biHeight);
952 pf.dwFlags = DDPF_RGB;
953 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8))
955 pf.dwFlags |= DDPF_PALETTEINDEXED8;
956 pf.u1.dwRGBBitCount = 8;
958 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB555))
960 pf.u1.dwRGBBitCount = 16;
961 pf.u2.dwRBitMask = 0x7c00;
962 pf.u3.dwGBitMask = 0x03e0;
963 pf.u4.dwBBitMask = 0x001f;
965 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB565))
967 pf.u1.dwRGBBitCount = 16;
968 pf.u2.dwRBitMask = 0xf800;
969 pf.u3.dwGBitMask = 0x07e0;
970 pf.u4.dwBBitMask = 0x001f;
972 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB24))
974 pf.u1.dwRGBBitCount = 24;
975 pf.u2.dwRBitMask = 0xff0000;
976 pf.u3.dwGBitMask = 0x00ff00;
977 pf.u4.dwBBitMask = 0x0000ff;
979 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB32))
981 pf.u1.dwRGBBitCount = 32;
982 pf.u2.dwRBitMask = 0xff0000;
983 pf.u3.dwGBitMask = 0x00ff00;
984 pf.u4.dwBBitMask = 0x0000ff;
986 else
988 LeaveCriticalSection(&stream->cs);
989 return VFW_E_TYPE_NOT_ACCEPTED;
992 if (!is_format_compatible(stream, width, height, &pf))
994 LeaveCriticalSection(&stream->cs);
995 return VFW_E_TYPE_NOT_ACCEPTED;
998 IPin_QueryDirection(peer, &dir);
999 if (dir != PINDIR_OUTPUT)
1001 WARN("Rejecting connection from input pin.\n");
1002 LeaveCriticalSection(&stream->cs);
1003 return VFW_E_INVALID_DIRECTION;
1006 CopyMediaType(&stream->mt, mt);
1007 IPin_AddRef(stream->peer = peer);
1009 stream->format.width = width;
1010 stream->format.height = height;
1011 if (!(stream->format.flags & DDSD_PIXELFORMAT))
1012 stream->format.pf = pf;
1014 LeaveCriticalSection(&stream->cs);
1016 return S_OK;
1019 static HRESULT WINAPI ddraw_sink_Disconnect(IPin *iface)
1021 struct ddraw_stream *stream = impl_from_IPin(iface);
1023 TRACE("stream %p.\n", stream);
1025 EnterCriticalSection(&stream->cs);
1027 if (!stream->peer)
1029 LeaveCriticalSection(&stream->cs);
1030 return S_FALSE;
1033 IPin_Release(stream->peer);
1034 stream->peer = NULL;
1035 FreeMediaType(&stream->mt);
1036 memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
1038 LeaveCriticalSection(&stream->cs);
1040 return S_OK;
1043 static HRESULT WINAPI ddraw_sink_ConnectedTo(IPin *iface, IPin **peer)
1045 struct ddraw_stream *stream = impl_from_IPin(iface);
1046 HRESULT hr;
1048 TRACE("stream %p, peer %p.\n", stream, peer);
1050 EnterCriticalSection(&stream->cs);
1052 if (stream->peer)
1054 IPin_AddRef(*peer = stream->peer);
1055 hr = S_OK;
1057 else
1059 *peer = NULL;
1060 hr = VFW_E_NOT_CONNECTED;
1063 LeaveCriticalSection(&stream->cs);
1065 return hr;
1068 static HRESULT WINAPI ddraw_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1070 struct ddraw_stream *stream = impl_from_IPin(iface);
1071 HRESULT hr;
1073 TRACE("stream %p, mt %p.\n", stream, mt);
1075 EnterCriticalSection(&stream->cs);
1077 if (stream->peer)
1079 CopyMediaType(mt, &stream->mt);
1080 hr = S_OK;
1082 else
1084 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1085 hr = VFW_E_NOT_CONNECTED;
1088 LeaveCriticalSection(&stream->cs);
1090 return hr;
1093 static HRESULT WINAPI ddraw_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1095 struct ddraw_stream *stream = impl_from_IPin(iface);
1097 TRACE("stream %p, info %p.\n", stream, info);
1099 IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1100 info->dir = PINDIR_INPUT;
1101 wcscpy(info->achName, sink_id);
1103 return S_OK;
1106 static HRESULT WINAPI ddraw_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1108 TRACE("iface %p, dir %p.\n", iface, dir);
1109 *dir = PINDIR_INPUT;
1110 return S_OK;
1113 static HRESULT WINAPI ddraw_sink_QueryId(IPin *iface, WCHAR **id)
1115 TRACE("iface %p, id %p.\n", iface, id);
1117 if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1118 return E_OUTOFMEMORY;
1120 wcscpy(*id, sink_id);
1122 return S_OK;
1125 static HRESULT WINAPI ddraw_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1127 TRACE("iface %p, mt %p.\n", iface, mt);
1129 if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
1130 && IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8)
1131 && IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
1132 return S_OK;
1134 return VFW_E_TYPE_NOT_ACCEPTED;
1137 static HRESULT WINAPI ddraw_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1139 struct enum_media_types *object;
1141 TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1143 if (!enum_media_types)
1144 return E_POINTER;
1146 if (!(object = heap_alloc(sizeof(*object))))
1147 return E_OUTOFMEMORY;
1149 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1150 object->refcount = 1;
1151 object->index = 0;
1153 *enum_media_types = &object->IEnumMediaTypes_iface;
1154 return S_OK;
1157 static HRESULT WINAPI ddraw_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1159 TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1160 return E_NOTIMPL;
1163 static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
1165 struct ddraw_stream *stream = impl_from_IPin(iface);
1167 TRACE("stream %p.\n", stream);
1169 EnterCriticalSection(&stream->cs);
1171 if (stream->eos || stream->flushing)
1173 LeaveCriticalSection(&stream->cs);
1174 return E_FAIL;
1177 stream->eos = TRUE;
1179 flush_update_queue(stream, MS_S_ENDOFSTREAM);
1181 LeaveCriticalSection(&stream->cs);
1183 /* Calling IMediaStreamFilter::EndOfStream() inside the critical section
1184 * would invert the locking order, so we must leave it first to avoid
1185 * the streaming thread deadlocking on the filter's critical section. */
1186 IMediaStreamFilter_EndOfStream(stream->filter);
1188 return S_OK;
1191 static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface)
1193 struct ddraw_stream *stream = impl_from_IPin(iface);
1194 BOOL cancel_eos;
1196 TRACE("stream %p.\n", stream);
1198 EnterCriticalSection(&stream->cs);
1200 cancel_eos = stream->eos;
1202 stream->flushing = TRUE;
1203 stream->eos = FALSE;
1204 WakeConditionVariable(&stream->update_queued_cv);
1206 LeaveCriticalSection(&stream->cs);
1208 /* Calling IMediaStreamFilter::Flush() inside the critical section would
1209 * invert the locking order, so we must leave it first to avoid the
1210 * application thread deadlocking on the filter's critical section. */
1211 IMediaStreamFilter_Flush(stream->filter, cancel_eos);
1213 return S_OK;
1216 static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface)
1218 struct ddraw_stream *stream = impl_from_IPin(iface);
1220 TRACE("stream %p.\n", stream);
1222 EnterCriticalSection(&stream->cs);
1224 stream->flushing = FALSE;
1226 LeaveCriticalSection(&stream->cs);
1228 return S_OK;
1231 static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1233 struct ddraw_stream *stream = impl_from_IPin(iface);
1235 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1236 stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1238 EnterCriticalSection(&stream->cs);
1240 stream->segment_start = start;
1242 LeaveCriticalSection(&stream->cs);
1244 return S_OK;
1247 static const IPinVtbl ddraw_sink_vtbl =
1249 ddraw_sink_QueryInterface,
1250 ddraw_sink_AddRef,
1251 ddraw_sink_Release,
1252 ddraw_sink_Connect,
1253 ddraw_sink_ReceiveConnection,
1254 ddraw_sink_Disconnect,
1255 ddraw_sink_ConnectedTo,
1256 ddraw_sink_ConnectionMediaType,
1257 ddraw_sink_QueryPinInfo,
1258 ddraw_sink_QueryDirection,
1259 ddraw_sink_QueryId,
1260 ddraw_sink_QueryAccept,
1261 ddraw_sink_EnumMediaTypes,
1262 ddraw_sink_QueryInternalConnections,
1263 ddraw_sink_EndOfStream,
1264 ddraw_sink_BeginFlush,
1265 ddraw_sink_EndFlush,
1266 ddraw_sink_NewSegment,
1269 static inline struct ddraw_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1271 return CONTAINING_RECORD(iface, struct ddraw_stream, IMemInputPin_iface);
1274 static HRESULT WINAPI ddraw_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1276 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1277 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1280 static ULONG WINAPI ddraw_meminput_AddRef(IMemInputPin *iface)
1282 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1283 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1286 static ULONG WINAPI ddraw_meminput_Release(IMemInputPin *iface)
1288 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1289 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1292 static HRESULT WINAPI ddraw_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1294 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1296 TRACE("stream %p, allocator %p.\n", stream, allocator);
1298 if (stream->allocator)
1300 IMemAllocator_AddRef(*allocator = stream->allocator);
1301 return S_OK;
1304 *allocator = NULL;
1305 return VFW_E_NO_ALLOCATOR;
1308 static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1310 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1312 TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1314 if (!allocator)
1315 return E_POINTER;
1317 if (allocator)
1318 IMemAllocator_AddRef(allocator);
1319 if (stream->allocator)
1320 IMemAllocator_Release(stream->allocator);
1321 stream->allocator = allocator;
1323 return S_OK;
1326 static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1328 TRACE("iface %p, props %p.\n", iface, props);
1329 return E_NOTIMPL;
1332 static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1334 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1335 BITMAPINFOHEADER *bitmap_info;
1336 REFERENCE_TIME start_time = 0;
1337 REFERENCE_TIME end_time = 0;
1338 STREAM_TIME start_stream_time;
1339 STREAM_TIME end_stream_time;
1340 IMediaStreamFilter *filter;
1341 STREAM_TIME current_time;
1342 BYTE *top_down_pointer;
1343 int top_down_stride;
1344 BYTE *pointer;
1345 BOOL top_down;
1346 int stride;
1347 HRESULT hr;
1349 TRACE("stream %p, sample %p.\n", stream, sample);
1351 hr = IMediaSample_GetPointer(sample, &pointer);
1352 if (FAILED(hr))
1353 return hr;
1355 IMediaSample_GetTime(sample, &start_time, &end_time);
1357 EnterCriticalSection(&stream->cs);
1359 if (stream->state == State_Stopped)
1361 LeaveCriticalSection(&stream->cs);
1362 return S_OK;
1364 if (stream->flushing)
1366 LeaveCriticalSection(&stream->cs);
1367 return S_FALSE;
1370 bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader;
1372 stride = ((bitmap_info->biWidth * bitmap_info->biBitCount + 31) & ~31) / 8;
1373 top_down = (bitmap_info->biHeight < 0);
1375 top_down_stride = top_down ? stride : -stride;
1376 top_down_pointer = top_down ? pointer : pointer + stride * (bitmap_info->biHeight - 1);
1378 start_stream_time = start_time + stream->segment_start;
1379 end_stream_time = end_time + stream->segment_start;
1381 filter = stream->filter;
1383 LeaveCriticalSection(&stream->cs);
1384 if (S_OK == IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time)
1385 && start_time >= current_time + 10000)
1386 IMediaStreamFilter_WaitUntil(filter, start_time);
1387 EnterCriticalSection(&stream->cs);
1389 for (;;)
1391 if (stream->state == State_Stopped)
1393 LeaveCriticalSection(&stream->cs);
1394 return S_OK;
1396 if (stream->flushing)
1398 LeaveCriticalSection(&stream->cs);
1399 return S_FALSE;
1401 if (!list_empty(&stream->update_queue))
1403 struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
1405 sample->update_hr = process_update(sample, top_down_stride, top_down_pointer,
1406 start_stream_time, end_stream_time);
1408 if (sample->continuous_update && SUCCEEDED(sample->update_hr))
1410 list_remove(&sample->entry);
1411 list_add_tail(&sample->parent->update_queue, &sample->entry);
1413 else
1415 remove_queued_update(sample);
1417 LeaveCriticalSection(&stream->cs);
1418 return S_OK;
1421 SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE);
1425 static HRESULT WINAPI ddraw_meminput_ReceiveMultiple(IMemInputPin *iface,
1426 IMediaSample **samples, LONG count, LONG *processed)
1428 FIXME("iface %p, samples %p, count %u, processed %p, stub!\n", iface, samples, count, processed);
1429 return E_NOTIMPL;
1432 static HRESULT WINAPI ddraw_meminput_ReceiveCanBlock(IMemInputPin *iface)
1434 TRACE("iface %p.\n", iface);
1435 return S_OK;
1438 static const IMemInputPinVtbl ddraw_meminput_vtbl =
1440 ddraw_meminput_QueryInterface,
1441 ddraw_meminput_AddRef,
1442 ddraw_meminput_Release,
1443 ddraw_meminput_GetAllocator,
1444 ddraw_meminput_NotifyAllocator,
1445 ddraw_meminput_GetAllocatorRequirements,
1446 ddraw_meminput_Receive,
1447 ddraw_meminput_ReceiveMultiple,
1448 ddraw_meminput_ReceiveCanBlock,
1451 HRESULT ddraw_stream_create(IUnknown *outer, void **out)
1453 struct ddraw_stream *object;
1455 if (outer)
1456 return CLASS_E_NOAGGREGATION;
1458 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1459 if (!object)
1460 return E_OUTOFMEMORY;
1462 object->IAMMediaStream_iface.lpVtbl = &ddraw_IAMMediaStream_vtbl;
1463 object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl;
1464 object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl;
1465 object->IPin_iface.lpVtbl = &ddraw_sink_vtbl;
1466 object->ref = 1;
1468 object->format.width = 100;
1469 object->format.height = 100;
1471 InitializeCriticalSection(&object->cs);
1472 InitializeConditionVariable(&object->update_queued_cv);
1473 list_init(&object->update_queue);
1475 TRACE("Created ddraw stream %p.\n", object);
1477 *out = &object->IAMMediaStream_iface;
1479 return S_OK;
1482 static inline struct ddraw_sample *impl_from_IDirectDrawStreamSample(IDirectDrawStreamSample *iface)
1484 return CONTAINING_RECORD(iface, struct ddraw_sample, IDirectDrawStreamSample_iface);
1487 /*** IUnknown methods ***/
1488 static HRESULT WINAPI ddraw_sample_QueryInterface(IDirectDrawStreamSample *iface,
1489 REFIID riid, void **ret_iface)
1491 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
1493 if (IsEqualGUID(riid, &IID_IUnknown) ||
1494 IsEqualGUID(riid, &IID_IStreamSample) ||
1495 IsEqualGUID(riid, &IID_IDirectDrawStreamSample))
1497 IDirectDrawStreamSample_AddRef(iface);
1498 *ret_iface = iface;
1499 return S_OK;
1502 *ret_iface = NULL;
1504 ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
1505 return E_NOINTERFACE;
1508 static ULONG WINAPI ddraw_sample_AddRef(IDirectDrawStreamSample *iface)
1510 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1511 ULONG ref = InterlockedIncrement(&sample->ref);
1513 TRACE("(%p)->(): new ref = %u\n", iface, ref);
1515 return ref;
1518 static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
1520 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1521 ULONG ref = InterlockedDecrement(&sample->ref);
1523 TRACE("(%p)->(): new ref = %u\n", iface, ref);
1525 if (!ref)
1527 EnterCriticalSection(&sample->parent->cs);
1528 --sample->parent->sample_refs;
1529 LeaveCriticalSection(&sample->parent->cs);
1531 if (sample->mmstream)
1532 IMultiMediaStream_Release(sample->mmstream);
1533 IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
1535 if (sample->surface)
1536 IDirectDrawSurface_Release(sample->surface);
1537 HeapFree(GetProcessHeap(), 0, sample);
1540 return ref;
1543 /*** IStreamSample methods ***/
1544 static HRESULT WINAPI ddraw_sample_GetMediaStream(IDirectDrawStreamSample *iface, IMediaStream **media_stream)
1546 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1548 TRACE("sample %p, media_stream %p.\n", sample, media_stream);
1550 if (!media_stream)
1551 return E_POINTER;
1553 IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
1554 *media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
1556 return S_OK;
1559 static HRESULT WINAPI ddraw_sample_GetSampleTimes(IDirectDrawStreamSample *iface, STREAM_TIME *start_time,
1560 STREAM_TIME *end_time, STREAM_TIME *current_time)
1562 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1564 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
1566 if (current_time)
1567 IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
1569 if (start_time)
1570 *start_time = sample->start_time;
1571 if (end_time)
1572 *end_time = sample->end_time;
1574 return S_OK;
1577 static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface, const STREAM_TIME *start_time,
1578 const STREAM_TIME *end_time)
1580 FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
1582 return E_NOTIMPL;
1585 static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
1586 DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
1588 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1590 TRACE("sample %p, flags %#x, event %p, apc_func %p, apc_data %#x.\n",
1591 sample, flags, event, apc_func, apc_data);
1593 if (event && apc_func)
1594 return E_INVALIDARG;
1596 if (apc_func)
1598 FIXME("APC support is not implemented!\n");
1599 return E_NOTIMPL;
1602 EnterCriticalSection(&sample->parent->cs);
1604 if (sample->parent->state != State_Running)
1606 LeaveCriticalSection(&sample->parent->cs);
1607 return MS_E_NOTRUNNING;
1609 if (!sample->parent->peer || sample->parent->eos)
1611 sample->update_hr = MS_S_ENDOFSTREAM;
1612 LeaveCriticalSection(&sample->parent->cs);
1613 return MS_S_ENDOFSTREAM;
1615 if (sample->busy)
1617 LeaveCriticalSection(&sample->parent->cs);
1618 return MS_E_BUSY;
1621 sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
1623 sample->update_hr = MS_S_NOUPDATE;
1624 sample->busy = TRUE;
1625 sample->external_event = event;
1626 list_add_tail(&sample->parent->update_queue, &sample->entry);
1627 WakeConditionVariable(&sample->parent->update_queued_cv);
1629 if ((flags & SSUPDATE_ASYNC) || event)
1631 LeaveCriticalSection(&sample->parent->cs);
1632 return MS_S_PENDING;
1635 while (sample->busy)
1636 SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
1638 LeaveCriticalSection(&sample->parent->cs);
1640 return sample->update_hr;
1643 static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds)
1645 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1646 HRESULT hr;
1648 TRACE("sample %p, flags %#x, milliseconds %u.\n", sample, flags, milliseconds);
1650 EnterCriticalSection(&sample->parent->cs);
1652 if (sample->busy)
1654 if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
1656 remove_queued_update(sample);
1658 else if (flags & COMPSTAT_WAIT)
1660 DWORD start_time = GetTickCount();
1661 DWORD elapsed = 0;
1662 sample->continuous_update = FALSE;
1663 while (sample->busy && elapsed < milliseconds)
1665 DWORD sleep_time = milliseconds - elapsed;
1666 if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
1667 break;
1668 elapsed = GetTickCount() - start_time;
1673 hr = sample->busy ? MS_S_PENDING : sample->update_hr;
1675 LeaveCriticalSection(&sample->parent->cs);
1677 return hr;
1680 /*** IDirectDrawStreamSample methods ***/
1681 static HRESULT WINAPI ddraw_sample_GetSurface(IDirectDrawStreamSample *iface, IDirectDrawSurface **ddraw_surface,
1682 RECT *rect)
1684 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1686 TRACE("(%p)->(%p,%p)\n", iface, ddraw_surface, rect);
1688 if (ddraw_surface)
1690 *ddraw_surface = sample->surface;
1691 if (*ddraw_surface)
1692 IDirectDrawSurface_AddRef(*ddraw_surface);
1695 if (rect)
1696 *rect = sample->rect;
1698 return S_OK;
1701 static HRESULT WINAPI ddraw_sample_SetRect(IDirectDrawStreamSample *iface, const RECT *rect)
1703 FIXME("(%p)->(%p): stub\n", iface, rect);
1705 return E_NOTIMPL;
1708 static const struct IDirectDrawStreamSampleVtbl DirectDrawStreamSample_Vtbl =
1710 /*** IUnknown methods ***/
1711 ddraw_sample_QueryInterface,
1712 ddraw_sample_AddRef,
1713 ddraw_sample_Release,
1714 /*** IStreamSample methods ***/
1715 ddraw_sample_GetMediaStream,
1716 ddraw_sample_GetSampleTimes,
1717 ddraw_sample_SetSampleTimes,
1718 ddraw_sample_Update,
1719 ddraw_sample_CompletionStatus,
1720 /*** IDirectDrawStreamSample methods ***/
1721 ddraw_sample_GetSurface,
1722 ddraw_sample_SetRect
1725 static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
1726 const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample)
1728 struct ddraw_sample *object;
1729 DDSURFACEDESC desc;
1730 HRESULT hr;
1732 TRACE("(%p)\n", ddraw_stream_sample);
1734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1735 if (!object)
1736 return E_OUTOFMEMORY;
1738 object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl;
1739 object->ref = 1;
1740 object->parent = parent;
1741 object->mmstream = parent->parent;
1742 InitializeConditionVariable(&object->update_cv);
1743 IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
1744 if (object->mmstream)
1745 IMultiMediaStream_AddRef(object->mmstream);
1746 ++parent->sample_refs;
1748 if (surface)
1750 object->surface = surface;
1751 IDirectDrawSurface_AddRef(surface);
1753 else
1755 IDirectDraw *ddraw;
1757 hr = IDirectDrawMediaStream_GetDirectDraw(&parent->IDirectDrawMediaStream_iface, &ddraw);
1758 if (FAILED(hr))
1760 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1761 return hr;
1764 desc.dwSize = sizeof(desc);
1765 desc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
1766 desc.dwHeight = parent->format.height;
1767 desc.dwWidth = parent->format.width;
1768 if (parent->format.flags & DDSD_PIXELFORMAT)
1770 desc.ddpfPixelFormat = parent->format.pf;
1772 else
1774 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
1775 desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1776 desc.ddpfPixelFormat.u1.dwRGBBitCount = 32;
1777 desc.ddpfPixelFormat.u2.dwRBitMask = 0xff0000;
1778 desc.ddpfPixelFormat.u3.dwGBitMask = 0x00ff00;
1779 desc.ddpfPixelFormat.u4.dwBBitMask = 0x0000ff;
1780 desc.ddpfPixelFormat.u5.dwRGBAlphaBitMask = 0;
1782 desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN;
1783 desc.lpSurface = NULL;
1785 hr = IDirectDraw_CreateSurface(ddraw, &desc, &object->surface, NULL);
1786 IDirectDraw_Release(ddraw);
1787 if (FAILED(hr))
1789 ERR("failed to create surface, 0x%08x\n", hr);
1790 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1791 return hr;
1795 desc.dwSize = sizeof(desc);
1796 hr = IDirectDrawSurface_GetSurfaceDesc(object->surface, &desc);
1797 if (FAILED(hr))
1799 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1800 return hr;
1803 if (rect)
1805 object->rect = *rect;
1806 desc.dwWidth = rect->right - rect->left;
1807 desc.dwHeight = rect->bottom - rect->top;
1809 else
1811 SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight);
1814 hr = IDirectDrawMediaStream_SetFormat(&parent->IDirectDrawMediaStream_iface, &desc, NULL);
1815 if (FAILED(hr))
1817 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1818 return hr;
1821 *ddraw_stream_sample = &object->IDirectDrawStreamSample_iface;
1823 return S_OK;