wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / amstream / ddrawstream.c
blobd6f07e1b10a18bd10d27c000e5321c834009ce91
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;
81 struct list entry;
82 HRESULT update_hr;
83 BOOL busy;
86 static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
87 const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample);
89 static void remove_queued_update(struct ddraw_sample *sample)
91 sample->busy = FALSE;
92 list_remove(&sample->entry);
93 WakeConditionVariable(&sample->update_cv);
96 static void flush_update_queue(struct ddraw_stream *stream, HRESULT update_hr)
98 struct list *entry;
99 while ((entry = list_head(&stream->update_queue)))
101 struct ddraw_sample *sample = LIST_ENTRY(entry, struct ddraw_sample, entry);
102 sample->update_hr = update_hr;
103 remove_queued_update(sample);
107 static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *pointer,
108 STREAM_TIME start_time, STREAM_TIME end_time)
110 DDSURFACEDESC desc;
111 DWORD row_size;
112 const BYTE *src_row;
113 BYTE *dst_row;
114 DWORD row;
115 HRESULT hr;
117 desc.dwSize = sizeof(desc);
118 hr = IDirectDrawSurface_Lock(sample->surface, &sample->rect, &desc, DDLOCK_WAIT, NULL);
119 if (FAILED(hr))
120 return hr;
122 row_size = (sample->rect.right - sample->rect.left) * desc.ddpfPixelFormat.u1.dwRGBBitCount / 8;
123 src_row = pointer;
124 dst_row = desc.lpSurface;
125 for (row = sample->rect.top; row < sample->rect.bottom; ++row)
127 memcpy(dst_row, src_row, row_size);
128 src_row += stride;
129 dst_row += desc.u1.lPitch;
132 hr = IDirectDrawSurface_Unlock(sample->surface, desc.lpSurface);
133 if (FAILED(hr))
134 return hr;
136 sample->start_time = start_time;
137 sample->end_time = end_time;
139 return S_OK;
142 static BOOL is_format_compatible(struct ddraw_stream *stream,
143 DWORD width, DWORD height, const DDPIXELFORMAT *connection_pf)
145 if (stream->format.flags & DDSD_HEIGHT)
147 if (stream->format.width != width || stream->format.height != height)
148 return FALSE;
150 if (stream->format.flags & DDSD_PIXELFORMAT)
152 if (stream->format.pf.dwFlags & DDPF_FOURCC)
153 return FALSE;
154 if (stream->format.pf.u1.dwRGBBitCount != connection_pf->u1.dwRGBBitCount)
155 return FALSE;
156 if (stream->format.pf.u1.dwRGBBitCount == 16 && stream->format.pf.u3.dwGBitMask != connection_pf->u3.dwGBitMask)
157 return FALSE;
159 return TRUE;
162 static inline struct ddraw_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
164 return CONTAINING_RECORD(iface, struct ddraw_stream, IAMMediaStream_iface);
167 /*** IUnknown methods ***/
168 static HRESULT WINAPI ddraw_IAMMediaStream_QueryInterface(IAMMediaStream *iface,
169 REFIID riid, void **ret_iface)
171 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
173 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
175 if (IsEqualGUID(riid, &IID_IUnknown) ||
176 IsEqualGUID(riid, &IID_IMediaStream) ||
177 IsEqualGUID(riid, &IID_IAMMediaStream))
179 IAMMediaStream_AddRef(iface);
180 *ret_iface = iface;
181 return S_OK;
183 else if (IsEqualGUID(riid, &IID_IDirectDrawMediaStream))
185 IAMMediaStream_AddRef(iface);
186 *ret_iface = &This->IDirectDrawMediaStream_iface;
187 return S_OK;
189 else if (IsEqualGUID(riid, &IID_IPin))
191 IAMMediaStream_AddRef(iface);
192 *ret_iface = &This->IPin_iface;
193 return S_OK;
195 else if (IsEqualGUID(riid, &IID_IMemInputPin))
197 IAMMediaStream_AddRef(iface);
198 *ret_iface = &This->IMemInputPin_iface;
199 return S_OK;
202 ERR("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ret_iface);
203 return E_NOINTERFACE;
206 static ULONG WINAPI ddraw_IAMMediaStream_AddRef(IAMMediaStream *iface)
208 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
209 ULONG ref = InterlockedIncrement(&This->ref);
211 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
213 return ref;
216 static ULONG WINAPI ddraw_IAMMediaStream_Release(IAMMediaStream *iface)
218 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
219 ULONG ref = InterlockedDecrement(&stream->ref);
221 TRACE("%p decreasing refcount to %u.\n", stream, ref);
223 if (!ref)
225 DeleteCriticalSection(&stream->cs);
226 if (stream->ddraw)
227 IDirectDraw_Release(stream->ddraw);
228 HeapFree(GetProcessHeap(), 0, stream);
231 return ref;
234 /*** IMediaStream methods ***/
235 static HRESULT WINAPI ddraw_IAMMediaStream_GetMultiMediaStream(IAMMediaStream *iface,
236 IMultiMediaStream **mmstream)
238 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
240 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
242 if (!mmstream)
243 return E_POINTER;
245 if (stream->parent)
246 IMultiMediaStream_AddRef(stream->parent);
247 *mmstream = stream->parent;
248 return S_OK;
251 static HRESULT WINAPI ddraw_IAMMediaStream_GetInformation(IAMMediaStream *iface,
252 MSPID *purpose_id, STREAM_TYPE *type)
254 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
256 TRACE("(%p/%p)->(%p,%p)\n", This, iface, purpose_id, type);
258 if (purpose_id)
259 *purpose_id = This->purpose_id;
260 if (type)
261 *type = This->stream_type;
263 return S_OK;
266 static HRESULT WINAPI ddraw_IAMMediaStream_SetSameFormat(IAMMediaStream *iface,
267 IMediaStream *pStreamThatHasDesiredFormat, DWORD flags)
269 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
271 FIXME("(%p/%p)->(%p,%x) stub!\n", This, iface, pStreamThatHasDesiredFormat, flags);
273 return S_FALSE;
276 static HRESULT WINAPI ddraw_IAMMediaStream_AllocateSample(IAMMediaStream *iface,
277 DWORD flags, IStreamSample **sample)
279 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
281 FIXME("(%p/%p)->(%x,%p) stub!\n", This, iface, flags, sample);
283 return S_FALSE;
286 static HRESULT WINAPI ddraw_IAMMediaStream_CreateSharedSample(IAMMediaStream *iface,
287 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
289 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
291 FIXME("(%p/%p)->(%p,%x,%p) stub!\n", This, iface, existing_sample, flags, sample);
293 return S_FALSE;
296 static HRESULT WINAPI ddraw_IAMMediaStream_SendEndOfStream(IAMMediaStream *iface, DWORD flags)
298 struct ddraw_stream *This = impl_from_IAMMediaStream(iface);
300 FIXME("(%p/%p)->(%x) stub!\n", This, iface, flags);
302 return S_FALSE;
305 /*** IAMMediaStream methods ***/
306 static HRESULT WINAPI ddraw_IAMMediaStream_Initialize(IAMMediaStream *iface, IUnknown *source_object, DWORD flags,
307 REFMSPID purpose_id, const STREAM_TYPE stream_type)
309 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
310 HRESULT hr;
312 TRACE("stream %p, source_object %p, flags %x, purpose_id %s, stream_type %u.\n", stream, source_object, flags,
313 debugstr_guid(purpose_id), stream_type);
315 if (!purpose_id)
316 return E_POINTER;
318 if (flags & AMMSF_CREATEPEER)
319 FIXME("AMMSF_CREATEPEER is not yet supported.\n");
321 stream->purpose_id = *purpose_id;
322 stream->stream_type = stream_type;
324 if (source_object
325 && FAILED(hr = IUnknown_QueryInterface(source_object, &IID_IDirectDraw, (void **)&stream->ddraw)))
326 FIXME("Stream object doesn't implement IDirectDraw interface, hr %#x.\n", hr);
328 if (!source_object)
330 if (FAILED(hr = DirectDrawCreate(NULL, &stream->ddraw, NULL)))
331 return hr;
332 IDirectDraw_SetCooperativeLevel(stream->ddraw, NULL, DDSCL_NORMAL);
335 return S_OK;
338 static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state)
340 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
342 TRACE("stream %p, state %u.\n", stream, state);
344 EnterCriticalSection(&stream->cs);
346 if (state == State_Stopped)
347 WakeConditionVariable(&stream->update_queued_cv);
348 if (stream->state == State_Stopped)
349 stream->eos = FALSE;
351 stream->state = state;
353 LeaveCriticalSection(&stream->cs);
355 return S_OK;
358 static HRESULT WINAPI ddraw_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface, IAMMultiMediaStream *mmstream)
360 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
362 TRACE("stream %p, mmstream %p.\n", stream, mmstream);
364 stream->parent = (IMultiMediaStream *)mmstream;
366 return S_OK;
369 static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilter(IAMMediaStream *iface, IMediaStreamFilter *filter)
371 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
373 TRACE("iface %p, filter %p.\n", iface, filter);
375 stream->filter = filter;
377 return S_OK;
380 static HRESULT WINAPI ddraw_IAMMediaStream_JoinFilterGraph(IAMMediaStream *iface, IFilterGraph *filtergraph)
382 struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
384 TRACE("stream %p, filtergraph %p.\n", stream, filtergraph);
386 stream->graph = filtergraph;
388 return S_OK;
391 static const struct IAMMediaStreamVtbl ddraw_IAMMediaStream_vtbl =
393 /*** IUnknown methods ***/
394 ddraw_IAMMediaStream_QueryInterface,
395 ddraw_IAMMediaStream_AddRef,
396 ddraw_IAMMediaStream_Release,
397 /*** IMediaStream methods ***/
398 ddraw_IAMMediaStream_GetMultiMediaStream,
399 ddraw_IAMMediaStream_GetInformation,
400 ddraw_IAMMediaStream_SetSameFormat,
401 ddraw_IAMMediaStream_AllocateSample,
402 ddraw_IAMMediaStream_CreateSharedSample,
403 ddraw_IAMMediaStream_SendEndOfStream,
404 /*** IAMMediaStream methods ***/
405 ddraw_IAMMediaStream_Initialize,
406 ddraw_IAMMediaStream_SetState,
407 ddraw_IAMMediaStream_JoinAMMultiMediaStream,
408 ddraw_IAMMediaStream_JoinFilter,
409 ddraw_IAMMediaStream_JoinFilterGraph
412 static inline struct ddraw_stream *impl_from_IDirectDrawMediaStream(IDirectDrawMediaStream *iface)
414 return CONTAINING_RECORD(iface, struct ddraw_stream, IDirectDrawMediaStream_iface);
417 /*** IUnknown methods ***/
418 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_QueryInterface(IDirectDrawMediaStream *iface,
419 REFIID riid, void **ret_iface)
421 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
422 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ret_iface);
423 return IAMMediaStream_QueryInterface(&This->IAMMediaStream_iface, riid, ret_iface);
426 static ULONG WINAPI ddraw_IDirectDrawMediaStream_AddRef(IDirectDrawMediaStream *iface)
428 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
429 TRACE("(%p/%p)\n", iface, This);
430 return IAMMediaStream_AddRef(&This->IAMMediaStream_iface);
433 static ULONG WINAPI ddraw_IDirectDrawMediaStream_Release(IDirectDrawMediaStream *iface)
435 struct ddraw_stream *This = impl_from_IDirectDrawMediaStream(iface);
436 TRACE("(%p/%p)\n", iface, This);
437 return IAMMediaStream_Release(&This->IAMMediaStream_iface);
440 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetMultiMediaStream(IDirectDrawMediaStream *iface,
441 IMultiMediaStream **mmstream)
443 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
444 return IAMMediaStream_GetMultiMediaStream(&stream->IAMMediaStream_iface, mmstream);
447 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetInformation(IDirectDrawMediaStream *iface,
448 MSPID *purpose_id, STREAM_TYPE *type)
450 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
451 return IAMMediaStream_GetInformation(&stream->IAMMediaStream_iface, purpose_id, type);
454 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetSameFormat(IDirectDrawMediaStream *iface,
455 IMediaStream *other, DWORD flags)
457 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
458 return IAMMediaStream_SetSameFormat(&stream->IAMMediaStream_iface, other, flags);
461 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_AllocateSample(IDirectDrawMediaStream *iface,
462 DWORD flags, IStreamSample **sample)
464 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
465 return IAMMediaStream_AllocateSample(&stream->IAMMediaStream_iface, flags, sample);
468 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSharedSample(IDirectDrawMediaStream *iface,
469 IStreamSample *existing_sample, DWORD flags, IStreamSample **sample)
471 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
472 return IAMMediaStream_CreateSharedSample(&stream->IAMMediaStream_iface, existing_sample, flags, sample);
475 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SendEndOfStream(IDirectDrawMediaStream *iface, DWORD flags)
477 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
478 return IAMMediaStream_SendEndOfStream(&stream->IAMMediaStream_iface, flags);
481 /*** IDirectDrawMediaStream methods ***/
482 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetFormat(IDirectDrawMediaStream *iface,
483 DDSURFACEDESC *current_format, IDirectDrawPalette **palette,
484 DDSURFACEDESC *desired_format, DWORD *flags)
486 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
488 TRACE("stream %p, current_format %p, palette %p, desired_format %p, flags %p.\n", stream, current_format, palette,
489 desired_format, flags);
491 EnterCriticalSection(&stream->cs);
493 if (!stream->peer)
495 LeaveCriticalSection(&stream->cs);
496 return MS_E_NOSTREAM;
499 if (current_format)
501 current_format->dwFlags = stream->format.flags | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
502 current_format->dwWidth = stream->format.width;
503 current_format->dwHeight = stream->format.height;
504 current_format->ddpfPixelFormat = stream->format.pf;
505 current_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
508 if (palette)
509 *palette = NULL;
511 if (desired_format)
513 desired_format->dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
514 desired_format->dwWidth = stream->format.width;
515 desired_format->dwHeight = stream->format.height;
516 desired_format->ddpfPixelFormat = stream->format.pf;
517 desired_format->ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
520 if (flags)
521 *flags = 0;
523 LeaveCriticalSection(&stream->cs);
525 return S_OK;
528 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetFormat(IDirectDrawMediaStream *iface,
529 const DDSURFACEDESC *format, IDirectDrawPalette *palette)
531 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
532 AM_MEDIA_TYPE old_media_type;
533 struct format old_format;
534 IPin *old_peer;
535 HRESULT hr;
537 TRACE("stream %p, format %p, palette %p.\n", stream, format, palette);
539 if (palette)
540 FIXME("Setting palette is not yet supported.\n");
542 if (!format)
543 return E_POINTER;
545 if (format->dwSize != sizeof(DDSURFACEDESC))
546 return E_INVALIDARG;
548 if (format->dwFlags & DDSD_PIXELFORMAT)
550 if (format->ddpfPixelFormat.dwSize != sizeof(DDPIXELFORMAT))
551 return DDERR_INVALIDSURFACETYPE;
553 if (format->ddpfPixelFormat.dwFlags & DDPF_FOURCC)
555 if (!format->ddpfPixelFormat.u1.dwRGBBitCount)
556 return E_INVALIDARG;
558 else
560 if (format->ddpfPixelFormat.dwFlags & (DDPF_YUV | DDPF_PALETTEINDEXED1 |
561 DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXEDTO8))
562 return DDERR_INVALIDSURFACETYPE;
564 if (!(format->ddpfPixelFormat.dwFlags & DDPF_RGB))
565 return DDERR_INVALIDSURFACETYPE;
567 switch (format->ddpfPixelFormat.u1.dwRGBBitCount)
569 case 8:
570 if (!(format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8))
571 return DDERR_INVALIDSURFACETYPE;
572 break;
573 case 16:
574 if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
575 return DDERR_INVALIDSURFACETYPE;
576 if ((format->ddpfPixelFormat.u2.dwRBitMask != 0x7c00 ||
577 format->ddpfPixelFormat.u3.dwGBitMask != 0x03e0 ||
578 format->ddpfPixelFormat.u4.dwBBitMask != 0x001f) &&
579 (format->ddpfPixelFormat.u2.dwRBitMask != 0xf800 ||
580 format->ddpfPixelFormat.u3.dwGBitMask != 0x07e0 ||
581 format->ddpfPixelFormat.u4.dwBBitMask != 0x001f))
582 return DDERR_INVALIDSURFACETYPE;
583 break;
584 case 24:
585 case 32:
586 if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
587 return DDERR_INVALIDSURFACETYPE;
588 if (format->ddpfPixelFormat.u2.dwRBitMask != 0xff0000 ||
589 format->ddpfPixelFormat.u3.dwGBitMask != 0x00ff00 ||
590 format->ddpfPixelFormat.u4.dwBBitMask != 0x0000ff)
591 return DDERR_INVALIDSURFACETYPE;
592 break;
593 default:
594 return DDERR_INVALIDSURFACETYPE;
599 EnterCriticalSection(&stream->cs);
601 old_format = stream->format;
602 stream->format.flags = format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
603 if (format->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT))
605 stream->format.width = format->dwWidth;
606 stream->format.height = format->dwHeight;
608 if (format->dwFlags & DDSD_PIXELFORMAT)
609 stream->format.pf = format->ddpfPixelFormat;
611 if (stream->peer && !is_format_compatible(stream, old_format.width, old_format.height, &old_format.pf))
613 hr = CopyMediaType(&old_media_type, &stream->mt);
614 if (FAILED(hr))
616 stream->format = old_format;
617 LeaveCriticalSection(&stream->cs);
618 return hr;
620 old_peer = stream->peer;
621 IPin_AddRef(old_peer);
623 IFilterGraph_Disconnect(stream->graph, stream->peer);
624 IFilterGraph_Disconnect(stream->graph, &stream->IPin_iface);
625 hr = IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, NULL);
626 if (FAILED(hr))
628 stream->format = old_format;
629 IFilterGraph_ConnectDirect(stream->graph, old_peer, &stream->IPin_iface, &old_media_type);
630 IPin_Release(old_peer);
631 FreeMediaType(&old_media_type);
632 LeaveCriticalSection(&stream->cs);
633 return DDERR_INVALIDSURFACETYPE;
636 IPin_Release(old_peer);
637 FreeMediaType(&old_media_type);
640 LeaveCriticalSection(&stream->cs);
642 return S_OK;
645 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetDirectDraw(IDirectDrawMediaStream *iface,
646 IDirectDraw **ddraw)
648 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
650 TRACE("stream %p, ddraw %p.\n", stream, ddraw);
652 if (!ddraw)
653 return E_POINTER;
655 if (!stream->ddraw)
657 *ddraw = NULL;
658 return S_OK;
661 IDirectDraw_AddRef(stream->ddraw);
662 *ddraw = stream->ddraw;
664 return S_OK;
667 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_SetDirectDraw(IDirectDrawMediaStream *iface,
668 IDirectDraw *ddraw)
670 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
672 TRACE("stream %p, ddraw %p.\n", stream, ddraw);
674 EnterCriticalSection(&stream->cs);
676 if (stream->sample_refs)
678 HRESULT hr = (stream->ddraw == ddraw) ? S_OK : MS_E_SAMPLEALLOC;
679 LeaveCriticalSection(&stream->cs);
680 return hr;
683 if (stream->ddraw)
684 IDirectDraw_Release(stream->ddraw);
686 if (ddraw)
688 IDirectDraw_AddRef(ddraw);
689 stream->ddraw = ddraw;
691 else
692 stream->ddraw = NULL;
694 LeaveCriticalSection(&stream->cs);
696 return S_OK;
699 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_CreateSample(IDirectDrawMediaStream *iface,
700 IDirectDrawSurface *surface, const RECT *rect, DWORD flags,
701 IDirectDrawStreamSample **sample)
703 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
704 HRESULT hr;
706 TRACE("stream %p, surface %p, rect %s, flags %#x, sample %p.\n",
707 stream, surface, wine_dbgstr_rect(rect), flags, sample);
709 if (!surface && rect)
710 return E_INVALIDARG;
712 EnterCriticalSection(&stream->cs);
713 hr = ddrawstreamsample_create(stream, surface, rect, sample);
714 LeaveCriticalSection(&stream->cs);
716 return hr;
719 static HRESULT WINAPI ddraw_IDirectDrawMediaStream_GetTimePerFrame(IDirectDrawMediaStream *iface,
720 STREAM_TIME *frame_time)
722 struct ddraw_stream *stream = impl_from_IDirectDrawMediaStream(iface);
724 TRACE("stream %p, frame_time %p.\n", stream, frame_time);
726 if (!frame_time)
727 return E_POINTER;
729 EnterCriticalSection(&stream->cs);
731 if (!stream->peer)
733 LeaveCriticalSection(&stream->cs);
734 return MS_E_NOSTREAM;
737 *frame_time = ((VIDEOINFO *)stream->mt.pbFormat)->AvgTimePerFrame;
739 LeaveCriticalSection(&stream->cs);
741 return S_OK;
744 static const struct IDirectDrawMediaStreamVtbl ddraw_IDirectDrawMediaStream_Vtbl =
746 /*** IUnknown methods ***/
747 ddraw_IDirectDrawMediaStream_QueryInterface,
748 ddraw_IDirectDrawMediaStream_AddRef,
749 ddraw_IDirectDrawMediaStream_Release,
750 /*** IMediaStream methods ***/
751 ddraw_IDirectDrawMediaStream_GetMultiMediaStream,
752 ddraw_IDirectDrawMediaStream_GetInformation,
753 ddraw_IDirectDrawMediaStream_SetSameFormat,
754 ddraw_IDirectDrawMediaStream_AllocateSample,
755 ddraw_IDirectDrawMediaStream_CreateSharedSample,
756 ddraw_IDirectDrawMediaStream_SendEndOfStream,
757 /*** IDirectDrawMediaStream methods ***/
758 ddraw_IDirectDrawMediaStream_GetFormat,
759 ddraw_IDirectDrawMediaStream_SetFormat,
760 ddraw_IDirectDrawMediaStream_GetDirectDraw,
761 ddraw_IDirectDrawMediaStream_SetDirectDraw,
762 ddraw_IDirectDrawMediaStream_CreateSample,
763 ddraw_IDirectDrawMediaStream_GetTimePerFrame
766 struct enum_media_types
768 IEnumMediaTypes IEnumMediaTypes_iface;
769 LONG refcount;
770 unsigned int index;
773 static const IEnumMediaTypesVtbl enum_media_types_vtbl;
775 static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
777 return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
780 static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
782 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
784 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
786 IEnumMediaTypes_AddRef(iface);
787 *out = iface;
788 return S_OK;
791 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
792 *out = NULL;
793 return E_NOINTERFACE;
796 static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
798 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
799 ULONG refcount = InterlockedIncrement(&enum_media_types->refcount);
800 TRACE("%p increasing refcount to %u.\n", enum_media_types, refcount);
801 return refcount;
804 static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
806 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
807 ULONG refcount = InterlockedDecrement(&enum_media_types->refcount);
808 TRACE("%p decreasing refcount to %u.\n", enum_media_types, refcount);
809 if (!refcount)
810 heap_free(enum_media_types);
811 return refcount;
814 static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count, AM_MEDIA_TYPE **mts, ULONG *ret_count)
816 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
818 TRACE("iface %p, count %u, mts %p, ret_count %p.\n", iface, count, mts, ret_count);
820 if (!ret_count)
821 return E_POINTER;
823 if (count && !enum_media_types->index)
825 mts[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
826 memset(mts[0], 0, sizeof(AM_MEDIA_TYPE));
827 mts[0]->majortype = MEDIATYPE_Video;
828 mts[0]->subtype = MEDIASUBTYPE_RGB8;
829 mts[0]->bFixedSizeSamples = TRUE;
830 mts[0]->lSampleSize = 10000;
831 ++enum_media_types->index;
832 *ret_count = 1;
833 return count == 1 ? S_OK : S_FALSE;
836 *ret_count = 0;
837 return count ? S_FALSE : S_OK;
840 static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
842 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
844 TRACE("iface %p, count %u.\n", iface, count);
846 enum_media_types->index += count;
848 return S_OK;
851 static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
853 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
855 TRACE("iface %p.\n", iface);
857 enum_media_types->index = 0;
858 return S_OK;
861 static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
863 struct enum_media_types *enum_media_types = impl_from_IEnumMediaTypes(iface);
864 struct enum_media_types *object;
866 TRACE("iface %p, out %p.\n", iface, out);
868 if (!(object = heap_alloc(sizeof(*object))))
869 return E_OUTOFMEMORY;
871 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
872 object->refcount = 1;
873 object->index = enum_media_types->index;
875 *out = &object->IEnumMediaTypes_iface;
876 return S_OK;
879 static const IEnumMediaTypesVtbl enum_media_types_vtbl =
881 enum_media_types_QueryInterface,
882 enum_media_types_AddRef,
883 enum_media_types_Release,
884 enum_media_types_Next,
885 enum_media_types_Skip,
886 enum_media_types_Reset,
887 enum_media_types_Clone,
890 static inline struct ddraw_stream *impl_from_IPin(IPin *iface)
892 return CONTAINING_RECORD(iface, struct ddraw_stream, IPin_iface);
895 static HRESULT WINAPI ddraw_sink_QueryInterface(IPin *iface, REFIID iid, void **out)
897 struct ddraw_stream *stream = impl_from_IPin(iface);
898 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
901 static ULONG WINAPI ddraw_sink_AddRef(IPin *iface)
903 struct ddraw_stream *stream = impl_from_IPin(iface);
904 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
907 static ULONG WINAPI ddraw_sink_Release(IPin *iface)
909 struct ddraw_stream *stream = impl_from_IPin(iface);
910 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
913 static HRESULT WINAPI ddraw_sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
915 WARN("iface %p, peer %p, mt %p, unexpected call!\n", iface, peer, mt);
916 return E_UNEXPECTED;
919 static HRESULT WINAPI ddraw_sink_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
921 struct ddraw_stream *stream = impl_from_IPin(iface);
922 const VIDEOINFOHEADER *video_info;
923 PIN_DIRECTION dir;
924 DWORD width;
925 DWORD height;
926 DDPIXELFORMAT pf = {sizeof(DDPIXELFORMAT)};
928 TRACE("stream %p, peer %p, mt %p.\n", stream, peer, mt);
930 EnterCriticalSection(&stream->cs);
932 if (stream->peer)
934 LeaveCriticalSection(&stream->cs);
935 return VFW_E_ALREADY_CONNECTED;
938 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
939 || !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
941 LeaveCriticalSection(&stream->cs);
942 return VFW_E_TYPE_NOT_ACCEPTED;
945 video_info = (const VIDEOINFOHEADER *)mt->pbFormat;
947 width = video_info->bmiHeader.biWidth;
948 height = abs(video_info->bmiHeader.biHeight);
949 pf.dwFlags = DDPF_RGB;
950 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8))
952 pf.dwFlags |= DDPF_PALETTEINDEXED8;
953 pf.u1.dwRGBBitCount = 8;
955 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB555))
957 pf.u1.dwRGBBitCount = 16;
958 pf.u2.dwRBitMask = 0x7c00;
959 pf.u3.dwGBitMask = 0x03e0;
960 pf.u4.dwBBitMask = 0x001f;
962 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB565))
964 pf.u1.dwRGBBitCount = 16;
965 pf.u2.dwRBitMask = 0xf800;
966 pf.u3.dwGBitMask = 0x07e0;
967 pf.u4.dwBBitMask = 0x001f;
969 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB24))
971 pf.u1.dwRGBBitCount = 24;
972 pf.u2.dwRBitMask = 0xff0000;
973 pf.u3.dwGBitMask = 0x00ff00;
974 pf.u4.dwBBitMask = 0x0000ff;
976 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB32))
978 pf.u1.dwRGBBitCount = 32;
979 pf.u2.dwRBitMask = 0xff0000;
980 pf.u3.dwGBitMask = 0x00ff00;
981 pf.u4.dwBBitMask = 0x0000ff;
983 else
985 LeaveCriticalSection(&stream->cs);
986 return VFW_E_TYPE_NOT_ACCEPTED;
989 if (!is_format_compatible(stream, width, height, &pf))
991 LeaveCriticalSection(&stream->cs);
992 return VFW_E_TYPE_NOT_ACCEPTED;
995 IPin_QueryDirection(peer, &dir);
996 if (dir != PINDIR_OUTPUT)
998 WARN("Rejecting connection from input pin.\n");
999 LeaveCriticalSection(&stream->cs);
1000 return VFW_E_INVALID_DIRECTION;
1003 CopyMediaType(&stream->mt, mt);
1004 IPin_AddRef(stream->peer = peer);
1006 stream->format.width = width;
1007 stream->format.height = height;
1008 if (!(stream->format.flags & DDSD_PIXELFORMAT))
1009 stream->format.pf = pf;
1011 LeaveCriticalSection(&stream->cs);
1013 return S_OK;
1016 static HRESULT WINAPI ddraw_sink_Disconnect(IPin *iface)
1018 struct ddraw_stream *stream = impl_from_IPin(iface);
1020 TRACE("stream %p.\n", stream);
1022 EnterCriticalSection(&stream->cs);
1024 if (!stream->peer)
1026 LeaveCriticalSection(&stream->cs);
1027 return S_FALSE;
1030 IPin_Release(stream->peer);
1031 stream->peer = NULL;
1032 FreeMediaType(&stream->mt);
1033 memset(&stream->mt, 0, sizeof(AM_MEDIA_TYPE));
1035 LeaveCriticalSection(&stream->cs);
1037 return S_OK;
1040 static HRESULT WINAPI ddraw_sink_ConnectedTo(IPin *iface, IPin **peer)
1042 struct ddraw_stream *stream = impl_from_IPin(iface);
1043 HRESULT hr;
1045 TRACE("stream %p, peer %p.\n", stream, peer);
1047 EnterCriticalSection(&stream->cs);
1049 if (stream->peer)
1051 IPin_AddRef(*peer = stream->peer);
1052 hr = S_OK;
1054 else
1056 *peer = NULL;
1057 hr = VFW_E_NOT_CONNECTED;
1060 LeaveCriticalSection(&stream->cs);
1062 return hr;
1065 static HRESULT WINAPI ddraw_sink_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mt)
1067 struct ddraw_stream *stream = impl_from_IPin(iface);
1068 HRESULT hr;
1070 TRACE("stream %p, mt %p.\n", stream, mt);
1072 EnterCriticalSection(&stream->cs);
1074 if (stream->peer)
1076 CopyMediaType(mt, &stream->mt);
1077 hr = S_OK;
1079 else
1081 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1082 hr = VFW_E_NOT_CONNECTED;
1085 LeaveCriticalSection(&stream->cs);
1087 return hr;
1090 static HRESULT WINAPI ddraw_sink_QueryPinInfo(IPin *iface, PIN_INFO *info)
1092 struct ddraw_stream *stream = impl_from_IPin(iface);
1094 TRACE("stream %p, info %p.\n", stream, info);
1096 IBaseFilter_AddRef(info->pFilter = (IBaseFilter *)stream->filter);
1097 info->dir = PINDIR_INPUT;
1098 wcscpy(info->achName, sink_id);
1100 return S_OK;
1103 static HRESULT WINAPI ddraw_sink_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1105 TRACE("iface %p, dir %p.\n", iface, dir);
1106 *dir = PINDIR_INPUT;
1107 return S_OK;
1110 static HRESULT WINAPI ddraw_sink_QueryId(IPin *iface, WCHAR **id)
1112 TRACE("iface %p, id %p.\n", iface, id);
1114 if (!(*id = CoTaskMemAlloc(sizeof(sink_id))))
1115 return E_OUTOFMEMORY;
1117 wcscpy(*id, sink_id);
1119 return S_OK;
1122 static HRESULT WINAPI ddraw_sink_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
1124 TRACE("iface %p, mt %p.\n", iface, mt);
1126 if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video)
1127 && IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8)
1128 && IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
1129 return S_OK;
1131 return VFW_E_TYPE_NOT_ACCEPTED;
1134 static HRESULT WINAPI ddraw_sink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
1136 struct enum_media_types *object;
1138 TRACE("iface %p, enum_media_types %p.\n", iface, enum_media_types);
1140 if (!enum_media_types)
1141 return E_POINTER;
1143 if (!(object = heap_alloc(sizeof(*object))))
1144 return E_OUTOFMEMORY;
1146 object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
1147 object->refcount = 1;
1148 object->index = 0;
1150 *enum_media_types = &object->IEnumMediaTypes_iface;
1151 return S_OK;
1154 static HRESULT WINAPI ddraw_sink_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
1156 TRACE("iface %p, pins %p, count %p.\n", iface, pins, count);
1157 return E_NOTIMPL;
1160 static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
1162 struct ddraw_stream *stream = impl_from_IPin(iface);
1164 TRACE("stream %p.\n", stream);
1166 EnterCriticalSection(&stream->cs);
1168 if (stream->eos || stream->flushing)
1170 LeaveCriticalSection(&stream->cs);
1171 return E_FAIL;
1174 stream->eos = TRUE;
1176 flush_update_queue(stream, MS_S_ENDOFSTREAM);
1178 LeaveCriticalSection(&stream->cs);
1180 return S_OK;
1183 static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface)
1185 struct ddraw_stream *stream = impl_from_IPin(iface);
1187 TRACE("stream %p.\n", stream);
1189 EnterCriticalSection(&stream->cs);
1191 stream->flushing = TRUE;
1192 stream->eos = FALSE;
1193 WakeConditionVariable(&stream->update_queued_cv);
1195 LeaveCriticalSection(&stream->cs);
1197 return S_OK;
1200 static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface)
1202 struct ddraw_stream *stream = impl_from_IPin(iface);
1204 TRACE("stream %p.\n", stream);
1206 EnterCriticalSection(&stream->cs);
1208 stream->flushing = FALSE;
1210 LeaveCriticalSection(&stream->cs);
1212 return S_OK;
1215 static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
1217 struct ddraw_stream *stream = impl_from_IPin(iface);
1219 TRACE("stream %p, start %s, stop %s, rate %0.16e\n",
1220 stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate);
1222 EnterCriticalSection(&stream->cs);
1224 stream->segment_start = start;
1226 LeaveCriticalSection(&stream->cs);
1228 return S_OK;
1231 static const IPinVtbl ddraw_sink_vtbl =
1233 ddraw_sink_QueryInterface,
1234 ddraw_sink_AddRef,
1235 ddraw_sink_Release,
1236 ddraw_sink_Connect,
1237 ddraw_sink_ReceiveConnection,
1238 ddraw_sink_Disconnect,
1239 ddraw_sink_ConnectedTo,
1240 ddraw_sink_ConnectionMediaType,
1241 ddraw_sink_QueryPinInfo,
1242 ddraw_sink_QueryDirection,
1243 ddraw_sink_QueryId,
1244 ddraw_sink_QueryAccept,
1245 ddraw_sink_EnumMediaTypes,
1246 ddraw_sink_QueryInternalConnections,
1247 ddraw_sink_EndOfStream,
1248 ddraw_sink_BeginFlush,
1249 ddraw_sink_EndFlush,
1250 ddraw_sink_NewSegment,
1253 static inline struct ddraw_stream *impl_from_IMemInputPin(IMemInputPin *iface)
1255 return CONTAINING_RECORD(iface, struct ddraw_stream, IMemInputPin_iface);
1258 static HRESULT WINAPI ddraw_meminput_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
1260 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1261 return IAMMediaStream_QueryInterface(&stream->IAMMediaStream_iface, iid, out);
1264 static ULONG WINAPI ddraw_meminput_AddRef(IMemInputPin *iface)
1266 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1267 return IAMMediaStream_AddRef(&stream->IAMMediaStream_iface);
1270 static ULONG WINAPI ddraw_meminput_Release(IMemInputPin *iface)
1272 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1273 return IAMMediaStream_Release(&stream->IAMMediaStream_iface);
1276 static HRESULT WINAPI ddraw_meminput_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
1278 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1280 TRACE("stream %p, allocator %p.\n", stream, allocator);
1282 if (stream->allocator)
1284 IMemAllocator_AddRef(*allocator = stream->allocator);
1285 return S_OK;
1288 *allocator = NULL;
1289 return VFW_E_NO_ALLOCATOR;
1292 static HRESULT WINAPI ddraw_meminput_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readonly)
1294 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1296 TRACE("stream %p, allocator %p, readonly %d.\n", stream, allocator, readonly);
1298 if (!allocator)
1299 return E_POINTER;
1301 if (allocator)
1302 IMemAllocator_AddRef(allocator);
1303 if (stream->allocator)
1304 IMemAllocator_Release(stream->allocator);
1305 stream->allocator = allocator;
1307 return S_OK;
1310 static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1312 TRACE("iface %p, props %p.\n", iface, props);
1313 return E_NOTIMPL;
1316 static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *sample)
1318 struct ddraw_stream *stream = impl_from_IMemInputPin(iface);
1319 BITMAPINFOHEADER *bitmap_info;
1320 REFERENCE_TIME start_time = 0;
1321 REFERENCE_TIME end_time = 0;
1322 STREAM_TIME start_stream_time;
1323 STREAM_TIME end_stream_time;
1324 IMediaStreamFilter *filter;
1325 STREAM_TIME current_time;
1326 BYTE *top_down_pointer;
1327 int top_down_stride;
1328 BYTE *pointer;
1329 BOOL top_down;
1330 int stride;
1331 HRESULT hr;
1333 TRACE("stream %p, sample %p.\n", stream, sample);
1335 hr = IMediaSample_GetPointer(sample, &pointer);
1336 if (FAILED(hr))
1337 return hr;
1339 IMediaSample_GetTime(sample, &start_time, &end_time);
1341 EnterCriticalSection(&stream->cs);
1343 if (stream->state == State_Stopped)
1345 LeaveCriticalSection(&stream->cs);
1346 return S_OK;
1348 if (stream->flushing)
1350 LeaveCriticalSection(&stream->cs);
1351 return S_FALSE;
1354 bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader;
1356 stride = ((bitmap_info->biWidth * bitmap_info->biBitCount + 31) & ~31) / 8;
1357 top_down = (bitmap_info->biHeight < 0);
1359 top_down_stride = top_down ? stride : -stride;
1360 top_down_pointer = top_down ? pointer : pointer + stride * (bitmap_info->biHeight - 1);
1362 start_stream_time = start_time + stream->segment_start;
1363 end_stream_time = end_time + stream->segment_start;
1365 filter = stream->filter;
1367 LeaveCriticalSection(&stream->cs);
1368 if (S_OK == IMediaStreamFilter_GetCurrentStreamTime(filter, &current_time)
1369 && start_time >= current_time + 10000)
1370 IMediaStreamFilter_WaitUntil(filter, start_time);
1371 EnterCriticalSection(&stream->cs);
1373 for (;;)
1375 if (stream->state == State_Stopped)
1377 LeaveCriticalSection(&stream->cs);
1378 return S_OK;
1380 if (stream->flushing)
1382 LeaveCriticalSection(&stream->cs);
1383 return S_FALSE;
1385 if (!list_empty(&stream->update_queue))
1387 struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
1389 sample->update_hr = process_update(sample, top_down_stride, top_down_pointer,
1390 start_stream_time, end_stream_time);
1392 if (sample->continuous_update && SUCCEEDED(sample->update_hr))
1394 list_remove(&sample->entry);
1395 list_add_tail(&sample->parent->update_queue, &sample->entry);
1397 else
1399 remove_queued_update(sample);
1401 LeaveCriticalSection(&stream->cs);
1402 return S_OK;
1405 SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE);
1409 static HRESULT WINAPI ddraw_meminput_ReceiveMultiple(IMemInputPin *iface,
1410 IMediaSample **samples, LONG count, LONG *processed)
1412 FIXME("iface %p, samples %p, count %u, processed %p, stub!\n", iface, samples, count, processed);
1413 return E_NOTIMPL;
1416 static HRESULT WINAPI ddraw_meminput_ReceiveCanBlock(IMemInputPin *iface)
1418 TRACE("iface %p.\n", iface);
1419 return S_OK;
1422 static const IMemInputPinVtbl ddraw_meminput_vtbl =
1424 ddraw_meminput_QueryInterface,
1425 ddraw_meminput_AddRef,
1426 ddraw_meminput_Release,
1427 ddraw_meminput_GetAllocator,
1428 ddraw_meminput_NotifyAllocator,
1429 ddraw_meminput_GetAllocatorRequirements,
1430 ddraw_meminput_Receive,
1431 ddraw_meminput_ReceiveMultiple,
1432 ddraw_meminput_ReceiveCanBlock,
1435 HRESULT ddraw_stream_create(IUnknown *outer, void **out)
1437 struct ddraw_stream *object;
1439 if (outer)
1440 return CLASS_E_NOAGGREGATION;
1442 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1443 if (!object)
1444 return E_OUTOFMEMORY;
1446 object->IAMMediaStream_iface.lpVtbl = &ddraw_IAMMediaStream_vtbl;
1447 object->IDirectDrawMediaStream_iface.lpVtbl = &ddraw_IDirectDrawMediaStream_Vtbl;
1448 object->IMemInputPin_iface.lpVtbl = &ddraw_meminput_vtbl;
1449 object->IPin_iface.lpVtbl = &ddraw_sink_vtbl;
1450 object->ref = 1;
1452 object->format.width = 100;
1453 object->format.height = 100;
1455 InitializeCriticalSection(&object->cs);
1456 InitializeConditionVariable(&object->update_queued_cv);
1457 list_init(&object->update_queue);
1459 TRACE("Created ddraw stream %p.\n", object);
1461 *out = &object->IAMMediaStream_iface;
1463 return S_OK;
1466 static inline struct ddraw_sample *impl_from_IDirectDrawStreamSample(IDirectDrawStreamSample *iface)
1468 return CONTAINING_RECORD(iface, struct ddraw_sample, IDirectDrawStreamSample_iface);
1471 /*** IUnknown methods ***/
1472 static HRESULT WINAPI ddraw_sample_QueryInterface(IDirectDrawStreamSample *iface,
1473 REFIID riid, void **ret_iface)
1475 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ret_iface);
1477 if (IsEqualGUID(riid, &IID_IUnknown) ||
1478 IsEqualGUID(riid, &IID_IStreamSample) ||
1479 IsEqualGUID(riid, &IID_IDirectDrawStreamSample))
1481 IDirectDrawStreamSample_AddRef(iface);
1482 *ret_iface = iface;
1483 return S_OK;
1486 *ret_iface = NULL;
1488 ERR("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ret_iface);
1489 return E_NOINTERFACE;
1492 static ULONG WINAPI ddraw_sample_AddRef(IDirectDrawStreamSample *iface)
1494 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1495 ULONG ref = InterlockedIncrement(&sample->ref);
1497 TRACE("(%p)->(): new ref = %u\n", iface, ref);
1499 return ref;
1502 static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
1504 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1505 ULONG ref = InterlockedDecrement(&sample->ref);
1507 TRACE("(%p)->(): new ref = %u\n", iface, ref);
1509 if (!ref)
1511 EnterCriticalSection(&sample->parent->cs);
1512 --sample->parent->sample_refs;
1513 LeaveCriticalSection(&sample->parent->cs);
1515 if (sample->mmstream)
1516 IMultiMediaStream_Release(sample->mmstream);
1517 IAMMediaStream_Release(&sample->parent->IAMMediaStream_iface);
1519 if (sample->surface)
1520 IDirectDrawSurface_Release(sample->surface);
1521 HeapFree(GetProcessHeap(), 0, sample);
1524 return ref;
1527 /*** IStreamSample methods ***/
1528 static HRESULT WINAPI ddraw_sample_GetMediaStream(IDirectDrawStreamSample *iface, IMediaStream **media_stream)
1530 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1532 TRACE("sample %p, media_stream %p.\n", sample, media_stream);
1534 if (!media_stream)
1535 return E_POINTER;
1537 IAMMediaStream_AddRef(&sample->parent->IAMMediaStream_iface);
1538 *media_stream = (IMediaStream *)&sample->parent->IAMMediaStream_iface;
1540 return S_OK;
1543 static HRESULT WINAPI ddraw_sample_GetSampleTimes(IDirectDrawStreamSample *iface, STREAM_TIME *start_time,
1544 STREAM_TIME *end_time, STREAM_TIME *current_time)
1546 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1548 TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time);
1550 if (current_time)
1551 IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time);
1553 if (start_time)
1554 *start_time = sample->start_time;
1555 if (end_time)
1556 *end_time = sample->end_time;
1558 return S_OK;
1561 static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface, const STREAM_TIME *start_time,
1562 const STREAM_TIME *end_time)
1564 FIXME("(%p)->(%p,%p): stub\n", iface, start_time, end_time);
1566 return E_NOTIMPL;
1569 static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
1570 DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data)
1572 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1574 TRACE("sample %p, flags %#x, event %p, apc_func %p, apc_data %#x.\n",
1575 sample, flags, event, apc_func, apc_data);
1577 if (event && apc_func)
1578 return E_INVALIDARG;
1580 if (apc_func)
1582 FIXME("APC support is not implemented!\n");
1583 return E_NOTIMPL;
1586 if (event)
1588 FIXME("Event parameter support is not implemented!\n");
1589 return E_NOTIMPL;
1592 EnterCriticalSection(&sample->parent->cs);
1594 if (sample->parent->state != State_Running)
1596 LeaveCriticalSection(&sample->parent->cs);
1597 return MS_E_NOTRUNNING;
1599 if (!sample->parent->peer || sample->parent->eos)
1601 sample->update_hr = MS_S_ENDOFSTREAM;
1602 LeaveCriticalSection(&sample->parent->cs);
1603 return MS_S_ENDOFSTREAM;
1605 if (sample->busy)
1607 LeaveCriticalSection(&sample->parent->cs);
1608 return MS_E_BUSY;
1611 sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
1613 sample->update_hr = MS_S_NOUPDATE;
1614 sample->busy = TRUE;
1615 list_add_tail(&sample->parent->update_queue, &sample->entry);
1616 WakeConditionVariable(&sample->parent->update_queued_cv);
1618 if (flags & SSUPDATE_ASYNC)
1620 LeaveCriticalSection(&sample->parent->cs);
1621 return MS_S_PENDING;
1624 while (sample->busy)
1625 SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
1627 LeaveCriticalSection(&sample->parent->cs);
1629 return sample->update_hr;
1632 static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds)
1634 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1635 HRESULT hr;
1637 TRACE("sample %p, flags %#x, milliseconds %u.\n", sample, flags, milliseconds);
1639 EnterCriticalSection(&sample->parent->cs);
1641 if (sample->busy)
1643 if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
1645 remove_queued_update(sample);
1647 else if (flags & COMPSTAT_WAIT)
1649 DWORD start_time = GetTickCount();
1650 DWORD elapsed = 0;
1651 sample->continuous_update = FALSE;
1652 while (sample->busy && elapsed < milliseconds)
1654 DWORD sleep_time = milliseconds - elapsed;
1655 if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
1656 break;
1657 elapsed = GetTickCount() - start_time;
1662 hr = sample->busy ? MS_S_PENDING : sample->update_hr;
1664 LeaveCriticalSection(&sample->parent->cs);
1666 return hr;
1669 /*** IDirectDrawStreamSample methods ***/
1670 static HRESULT WINAPI ddraw_sample_GetSurface(IDirectDrawStreamSample *iface, IDirectDrawSurface **ddraw_surface,
1671 RECT *rect)
1673 struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
1675 TRACE("(%p)->(%p,%p)\n", iface, ddraw_surface, rect);
1677 if (ddraw_surface)
1679 *ddraw_surface = sample->surface;
1680 if (*ddraw_surface)
1681 IDirectDrawSurface_AddRef(*ddraw_surface);
1684 if (rect)
1685 *rect = sample->rect;
1687 return S_OK;
1690 static HRESULT WINAPI ddraw_sample_SetRect(IDirectDrawStreamSample *iface, const RECT *rect)
1692 FIXME("(%p)->(%p): stub\n", iface, rect);
1694 return E_NOTIMPL;
1697 static const struct IDirectDrawStreamSampleVtbl DirectDrawStreamSample_Vtbl =
1699 /*** IUnknown methods ***/
1700 ddraw_sample_QueryInterface,
1701 ddraw_sample_AddRef,
1702 ddraw_sample_Release,
1703 /*** IStreamSample methods ***/
1704 ddraw_sample_GetMediaStream,
1705 ddraw_sample_GetSampleTimes,
1706 ddraw_sample_SetSampleTimes,
1707 ddraw_sample_Update,
1708 ddraw_sample_CompletionStatus,
1709 /*** IDirectDrawStreamSample methods ***/
1710 ddraw_sample_GetSurface,
1711 ddraw_sample_SetRect
1714 static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
1715 const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample)
1717 struct ddraw_sample *object;
1718 DDSURFACEDESC desc;
1719 HRESULT hr;
1721 TRACE("(%p)\n", ddraw_stream_sample);
1723 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1724 if (!object)
1725 return E_OUTOFMEMORY;
1727 object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl;
1728 object->ref = 1;
1729 object->parent = parent;
1730 object->mmstream = parent->parent;
1731 InitializeConditionVariable(&object->update_cv);
1732 IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
1733 if (object->mmstream)
1734 IMultiMediaStream_AddRef(object->mmstream);
1735 ++parent->sample_refs;
1737 if (surface)
1739 object->surface = surface;
1740 IDirectDrawSurface_AddRef(surface);
1742 else
1744 IDirectDraw *ddraw;
1746 hr = IDirectDrawMediaStream_GetDirectDraw(&parent->IDirectDrawMediaStream_iface, &ddraw);
1747 if (FAILED(hr))
1749 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1750 return hr;
1753 desc.dwSize = sizeof(desc);
1754 desc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;
1755 desc.dwHeight = parent->format.height;
1756 desc.dwWidth = parent->format.width;
1757 if (parent->format.flags & DDSD_PIXELFORMAT)
1759 desc.ddpfPixelFormat = parent->format.pf;
1761 else
1763 desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
1764 desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1765 desc.ddpfPixelFormat.u1.dwRGBBitCount = 32;
1766 desc.ddpfPixelFormat.u2.dwRBitMask = 0xff0000;
1767 desc.ddpfPixelFormat.u3.dwGBitMask = 0x00ff00;
1768 desc.ddpfPixelFormat.u4.dwBBitMask = 0x0000ff;
1769 desc.ddpfPixelFormat.u5.dwRGBAlphaBitMask = 0;
1771 desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY|DDSCAPS_OFFSCREENPLAIN;
1772 desc.lpSurface = NULL;
1774 hr = IDirectDraw_CreateSurface(ddraw, &desc, &object->surface, NULL);
1775 IDirectDraw_Release(ddraw);
1776 if (FAILED(hr))
1778 ERR("failed to create surface, 0x%08x\n", hr);
1779 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1780 return hr;
1784 desc.dwSize = sizeof(desc);
1785 hr = IDirectDrawSurface_GetSurfaceDesc(object->surface, &desc);
1786 if (FAILED(hr))
1788 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1789 return hr;
1792 if (rect)
1794 object->rect = *rect;
1795 desc.dwWidth = rect->right - rect->left;
1796 desc.dwHeight = rect->bottom - rect->top;
1798 else
1800 SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight);
1803 hr = IDirectDrawMediaStream_SetFormat(&parent->IDirectDrawMediaStream_iface, &desc, NULL);
1804 if (FAILED(hr))
1806 IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface);
1807 return hr;
1810 *ddraw_stream_sample = &object->IDirectDrawStreamSample_iface;
1812 return S_OK;