kernelbase: Remove unnecessary handler from LocalLock.
[wine.git] / dlls / amstream / ddrawstream.c
blobe31e0d106d3321d32a57c6e5afe0a88de60d7fe8
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/list.h"
26 #include "wine/strmbase.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
30 static const WCHAR sink_id[] = L"I{A35FF56A-9FDA-11D0-8FDF-00C04FD9189D}";
32 struct format
34 DWORD flags;
35 DWORD width;
36 DWORD height;
37 DDPIXELFORMAT pf;
40 struct ddraw_stream
42 IAMMediaStream IAMMediaStream_iface;
43 IDirectDrawMediaStream IDirectDrawMediaStream_iface;
44 IMemInputPin IMemInputPin_iface;
45 IPin IPin_iface;
46 LONG ref;
47 LONG sample_refs;
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;
57 IPin *peer;
58 IMemAllocator *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;
69 struct ddraw_sample
71 IDirectDrawStreamSample IDirectDrawStreamSample_iface;
72 LONG ref;
73 struct ddraw_stream *parent;
74 IMultiMediaStream *mmstream;
75 IDirectDrawSurface *surface;
76 RECT rect;
77 STREAM_TIME start_time;
78 STREAM_TIME end_time;
79 BOOL continuous_update;
80 CONDITION_VARIABLE update_cv;
81 HANDLE external_event;
83 struct list entry;
84 HRESULT update_hr;
85 BOOL busy;
88 static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
89 const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample);
91 static void remove_queued_update(struct ddraw_sample *sample)
93 sample->busy = FALSE;
94 list_remove(&sample->entry);
95 WakeConditionVariable(&sample->update_cv);
96 if (sample->external_event)
97 SetEvent(sample->external_event);
100 static void flush_update_queue(struct ddraw_stream *stream, HRESULT update_hr)
102 struct list *entry;
103 while ((entry = list_head(&stream->update_queue)))
105 struct ddraw_sample *sample = LIST_ENTRY(entry, struct ddraw_sample, entry);
106 sample->update_hr = update_hr;
107 remove_queued_update(sample);
111 static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *pointer,
112 STREAM_TIME start_time, STREAM_TIME end_time)
114 DDSURFACEDESC desc;
115 DWORD row_size;
116 const BYTE *src_row;
117 BYTE *dst_row;
118 DWORD row;
119 HRESULT hr;
121 desc.dwSize = sizeof(desc);
122 hr = IDirectDrawSurface_Lock(sample->surface, &sample->rect, &desc, DDLOCK_WAIT, NULL);
123 if (FAILED(hr))
124 return hr;
126 row_size = (sample->rect.right - sample->rect.left) * desc.ddpfPixelFormat.u1.dwRGBBitCount / 8;
127 src_row = pointer;
128 dst_row = desc.lpSurface;
129 for (row = sample->rect.top; row < sample->rect.bottom; ++row)
131 memcpy(dst_row, src_row, row_size);
132 src_row += stride;
133 dst_row += desc.u1.lPitch;
136 hr = IDirectDrawSurface_Unlock(sample->surface, desc.lpSurface);
137 if (FAILED(hr))
138 return hr;
140 sample->start_time = start_time;
141 sample->end_time = end_time;
143 return S_OK;
146 static BOOL is_format_compatible(struct ddraw_stream *stream,
147 DWORD width, DWORD height, const DDPIXELFORMAT *connection_pf)
149 if (stream->format.flags & DDSD_HEIGHT)
151 if (stream->format.width != width || stream->format.height != height)
152 return FALSE;
154 if (stream->format.flags & DDSD_PIXELFORMAT)
156 if (stream->format.pf.dwFlags & DDPF_FOURCC)
157 return FALSE;
158 if (stream->format.pf.u1.dwRGBBitCount != connection_pf->u1.dwRGBBitCount)
159 return FALSE;
160 if (stream->format.pf.u1.dwRGBBitCount == 16 && stream->format.pf.u3.dwGBitMask != connection_pf->u3.dwGBitMask)
161 return FALSE;
163 return TRUE;
166 static inline struct ddraw_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
168 return CONTAINING_RECORD(iface, struct ddraw_stream, IAMMediaStream_iface);
171 /*** IUnknown methods ***/
172 static HRESULT WINAPI ddraw_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
173 REFIID riid, void **ret_iface)
175 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
177 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
179 if (IsEqualGUID(riid, &IID_IUnknown) ||
180 IsEqualGUID(riid, &IID_IMediaStream) ||
181 IsEqualGUID(riid, &IID_IAMMediaStream))
183 IAMMediaStream_AddRef(iface);
184 *ret_iface = iface;
185 return S_OK;
187 else if (IsEqualGUID(riid, &IID_IDirectDrawMediaStream))
189 IAMMediaStream_AddRef(iface);
190 *ret_iface = &This->IDirectDrawMediaStream_iface;
191 return S_OK;
193 else if (IsEqualGUID(riid, &IID_IPin))
195 IAMMediaStream_AddRef(iface);
196 *ret_iface = &This->IPin_iface;
197 return S_OK;
199 else if (IsEqualGUID(riid, &IID_IMemInputPin))
201 IAMMediaStream_AddRef(iface);
202 *ret_iface = &This->IMemInputPin_iface;
203 return S_OK;
206 ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
207 return E_NOINTERFACE;
210 static ULONG WINAPI ddraw_IAMMediaStream_AddRef(IAMMediaStream *iface)
212 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
213 ULONG ref = InterlockedIncrement(&This->ref);
215 TRACE("(%p/%p)->(): new ref = %lu\n", iface, This, ref);
217 return ref;
220 static ULONG WINAPI ddraw_IAMMediaStream_Release(IAMMediaStream *iface)
222 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
223 ULONG ref = InterlockedDecrement(&stream->ref);
225 TRACE("%p decreasing refcount to %lu.\n", stream, ref);
227 if (!ref)
229 DeleteCriticalSection(&stream->cs);
230 if (stream->ddraw)
231 IDirectDraw_Release(stream->ddraw);
232 free(stream);
235 return ref;
238 /*** IMediaStream methods ***/
239 static HRESULT WINAPI ddraw_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
240 IMultiMediaStream **mmstream)
242 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
244 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
246 if (!mmstream)
247 return E_POINTER;
249 if (stream->parent)
250 IMultiMediaStream_AddRef(stream->parent);
251 *mmstream = stream->parent;
252 return S_OK;
255 static HRESULT WINAPI ddraw_IAMMediaStream_GetInformation(IAMMediaStream *iface,
256 MSPID *purpose_id, STREAM_TYPE *type)
258 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
260 TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
262 if (purpose_id)
263 *purpose_id = This->purpose_id;
264 if (type)
265 *type = This->stream_type;
267 return S_OK;
270 static HRESULT WINAPI ddraw_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
271 IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
273 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
275 FIXME("(%p/%p)->(%p,%lx) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
277 return S_FALSE;
280 static HRESULT WINAPI ddraw_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
281 DWORD flags, IStreamSample **sample)
283 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
285 FIXME("(%p/%p)->(%lx,%p) stub!\n", This, iface, flags, sample);
287 return S_FALSE;
290 static HRESULT WINAPI ddraw_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
291 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
293 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
295 FIXME("(%p/%p)->(%p,%lx,%p) stub!\n", This, iface, existing_sample, flags, sample);
297 return S_FALSE;
300 static HRESULT WINAPI ddraw_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
302 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
304 FIXME("(%p/%p)->(%lx) stub!\n", This, iface, flags);
306 return S_FALSE;
309 /*** IAMMediaStream methods ***/
310 static HRESULT WINAPI ddraw_IAMMediaStream_Initialize(IAMMediaStream *iface, IUnknown *source_object, DWORD flags,
311 REFMSPID purpose_id, const STREAM_TYPE stream_type)
313 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
314 HRESULT hr;
316 TRACE("stream %p, source_object %p, flags %lx, purpose_id %s, stream_type %u.\n", stream, source_object, flags,
317 debugstr_guid(purpose_id), stream_type);
319 if (!purpose_id)
320 return E_POINTER;
322 if (flags & AMMSF_CREATEPEER)
323 FIXME("AMMSF_CREATEPEER is not yet supported.\n");
325 stream->purpose_id = *purpose_id;
326 stream->stream_type = stream_type;
328 if (source_object
329 && FAILED(hr = IUnknown_QueryInterface(source_object, &IID_IDirectDraw, (void **)&stream->ddraw)))
330 FIXME("Stream object doesn't implement IDirectDraw interface, hr %#lx.\n", hr);
332 if (!source_object)
334 if (FAILED(hr = DirectDrawCreate(NULL, &stream->ddraw, NULL)))
335 return hr;
336 IDirectDraw_SetCooperativeLevel(stream->ddraw, NULL, DDSCL_NORMAL);
339 return S_OK;
342 static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
344 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
346 TRACE("stream %p, state %u.\n", stream, state);
348 EnterCriticalSection(&stream->cs);
350 if (state == State_Stopped)
351 WakeConditionVariable(&stream->update_queued_cv);
352 if (stream->state == State_Stopped)
353 stream->eos = FALSE;
355 stream->state = state;
357 LeaveCriticalSection(&stream->cs);
359 return S_OK;
362 static HRESULT WINAPI ddraw_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface, IAMMultiMediaStream *mmstream)
364 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
366 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
368 stream->parent = (IMultiMediaStream *)mmstream;
370 return S_OK;
373 static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
375 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
377 TRACE("iface %p, filter %p.\n", iface, filter);
379 stream->filter = filter;
381 return S_OK;
384 static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
386 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
388 TRACE("stream %p, filtergraph %p.\n", stream, filtergraph);
390 stream->graph = filtergraph;
392 return S_OK;
395 static const struct IAMMediaStreamVtbl ddraw_IAMMediaStream_vtbl =
397 /*** IUnknown methods ***/
398 ddraw_IAMMediaStream_QueryInterface,
399 ddraw_IAMMediaStream_AddRef,
400 ddraw_IAMMediaStream_Release,
401 /*** IMediaStream methods ***/
402 ddraw_IAMMediaStream_GetMultiMediaStream,
403 ddraw_IAMMediaStream_GetInformation,
404 ddraw_IAMMediaStream_SetSameFormat,
405 ddraw_IAMMediaStream_AllocateSample,
406 ddraw_IAMMediaStream_CreateSharedSample,
407 ddraw_IAMMediaStream_SendEndOfStream,
408 /*** IAMMediaStream methods ***/
409 ddraw_IAMMediaStream_Initialize,
410 ddraw_IAMMediaStream_SetState,
411 ddraw_IAMMediaStream_JoinAMMultiMediaStream,
412 ddraw_IAMMediaStream_JoinFilter,
413 ddraw_IAMMediaStream_JoinFilterGraph
416 static inline struct ddraw_stream *impl_from_IDirectDrawMediaStream(IDirectDrawMediaStream *iface)
418 return CONTAINING_RECORD(iface, struct ddraw_stream, IDirectDrawMediaStream_iface);
421 /*** IUnknown methods ***/
422 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_QueryInterface(IDirectDrawMediaStream *iface,
423 REFIID riid, void **ret_iface)
425 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
426 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
427 return IAMMediaStream_QueryInterface(&This->IAMMediaStream_iface, riid, ret_iface);
430 static ULONG WINAPI ddraw_IDirectDrawMediaStream_AddRef(IDirectDrawMediaStream *iface)
432 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
433 TRACE("(%p/%p)\n", iface, This);
434 return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
437 static ULONG WINAPI ddraw_IDirectDrawMediaStream_Release(IDirectDrawMediaStream *iface)
439 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
440 TRACE("(%p/%p)\n", iface, This);
441 return IAMMediaStream_Release(&This->IAMMediaStream_iface);
444 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetMultiMediaStream(IDirectDrawMediaStream *iface,
445 IMultiMediaStream **mmstream)
447 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
448 return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
451 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetInformation(IDirectDrawMediaStream *iface,
452 MSPID *purpose_id, STREAM_TYPE *type)
454 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
455 return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
458 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetSameFormat(IDirectDrawMediaStream *iface,
459 IMediaStream *other, DWORD flags)
461 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
462 return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
465 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_AllocateSample(IDirectDrawMediaStream *iface,
466 DWORD flags, IStreamSample **sample)
468 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
469 return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
472 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSharedSample(IDirectDrawMediaStream *iface,
473 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
475 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
476 return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
479 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SendEndOfStream(IDirectDrawMediaStream *iface, DWORD flags)
481 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
482 return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
485 /*** IDirectDrawMediaStream methods ***/
486 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetFormat(IDirectDrawMediaStream *iface,
487 DDSURFACEDESC *current_format, IDirectDrawPalette **palette,
488 DDSURFACEDESC *desired_format, DWORD *flags)
490 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
492 TRACE("stream %p, current_format %p, palette %p, desired_format %p, flags %p.\n", stream, current_format, palette,
493 desired_format, flags);
495 EnterCriticalSection(&stream->cs);
497 if (!stream->peer)
499 LeaveCriticalSection(&stream->cs);
500 return MS_E_NOSTREAM;
503 if (current_format)
505 current_format->dwFlags = stream->format.flags | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
506 current_format->dwWidth = stream->format.width;
507 current_format->dwHeight = stream->format.height;
508 current_format->ddpfPixelFormat = stream->format.pf;
509 current_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
512 if (palette)
513 *palette = NULL;
515 if (desired_format)
517 desired_format->dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
518 desired_format->dwWidth = stream->format.width;
519 desired_format->dwHeight = stream->format.height;
520 desired_format->ddpfPixelFormat = stream->format.pf;
521 desired_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
524 if (flags)
525 *flags = 0;
527 LeaveCriticalSection(&stream->cs);
529 return S_OK;
532 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetFormat(IDirectDrawMediaStream *iface,
533 const DDSURFACEDESC *format, IDirectDrawPalette *palette)
535 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
536 AM_MEDIA_TYPE old_media_type;
537 struct format old_format;
538 IPin *old_peer;
539 HRESULT hr;
541 TRACE("stream %p, format %p, palette %p.\n", stream, format, palette);
543 if (palette)
544 FIXME("Setting palette is not yet supported.\n");
546 if (!format)
547 return E_POINTER;
549 if (format->dwSize != sizeof(DDSURFACEDESC))
550 return E_INVALIDARG;
552 TRACE("flags %#lx, pixel format flags %#lx, bit count %lu, size %lux%lu.\n",
553 format->dwFlags, format->ddpfPixelFormat.dwFlags,
554 format->ddpfPixelFormat.u1.dwRGBBitCount, format->dwWidth, format->dwHeight);
556 if (format->dwFlags & DDSD_PIXELFORMAT)
558 if (format->ddpfPixelFormat.dwSize != sizeof(DDPIXELFORMAT))
559 return DDERR_INVALIDSURFACETYPE;
561 if (format->ddpfPixelFormat.dwFlags & DDPF_FOURCC)
563 if (!format->ddpfPixelFormat.u1.dwRGBBitCount)
564 return E_INVALIDARG;
566 else
568 if (format->ddpfPixelFormat.dwFlags & (DDPF_YUV | DDPF_PALETTEINDEXED1 |
569 DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXEDTO8))
570 return DDERR_INVALIDSURFACETYPE;
572 if (!(format->ddpfPixelFormat.dwFlags & DDPF_RGB))
573 return DDERR_INVALIDSURFACETYPE;
575 switch (format->ddpfPixelFormat.u1.dwRGBBitCount)
577 case 8:
578 if (!(format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8))
579 return DDERR_INVALIDSURFACETYPE;
580 break;
581 case 16:
582 if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
583 return DDERR_INVALIDSURFACETYPE;
584 if ((format->ddpfPixelFormat.u2.dwRBitMask != 0x7c00 ||
585 format->ddpfPixelFormat.u3.dwGBitMask != 0x03e0 ||
586 format->ddpfPixelFormat.u4.dwBBitMask != 0x001f) &&
587 (format->ddpfPixelFormat.u2.dwRBitMask != 0xf800 ||
588 format->ddpfPixelFormat.u3.dwGBitMask != 0x07e0 ||
589 format->ddpfPixelFormat.u4.dwBBitMask != 0x001f))
590 return DDERR_INVALIDSURFACETYPE;
591 break;
592 case 24:
593 case 32:
594 if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
595 return DDERR_INVALIDSURFACETYPE;
596 if (format->ddpfPixelFormat.u2.dwRBitMask != 0xff0000 ||
597 format->ddpfPixelFormat.u3.dwGBitMask != 0x00ff00 ||
598 format->ddpfPixelFormat.u4.dwBBitMask != 0x0000ff)
599 return DDERR_INVALIDSURFACETYPE;
600 break;
601 default:
602 return DDERR_INVALIDSURFACETYPE;
607 EnterCriticalSection(&stream->cs);
609 old_format = stream->format;
610 stream->format.flags = format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
611 if (format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT))
613 stream->format.width = format->dwWidth;
614 stream->format.height = format->dwHeight;
616 if (format->dwFlags & DDSD_PIXELFORMAT)
617 stream->format.pf = format->ddpfPixelFormat;
619 if (stream->peer && !is_format_compatible(stream, old_format.width, old_format.height, &old_format.pf))
621 hr = CopyMediaType(&old_media_type, &stream->mt);
622 if (FAILED(hr))
624 stream->format = old_format;
625 LeaveCriticalSection(&stream->cs);
626 return hr;
628 old_peer = stream->peer;
629 IPin_AddRef(old_peer);
631 IFilterGraph_Disconnect(stream->graph, stream->peer);
632 IFilterGraph_Disconnect(stream->graph, &stream->IPin_iface);
633 hr = IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, NULL);
634 if (FAILED(hr))
636 stream->format = old_format;
637 IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, &old_media_type);
638 IPin_Release(old_peer);
639 FreeMediaType(&old_media_type);
640 LeaveCriticalSection(&stream->cs);
641 return DDERR_INVALIDSURFACETYPE;
644 IPin_Release(old_peer);
645 FreeMediaType(&old_media_type);
648 LeaveCriticalSection(&stream->cs);
650 return S_OK;
653 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetDirectDraw(IDirectDrawMediaStream *iface,
654 IDirectDraw **ddraw)
656 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
658 TRACE("stream %p, ddraw %p.\n", stream, ddraw);
660 if (!ddraw)
661 return E_POINTER;
663 if (!stream->ddraw)
665 *ddraw = NULL;
666 return S_OK;
669 IDirectDraw_AddRef(stream->ddraw);
670 *ddraw = stream->ddraw;
672 return S_OK;
675 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetDirectDraw(IDirectDrawMediaStream *iface,
676 IDirectDraw *ddraw)
678 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
680 TRACE("stream %p, ddraw %p.\n", stream, ddraw);
682 EnterCriticalSection(&stream->cs);
684 if (stream->sample_refs)
686 HRESULT hr = (stream->ddraw == ddraw) ? S_OK : MS_E_SAMPLEALLOC;
687 LeaveCriticalSection(&stream->cs);
688 return hr;
691 if (stream->ddraw)
692 IDirectDraw_Release(stream->ddraw);
694 if (ddraw)
696 IDirectDraw_AddRef(ddraw);
697 stream->ddraw = ddraw;
699 else
700 stream->ddraw = NULL;
702 LeaveCriticalSection(&stream->cs);
704 return S_OK;
707 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSample(IDirectDrawMediaStream *iface,
708 IDirectDrawSurface *surface, const RECT *rect, DWORD flags,
709 IDirectDrawStreamSample **sample)
711 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
712 HRESULT hr;
714 TRACE("stream %p, surface %p, rect %s, flags %#lx, sample %p.\n",
715 stream, surface, wine_dbgstr_rect(rect), flags, sample);
717 if (!surface && rect)
718 return E_INVALIDARG;
720 EnterCriticalSection(&stream->cs);
721 hr = ddrawstreamsample_create(stream, surface, rect, sample);
722 LeaveCriticalSection(&stream->cs);
724 return hr;
727 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetTimePerFrame(IDirectDrawMediaStream *iface,
728 STREAM_TIME *frame_time)
730 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
732 TRACE("stream %p, frame_time %p.\n", stream, frame_time);
734 if (!frame_time)
735 return E_POINTER;
737 EnterCriticalSection(&stream->cs);
739 if (!stream->peer)
741 LeaveCriticalSection(&stream->cs);
742 return MS_E_NOSTREAM;
745 *frame_time = ((VIDEOINFO *)stream->mt.pbFormat)->AvgTimePerFrame;
747 LeaveCriticalSection(&stream->cs);
749 return S_OK;
752 static const struct IDirectDrawMediaStreamVtbl ddraw_IDirectDrawMediaStream_Vtbl =
754 /*** IUnknown methods ***/
755 ddraw_IDirectDrawMediaStream_QueryInterface,
756 ddraw_IDirectDrawMediaStream_AddRef,
757 ddraw_IDirectDrawMediaStream_Release,
758 /*** IMediaStream methods ***/
759 ddraw_IDirectDrawMediaStream_GetMultiMediaStream,
760 ddraw_IDirectDrawMediaStream_GetInformation,
761 ddraw_IDirectDrawMediaStream_SetSameFormat,
762 ddraw_IDirectDrawMediaStream_AllocateSample,
763 ddraw_IDirectDrawMediaStream_CreateSharedSample,
764 ddraw_IDirectDrawMediaStream_SendEndOfStream,
765 /*** IDirectDrawMediaStream methods ***/
766 ddraw_IDirectDrawMediaStream_GetFormat,
767 ddraw_IDirectDrawMediaStream_SetFormat,
768 ddraw_IDirectDrawMediaStream_GetDirectDraw,
769 ddraw_IDirectDrawMediaStream_SetDirectDraw,
770 ddraw_IDirectDrawMediaStream_CreateSample,
771 ddraw_IDirectDrawMediaStream_GetTimePerFrame
774 struct enum_media_types
776 IEnumMediaTypes IEnumMediaTypes_iface;
777 LONG refcount;
778 unsigned int index;
781 static const IEnumMediaTypesVtbl enum_media_types_vtbl;
783 static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
785 return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
788 static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
790 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
792 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
794 IEnumMediaTypes_AddRef(iface);
795 *out = iface;
796 return S_OK;
799 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
800 *out = NULL;
801 return E_NOINTERFACE;
804 static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
806 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
807 ULONG refcount = InterlockedIncrement(&enum_media_types->refcount);
808 TRACE("%p increasing refcount to %lu.\n", enum_media_types, refcount);
809 return refcount;
812 static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
814 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
815 ULONG refcount = InterlockedDecrement(&enum_media_types->refcount);
816 TRACE("%p decreasing refcount to %lu.\n", enum_media_types, refcount);
817 if (!refcount)
818 free(enum_media_types);
819 return refcount;
822 static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
824 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
826 TRACE("iface %p, count %lu, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
828 if (!ret_count)
829 return E_POINTER;
831 if (count && !enum_media_types->index)
833 mts[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
834 memset(mts[0], 0, sizeof(AM_MEDIA_TYPE));
835 mts[0]->majortype = MEDIATYPE_Video;
836 mts[0]->subtype = MEDIASUBTYPE_RGB8;
837 mts[0]->bFixedSizeSamples = TRUE;
838 mts[0]->lSampleSize = 10000;
839 ++enum_media_types->index;
840 *ret_count = 1;
841 return count == 1 ? S_OK : S_FALSE;
844 *ret_count = 0;
845 return count ? S_FALSE : S_OK;
848 static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
850 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
852 TRACE("iface %p, count %lu.\n", iface, count);
854 enum_media_types->index += count;
856 return S_OK;
859 static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
861 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
863 TRACE("iface %p.\n", iface);
865 enum_media_types->index = 0;
866 return S_OK;
869 static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
871 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
872 struct enum_media_types *object;
874 TRACE("iface %p, out %p.\n", iface, out);
876 if (!(object = calloc(1, sizeof(*object))))
877 return E_OUTOFMEMORY;
879 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
880 object->refcount = 1;
881 object->index = enum_media_types->index;
883 *out = &object->IEnumMediaTypes_iface;
884 return S_OK;
887 static const IEnumMediaTypesVtbl enum_media_types_vtbl =
889 enum_media_types_QueryInterface,
890 enum_media_types_AddRef,
891 enum_media_types_Release,
892 enum_media_types_Next,
893 enum_media_types_Skip,
894 enum_media_types_Reset,
895 enum_media_types_Clone,
898 static inline struct ddraw_stream *impl_from_IPin(IPin *iface)
900 return CONTAINING_RECORD(iface, struct ddraw_stream, IPin_iface);
903 static HRESULT WINAPI ddraw_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
905 struct ddraw_stream *stream = impl_from_IPin(iface);
906 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
909 static ULONG WINAPI ddraw_sink_AddRef(IPin *iface)
911 struct ddraw_stream *stream = impl_from_IPin(iface);
912 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
915 static ULONG WINAPI ddraw_sink_Release(IPin *iface)
917 struct ddraw_stream *stream = impl_from_IPin(iface);
918 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
921 static HRESULT WINAPI ddraw_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
923 WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
924 return E_UNEXPECTED;
927 static HRESULT WINAPI ddraw_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
929 struct ddraw_stream *stream = impl_from_IPin(iface);
930 const VIDEOINFOHEADER *video_info;
931 PIN_DIRECTION dir;
932 DWORD width;
933 DWORD height;
934 DDPIXELFORMAT pf = {sizeof(DDPIXELFORMAT)};
936 TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
938 EnterCriticalSection(&stream->cs);
940 if (stream->peer)
942 LeaveCriticalSection(&stream->cs);
943 return VFW_E_ALREADY_CONNECTED;
946 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
947 || !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
949 LeaveCriticalSection(&stream->cs);
950 return VFW_E_TYPE_NOT_ACCEPTED;
953 video_info = (const VIDEOINFOHEADER *)mt->pbFormat;
955 width = video_info->bmiHeader.biWidth;
956 height = abs(video_info->bmiHeader.biHeight);
957 pf.dwFlags = DDPF_RGB;
958 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8))
960 pf.dwFlags |= DDPF_PALETTEINDEXED8;
961 pf.u1.dwRGBBitCount = 8;
963 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB555))
965 pf.u1.dwRGBBitCount = 16;
966 pf.u2.dwRBitMask = 0x7c00;
967 pf.u3.dwGBitMask = 0x03e0;
968 pf.u4.dwBBitMask = 0x001f;
970 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB565))
972 pf.u1.dwRGBBitCount = 16;
973 pf.u2.dwRBitMask = 0xf800;
974 pf.u3.dwGBitMask = 0x07e0;
975 pf.u4.dwBBitMask = 0x001f;
977 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB24))
979 pf.u1.dwRGBBitCount = 24;
980 pf.u2.dwRBitMask = 0xff0000;
981 pf.u3.dwGBitMask = 0x00ff00;
982 pf.u4.dwBBitMask = 0x0000ff;
984 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB32))
986 pf.u1.dwRGBBitCount = 32;
987 pf.u2.dwRBitMask = 0xff0000;
988 pf.u3.dwGBitMask = 0x00ff00;
989 pf.u4.dwBBitMask = 0x0000ff;
991 else
993 LeaveCriticalSection(&stream->cs);
994 return VFW_E_TYPE_NOT_ACCEPTED;
997 if (!is_format_compatible(stream, width, height, &pf))
999 LeaveCriticalSection(&stream->cs);
1000 return VFW_E_TYPE_NOT_ACCEPTED;
1003 IPin_QueryDirection(peer, &dir);
1004 if (dir != PINDIR_OUTPUT)
1006 WARN("Rejecting connection from input pin.\n");
1007 LeaveCriticalSection(&stream->cs);
1008 return VFW_E_INVALID_DIRECTION;
1011 CopyMediaType(&stream->mt, mt);
1012 IPin_AddRef(stream->peer = peer);
1014 stream->format.width = width;
1015 stream->format.height = height;
1016 if (!(stream->format.flags & DDSD_PIXELFORMAT))
1017 stream->format.pf = pf;
1019 LeaveCriticalSection(&stream->cs);
1021 return S_OK;
1024 static HRESULT WINAPI ddraw_sink_Disconnect(IPin *iface)
1026 struct ddraw_stream *stream = impl_from_IPin(iface);
1028 TRACE("stream %p.\n", stream);
1030 EnterCriticalSection(&stream->cs);
1032 if (!stream->peer)
1034 LeaveCriticalSection(&stream->cs);
1035 return S_FALSE;
1038 IPin_Release(stream->peer);
1039 stream->peer = NULL;
1040 FreeMediaType(&stream->mt);
1041 memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
1043 LeaveCriticalSection(&stream->cs);
1045 return S_OK;
1048 static HRESULT WINAPI ddraw_sink_ConnectedTo(IPin *iface, IPin **peer)
1050 struct ddraw_stream *stream = impl_from_IPin(iface);
1051 HRESULT hr;
1053 TRACE("stream %p, peer %p.\n", stream, peer);
1055 EnterCriticalSection(&stream->cs);
1057 if (stream->peer)
1059 IPin_AddRef(*peer = stream->peer);
1060 hr = S_OK;
1062 else
1064 *peer = NULL;
1065 hr = VFW_E_NOT_CONNECTED;
1068 LeaveCriticalSection(&stream->cs);
1070 return hr;
1073 static HRESULT WINAPI ddraw_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1075 struct ddraw_stream *stream = impl_from_IPin(iface);
1076 HRESULT hr;
1078 TRACE("stream %p, mt %p.\n", stream, mt);
1080 EnterCriticalSection(&stream->cs);
1082 if (stream->peer)
1084 CopyMediaType(mt, &stream->mt);
1085 hr = S_OK;
1087 else
1089 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1090 hr = VFW_E_NOT_CONNECTED;
1093 LeaveCriticalSection(&stream->cs);
1095 return hr;
1098 static HRESULT WINAPI ddraw_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1100 struct ddraw_stream *stream = impl_from_IPin(iface);
1102 TRACE("stream %p, info %p.\n", stream, info);
1104 IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1105 info->dir = PINDIR_INPUT;
1106 wcscpy(info->achName, sink_id);
1108 return S_OK;
1111 static HRESULT WINAPI ddraw_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1113 TRACE("iface %p, dir %p.\n", iface, dir);
1114 *dir = PINDIR_INPUT;
1115 return S_OK;
1118 static HRESULT WINAPI ddraw_sink_QueryId(IPin *iface, WCHAR **id)
1120 TRACE("iface %p, id %p.\n", iface, id);
1122 if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1123 return E_OUTOFMEMORY;
1125 wcscpy(*id, sink_id);
1127 return S_OK;
1130 static HRESULT WINAPI ddraw_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1132 TRACE("iface %p, mt %p.\n", iface, mt);
1134 if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
1135 && IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8)
1136 && IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
1137 return S_OK;
1139 return VFW_E_TYPE_NOT_ACCEPTED;
1142 static HRESULT WINAPI ddraw_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1144 struct enum_media_types *object;
1146 TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1148 if (!enum_media_types)
1149 return E_POINTER;
1151 if (!(object = calloc(1, sizeof(*object))))
1152 return E_OUTOFMEMORY;
1154 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1155 object->refcount = 1;
1156 object->index = 0;
1158 *enum_media_types = &object->IEnumMediaTypes_iface;
1159 return S_OK;
1162 static HRESULT WINAPI ddraw_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1164 TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1165 return E_NOTIMPL;
1168 static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
1170 struct ddraw_stream *stream = impl_from_IPin(iface);
1172 TRACE("stream %p.\n", stream);
1174 EnterCriticalSection(&stream->cs);
1176 if (stream->eos || stream->flushing)
1178 LeaveCriticalSection(&stream->cs);
1179 return E_FAIL;
1182 stream->eos = TRUE;
1184 flush_update_queue(stream, MS_S_ENDOFSTREAM);
1186 LeaveCriticalSection(&stream->cs);
1188 /* Calling IMediaStreamFilter::EndOfStream() inside the critical section
1189 * would invert the locking order, so we must leave it first to avoid
1190 * the streaming thread deadlocking on the filter's critical section. */
1191 IMediaStreamFilter_EndOfStream(stream->filter);
1193 return S_OK;
1196 static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface)
1198 struct ddraw_stream *stream = impl_from_IPin(iface);
1199 BOOL cancel_eos;
1201 TRACE("stream %p.\n", stream);
1203 EnterCriticalSection(&stream->cs);
1205 cancel_eos = stream->eos;
1207 stream->flushing = TRUE;
1208 stream->eos = FALSE;
1209 WakeConditionVariable(&stream->update_queued_cv);
1211 LeaveCriticalSection(&stream->cs);
1213 /* Calling IMediaStreamFilter::Flush() inside the critical section would
1214 * invert the locking order, so we must leave it first to avoid the
1215 * application thread deadlocking on the filter's critical section. */
1216 IMediaStreamFilter_Flush(stream->filter, cancel_eos);
1218 return S_OK;
1221 static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface)
1223 struct ddraw_stream *stream = impl_from_IPin(iface);
1225 TRACE("stream %p.\n", stream);
1227 EnterCriticalSection(&stream->cs);
1229 stream->flushing = FALSE;
1231 LeaveCriticalSection(&stream->cs);
1233 return S_OK;
1236 static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1238 struct ddraw_stream *stream = impl_from_IPin(iface);
1240 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1241 stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1243 EnterCriticalSection(&stream->cs);
1245 stream->segment_start = start;
1247 LeaveCriticalSection(&stream->cs);
1249 return S_OK;
1252 static const IPinVtbl ddraw_sink_vtbl =
1254 ddraw_sink_QueryInterface,
1255 ddraw_sink_AddRef,
1256 ddraw_sink_Release,
1257 ddraw_sink_Connect,
1258 ddraw_sink_ReceiveConnection,
1259 ddraw_sink_Disconnect,
1260 ddraw_sink_ConnectedTo,
1261 ddraw_sink_ConnectionMediaType,
1262 ddraw_sink_QueryPinInfo,
1263 ddraw_sink_QueryDirection,
1264 ddraw_sink_QueryId,
1265 ddraw_sink_QueryAccept,
1266 ddraw_sink_EnumMediaTypes,
1267 ddraw_sink_QueryInternalConnections,
1268 ddraw_sink_EndOfStream,
1269 ddraw_sink_BeginFlush,
1270 ddraw_sink_EndFlush,
1271 ddraw_sink_NewSegment,
1274 static inline struct ddraw_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1276 return CONTAINING_RECORD(iface, struct ddraw_stream, IMemInputPin_iface);
1279 static HRESULT WINAPI ddraw_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1281 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1282 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1285 static ULONG WINAPI ddraw_meminput_AddRef(IMemInputPin *iface)
1287 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1288 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1291 static ULONG WINAPI ddraw_meminput_Release(IMemInputPin *iface)
1293 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1294 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1297 static HRESULT WINAPI ddraw_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1299 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1301 TRACE("stream %p, allocator %p.\n", stream, allocator);
1303 if (stream->allocator)
1305 IMemAllocator_AddRef(*allocator = stream->allocator);
1306 return S_OK;
1309 *allocator = NULL;
1310 return VFW_E_NO_ALLOCATOR;
1313 static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1315 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1317 TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1319 if (!allocator)
1320 return E_POINTER;
1322 if (allocator)
1323 IMemAllocator_AddRef(allocator);
1324 if (stream->allocator)
1325 IMemAllocator_Release(stream->allocator);
1326 stream->allocator = allocator;
1328 return S_OK;
1331 static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1333 TRACE("iface %p, props %p.\n", iface, props);
1334 return E_NOTIMPL;
1337 static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1339 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1340 BITMAPINFOHEADER *bitmap_info;
1341 REFERENCE_TIME start_time = 0;
1342 REFERENCE_TIME end_time = 0;
1343 STREAM_TIME start_stream_time;
1344 STREAM_TIME end_stream_time;
1345 IMediaStreamFilter *filter;
1346 STREAM_TIME current_time;
1347 BYTE *top_down_pointer;
1348 int top_down_stride;
1349 BYTE *pointer;
1350 BOOL top_down;
1351 int stride;
1352 HRESULT hr;
1354 TRACE("stream %p, sample %p.\n", stream, sample);
1356 hr = IMediaSample_GetPointer(sample, &pointer);
1357 if (FAILED(hr))
1358 return hr;
1360 IMediaSample_GetTime(sample, &start_time, &end_time);
1362 EnterCriticalSection(&stream->cs);
1364 if (stream->state == State_Stopped)
1366 LeaveCriticalSection(&stream->cs);
1367 return S_OK;
1369 if (stream->flushing)
1371 LeaveCriticalSection(&stream->cs);
1372 return S_FALSE;
1375 bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader;
1377 stride = ((bitmap_info->biWidth * bitmap_info->biBitCount + 31) & ~31) / 8;
1378 top_down = (bitmap_info->biHeight < 0);
1380 top_down_stride = top_down ? stride : -stride;
1381 top_down_pointer = top_down ? pointer : pointer + stride * (bitmap_info->biHeight - 1);
1383 start_stream_time = start_time + stream->segment_start;
1384 end_stream_time = end_time + stream->segment_start;
1386 filter = stream->filter;
1388 LeaveCriticalSection(&stream->cs);
1389 if (S_OK == IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time)
1390 && start_time >= current_time + 10000)
1391 IMediaStreamFilter_WaitUntil(filter, start_time);
1392 EnterCriticalSection(&stream->cs);
1394 for (;;)
1396 if (stream->state == State_Stopped)
1398 LeaveCriticalSection(&stream->cs);
1399 return S_OK;
1401 if (stream->flushing)
1403 LeaveCriticalSection(&stream->cs);
1404 return S_FALSE;
1406 if (!list_empty(&stream->update_queue))
1408 struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
1410 sample->update_hr = process_update(sample, top_down_stride, top_down_pointer,
1411 start_stream_time, end_stream_time);
1413 if (sample->continuous_update && SUCCEEDED(sample->update_hr))
1415 list_remove(&sample->entry);
1416 list_add_tail(&sample->parent->update_queue, &sample->entry);
1418 else
1420 remove_queued_update(sample);
1422 LeaveCriticalSection(&stream->cs);
1423 return S_OK;
1426 SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE);
1430 static HRESULT WINAPI ddraw_meminput_ReceiveMultiple(IMemInputPin *iface,
1431 IMediaSample **samples, LONG count, LONG *processed)
1433 FIXME("iface %p, samples %p, count %lu, processed %p, stub!\n", iface, samples, count, processed);
1434 return E_NOTIMPL;
1437 static HRESULT WINAPI ddraw_meminput_ReceiveCanBlock(IMemInputPin *iface)
1439 TRACE("iface %p.\n", iface);
1440 return S_OK;
1443 static const IMemInputPinVtbl ddraw_meminput_vtbl =
1445 ddraw_meminput_QueryInterface,
1446 ddraw_meminput_AddRef,
1447 ddraw_meminput_Release,
1448 ddraw_meminput_GetAllocator,
1449 ddraw_meminput_NotifyAllocator,
1450 ddraw_meminput_GetAllocatorRequirements,
1451 ddraw_meminput_Receive,
1452 ddraw_meminput_ReceiveMultiple,
1453 ddraw_meminput_ReceiveCanBlock,
1456 HRESULT ddraw_stream_create(IUnknown *outer, void **out)
1458 struct ddraw_stream *object;
1460 if (outer)
1461 return CLASS_E_NOAGGREGATION;
1463 if (!(object = calloc(1, sizeof(*object))))
1464 return E_OUTOFMEMORY;
1466 object->IAMMediaStream_iface.lpVtbl = &ddraw_IAMMediaStream_vtbl;
1467 object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl;
1468 object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl;
1469 object->IPin_iface.lpVtbl = &ddraw_sink_vtbl;
1470 object->ref = 1;
1472 object->format.width = 100;
1473 object->format.height = 100;
1475 InitializeCriticalSection(&object->cs);
1476 InitializeConditionVariable(&object->update_queued_cv);
1477 list_init(&object->update_queue);
1479 TRACE("Created ddraw stream %p.\n", object);
1481 *out = &object->IAMMediaStream_iface;
1483 return S_OK;
1486 static inline struct ddraw_sample *impl_from_IDirectDrawStreamSample(IDirectDrawStreamSample *iface)
1488 return CONTAINING_RECORD(iface, struct ddraw_sample, IDirectDrawStreamSample_iface);
1491 /*** IUnknown methods ***/
1492 static HRESULT WINAPI ddraw_sample_QueryInterface(IDirectDrawStreamSample *iface,
1493 REFIID riid, void **ret_iface)
1495 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
1497 if (IsEqualGUID(riid, &IID_IUnknown) ||
1498 IsEqualGUID(riid, &IID_IStreamSample) ||
1499 IsEqualGUID(riid, &IID_IDirectDrawStreamSample))
1501 IDirectDrawStreamSample_AddRef(iface);
1502 *ret_iface = iface;
1503 return S_OK;
1506 *ret_iface = NULL;
1508 ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
1509 return E_NOINTERFACE;
1512 static ULONG WINAPI ddraw_sample_AddRef(IDirectDrawStreamSample *iface)
1514 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1515 ULONG ref = InterlockedIncrement(&sample->ref);
1517 TRACE("(%p)->(): new ref = %lu\n", iface, ref);
1519 return ref;
1522 static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
1524 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1525 ULONG ref = InterlockedDecrement(&sample->ref);
1527 TRACE("(%p)->(): new ref = %lu\n", iface, ref);
1529 if (!ref)
1531 EnterCriticalSection(&sample->parent->cs);
1532 --sample->parent->sample_refs;
1533 LeaveCriticalSection(&sample->parent->cs);
1535 if (sample->mmstream)
1536 IMultiMediaStream_Release(sample->mmstream);
1537 IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
1539 if (sample->surface)
1540 IDirectDrawSurface_Release(sample->surface);
1541 free(sample);
1544 return ref;
1547 /*** IStreamSample methods ***/
1548 static HRESULT WINAPI ddraw_sample_GetMediaStream(IDirectDrawStreamSample *iface, IMediaStream **media_stream)
1550 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1552 TRACE("sample %p, media_stream %p.\n", sample, media_stream);
1554 if (!media_stream)
1555 return E_POINTER;
1557 IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
1558 *media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
1560 return S_OK;
1563 static HRESULT WINAPI ddraw_sample_GetSampleTimes(IDirectDrawStreamSample *iface, STREAM_TIME *start_time,
1564 STREAM_TIME *end_time, STREAM_TIME *current_time)
1566 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1568 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
1570 if (current_time)
1571 IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
1573 if (start_time)
1574 *start_time = sample->start_time;
1575 if (end_time)
1576 *end_time = sample->end_time;
1578 return S_OK;
1581 static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface, const STREAM_TIME *start_time,
1582 const STREAM_TIME *end_time)
1584 FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
1586 return E_NOTIMPL;
1589 static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
1590 DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
1592 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1594 TRACE("sample %p, flags %#lx, event %p, apc_func %p, apc_data %#lx.\n",
1595 sample, flags, event, apc_func, apc_data);
1597 if (event && apc_func)
1598 return E_INVALIDARG;
1600 if (apc_func)
1602 FIXME("APC support is not implemented!\n");
1603 return E_NOTIMPL;
1606 EnterCriticalSection(&sample->parent->cs);
1608 if (sample->parent->state != State_Running)
1610 LeaveCriticalSection(&sample->parent->cs);
1611 return MS_E_NOTRUNNING;
1613 if (!sample->parent->peer || sample->parent->eos)
1615 sample->update_hr = MS_S_ENDOFSTREAM;
1616 LeaveCriticalSection(&sample->parent->cs);
1617 return MS_S_ENDOFSTREAM;
1619 if (sample->busy)
1621 LeaveCriticalSection(&sample->parent->cs);
1622 return MS_E_BUSY;
1625 sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
1627 sample->update_hr = MS_S_NOUPDATE;
1628 sample->busy = TRUE;
1629 sample->external_event = event;
1630 list_add_tail(&sample->parent->update_queue, &sample->entry);
1631 WakeConditionVariable(&sample->parent->update_queued_cv);
1633 if ((flags & SSUPDATE_ASYNC) || event)
1635 LeaveCriticalSection(&sample->parent->cs);
1636 return MS_S_PENDING;
1639 while (sample->busy)
1640 SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
1642 LeaveCriticalSection(&sample->parent->cs);
1644 return sample->update_hr;
1647 static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds)
1649 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1650 HRESULT hr;
1652 TRACE("sample %p, flags %#lx, milliseconds %lu.\n", sample, flags, milliseconds);
1654 EnterCriticalSection(&sample->parent->cs);
1656 if (sample->busy)
1658 if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
1660 remove_queued_update(sample);
1662 else if (flags & COMPSTAT_WAIT)
1664 DWORD start_time = GetTickCount();
1665 DWORD elapsed = 0;
1666 sample->continuous_update = FALSE;
1667 while (sample->busy && elapsed < milliseconds)
1669 DWORD sleep_time = milliseconds - elapsed;
1670 if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
1671 break;
1672 elapsed = GetTickCount() - start_time;
1677 hr = sample->busy ? MS_S_PENDING : sample->update_hr;
1679 LeaveCriticalSection(&sample->parent->cs);
1681 return hr;
1684 /*** IDirectDrawStreamSample methods ***/
1685 static HRESULT WINAPI ddraw_sample_GetSurface(IDirectDrawStreamSample *iface, IDirectDrawSurface **ddraw_surface,
1686 RECT *rect)
1688 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1690 TRACE("(%p)->(%p,%p)\n", iface, ddraw_surface, rect);
1692 if (ddraw_surface)
1694 *ddraw_surface = sample->surface;
1695 if (*ddraw_surface)
1696 IDirectDrawSurface_AddRef(*ddraw_surface);
1699 if (rect)
1700 *rect = sample->rect;
1702 return S_OK;
1705 static HRESULT WINAPI ddraw_sample_SetRect(IDirectDrawStreamSample *iface, const RECT *rect)
1707 FIXME("(%p)->(%p): stub\n", iface, rect);
1709 return E_NOTIMPL;
1712 static const struct IDirectDrawStreamSampleVtbl DirectDrawStreamSample_Vtbl =
1714 /*** IUnknown methods ***/
1715 ddraw_sample_QueryInterface,
1716 ddraw_sample_AddRef,
1717 ddraw_sample_Release,
1718 /*** IStreamSample methods ***/
1719 ddraw_sample_GetMediaStream,
1720 ddraw_sample_GetSampleTimes,
1721 ddraw_sample_SetSampleTimes,
1722 ddraw_sample_Update,
1723 ddraw_sample_CompletionStatus,
1724 /*** IDirectDrawStreamSample methods ***/
1725 ddraw_sample_GetSurface,
1726 ddraw_sample_SetRect
1729 static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
1730 const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample)
1732 struct ddraw_sample *object;
1733 DDSURFACEDESC desc;
1734 HRESULT hr;
1736 TRACE("(%p)\n", ddraw_stream_sample);
1738 if (!(object = calloc(1, sizeof(*object))))
1739 return E_OUTOFMEMORY;
1741 object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl;
1742 object->ref = 1;
1743 object->parent = parent;
1744 object->mmstream = parent->parent;
1745 InitializeConditionVariable(&object->update_cv);
1746 IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
1747 if (object->mmstream)
1748 IMultiMediaStream_AddRef(object->mmstream);
1749 ++parent->sample_refs;
1751 if (surface)
1753 object->surface = surface;
1754 IDirectDrawSurface_AddRef(surface);
1756 else
1758 IDirectDraw *ddraw;
1760 hr = IDirectDrawMediaStream_GetDirectDraw(&parent->IDirectDrawMediaStream_iface, &ddraw);
1761 if (FAILED(hr))
1763 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1764 return hr;
1767 desc.dwSize = sizeof(desc);
1768 desc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
1769 desc.dwHeight = parent->format.height;
1770 desc.dwWidth = parent->format.width;
1771 if (parent->format.flags & DDSD_PIXELFORMAT)
1773 desc.ddpfPixelFormat = parent->format.pf;
1775 else
1777 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
1778 desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1779 desc.ddpfPixelFormat.u1.dwRGBBitCount = 32;
1780 desc.ddpfPixelFormat.u2.dwRBitMask = 0xff0000;
1781 desc.ddpfPixelFormat.u3.dwGBitMask = 0x00ff00;
1782 desc.ddpfPixelFormat.u4.dwBBitMask = 0x0000ff;
1783 desc.ddpfPixelFormat.u5.dwRGBAlphaBitMask = 0;
1785 desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN;
1786 desc.lpSurface = NULL;
1788 hr = IDirectDraw_CreateSurface(ddraw, &desc, &object->surface, NULL);
1789 IDirectDraw_Release(ddraw);
1790 if (FAILED(hr))
1792 ERR("failed to create surface, 0x%08lx\n", hr);
1793 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1794 return hr;
1798 desc.dwSize = sizeof(desc);
1799 hr = IDirectDrawSurface_GetSurfaceDesc(object->surface, &desc);
1800 if (FAILED(hr))
1802 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1803 return hr;
1806 if (rect)
1808 object->rect = *rect;
1809 desc.dwWidth = rect->right - rect->left;
1810 desc.dwHeight = rect->bottom - rect->top;
1812 else
1814 SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight);
1817 hr = IDirectDrawMediaStream_SetFormat(&parent->IDirectDrawMediaStream_iface, &desc, NULL);
1818 if (FAILED(hr))
1820 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1821 return hr;
1824 *ddraw_stream_sample = &object->IDirectDrawStreamSample_iface;
1826 return S_OK;