Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 68 ++++++++++++++++++++++++++++++++++++----- include/mfidl.idl | 3 ++ 2 files changed, 63 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index d501e0865d..e2766c086c 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -28,6 +28,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+enum sink_state +{ + SINK_STATE_STOPPED = 0, + SINK_STATE_RUNNING, +}; + struct sample_grabber;
struct sample_grabber_stream @@ -51,6 +57,7 @@ struct sample_grabber struct sample_grabber_stream *stream; IMFMediaEventQueue *event_queue; IMFPresentationClock *clock; + enum sink_state state; CRITICAL_SECTION cs; };
@@ -685,32 +692,77 @@ static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface) return IMFMediaSink_Release(&grabber->IMFMediaSink_iface); }
+static void sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state) +{ + static const DWORD events[] = + { + MEStreamSinkStopped, /* SINK_STATE_STOPPED */ + MEStreamSinkStarted, /* SINK_STATE_RUNNING */ + }; + BOOL set_state = FALSE; + + EnterCriticalSection(&grabber->cs); + + switch (grabber->state) + { + case SINK_STATE_STOPPED: + set_state = state == SINK_STATE_RUNNING; + break; + case SINK_STATE_RUNNING: + set_state = state == SINK_STATE_STOPPED; + break; + default: + ; + } + + if (set_state) + { + grabber->state = state; + if (grabber->stream) + IMFStreamSink_QueueEvent(&grabber->stream->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL); + } + + LeaveCriticalSection(&grabber->cs); +} + static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) { - FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(systime), wine_dbgstr_longlong(offset)); + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
- return E_NOTIMPL; + TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(systime), wine_dbgstr_longlong(offset)); + + sample_grabber_set_state(grabber, SINK_STATE_RUNNING); + + return S_OK; }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
- return E_NOTIMPL; + TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + + sample_grabber_set_state(grabber, SINK_STATE_STOPPED); + + return S_OK; }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(systime));
- return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) { - FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
- return E_NOTIMPL; + TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(systime)); + + sample_grabber_set_state(grabber, SINK_STATE_RUNNING); + + return S_OK; }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) diff --git a/include/mfidl.idl b/include/mfidl.idl index 2421c06f50..93e20a6978 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -820,3 +820,6 @@ cpp_quote("EXTERN_GUID(MF_TOPOLOGY_START_TIME_ON_PRESENTATION_SWITCH, 0xc8cc113f cpp_quote("EXTERN_GUID(MF_TOPOLOGY_STATIC_PLAYBACK_OPTIMIZATIONS, 0xb86cac42, 0x41a6, 0x4b79, 0x89, 0x7a, 0x1a, 0xb0, 0xe5, 0x2b, 0x4a, 0x1b);")
cpp_quote("EXTERN_GUID(MF_RATE_CONTROL_SERVICE, 0x866fa297, 0xb802, 0x4bf8, 0x9d, 0xc9, 0x5e, 0x3b, 0x6a, 0x9f, 0x53, 0xc9);") + +cpp_quote("EXTERN_GUID(MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET, 0x62e3d776, 0x8100, 0x4e03, 0xa6, 0xe8, 0xbd, 0x38, 0x57, 0xac, 0x9c, 0x47);") +cpp_quote("EXTERN_GUID(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, 0x0efda2c0, 0x2b69, 0x4e2e, 0xab, 0x8d, 0x46, 0xdc, 0xbf, 0xf7, 0xd2, 0x5d);")
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 1009f4083b..460f21e3b6 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -657,6 +657,7 @@ const char *debugstr_attr(const GUID *guid) X(MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES), X(MF_MT_VIDEO_NO_FRAME_ORDERING), X(MFSampleExtension_3DVideo_SampleFormat), + X(MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET), X(MF_MT_SAMPLE_SIZE), X(MF_MT_AAC_PAYLOAD_TIME), X(MF_TOPOLOGY_PLAYBACK_FRAMERATE), @@ -701,8 +702,8 @@ const char *debugstr_attr(const GUID *guid) X(MF_TOPONODE_DISABLE_PREROLL), X(MF_MT_VIDEO_3D_FORMAT), X(MF_EVENT_STREAM_METADATA_KEYDATA), - X(MF_SOURCE_READER_D3D_MANAGER), X(MF_SINK_WRITER_D3D_MANAGER), + X(MF_SOURCE_READER_D3D_MANAGER), X(MFSampleExtension_3DVideo), X(MF_EVENT_SOURCE_FAKE_START), X(MF_EVENT_SOURCE_PROJECTSTART), @@ -717,6 +718,7 @@ const char *debugstr_attr(const GUID *guid) X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_HW_SOURCE), X(MF_MT_AUDIO_PREFER_WAVEFORMATEX), X(MF_TOPONODE_WORKQUEUE_ITEM_PRIORITY), + X(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK), X(MFSampleExtension_ForwardedDecodeUnitType), X(MF_MT_AUDIO_AVG_BYTES_PER_SECOND), X(MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS),
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/samplegrabber.c | 71 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index e2766c086c..d19496d7f8 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -58,6 +58,7 @@ struct sample_grabber IMFMediaEventQueue *event_queue; IMFPresentationClock *clock; enum sink_state state; + UINT32 ignore_clock; CRITICAL_SECTION cs; };
@@ -245,11 +246,76 @@ static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *i return S_OK; }
+static HRESULT sample_grabber_report_sample(struct sample_grabber *grabber, IMFSample *sample) +{ + LONGLONG sample_time, sample_duration = 0; + IMFMediaBuffer *buffer; + DWORD flags, size; + GUID major_type; + BYTE *data; + HRESULT hr; + + hr = IMFMediaType_GetMajorType(grabber->media_type, &major_type); + + if (SUCCEEDED(hr)) + hr = IMFSample_GetSampleTime(sample, &sample_time); + + if (FAILED(IMFSample_GetSampleDuration(sample, &sample_duration))) + sample_duration = 0; + + if (SUCCEEDED(hr)) + hr = IMFSample_GetSampleFlags(sample, &flags); + + if (SUCCEEDED(hr)) + { + if (FAILED(IMFSample_ConvertToContiguousBuffer(sample, &buffer))) + return E_UNEXPECTED; + + if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &size))) + { + hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time, + sample_duration, data, size); + IMFMediaBuffer_Unlock(buffer); + } + + IMFMediaBuffer_Release(buffer); + } + + return hr; +} + static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample) { - FIXME("%p, %p.\n", iface, sample); + struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface); + LONGLONG sampletime; + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, sample); + + if (!sample) + return S_OK; + + if (!stream->sink) + return MF_E_STREAMSINK_REMOVED; + + EnterCriticalSection(&stream->sink->cs); + + if (stream->sink->state == SINK_STATE_RUNNING) + { + hr = IMFSample_GetSampleTime(sample, &sampletime); + + if (SUCCEEDED(hr)) + { + if (stream->sink->ignore_clock) + hr = sample_grabber_report_sample(stream->sink, sample); + else + FIXME("Sample scheduling is not implemented.\n"); + } + } + + LeaveCriticalSection(&stream->sink->cs); + + return hr; }
static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, @@ -905,6 +971,7 @@ static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *use IMFSampleGrabberSinkCallback_AddRef(object->callback); object->media_type = context->media_type; IMFMediaType_AddRef(object->media_type); + IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock); InitializeCriticalSection(&object->cs);
if (FAILED(hr = sample_grabber_create_stream(object, &object->stream)))