mf: Add support for MEStreamSinkMarker event for sample grabber.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5371d6b82b
commit
f525251226
|
@ -1,6 +1,6 @@
|
||||||
MODULE = mf.dll
|
MODULE = mf.dll
|
||||||
IMPORTLIB = mf
|
IMPORTLIB = mf
|
||||||
IMPORTS = mfplat uuid mfuuid
|
IMPORTS = mfplat ole32 uuid mfuuid
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
main.c \
|
main.c \
|
||||||
|
|
|
@ -37,10 +37,25 @@ enum sink_state
|
||||||
|
|
||||||
struct sample_grabber;
|
struct sample_grabber;
|
||||||
|
|
||||||
struct scheduled_sample
|
enum scheduled_item_type
|
||||||
|
{
|
||||||
|
ITEM_TYPE_SAMPLE,
|
||||||
|
ITEM_TYPE_MARKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scheduled_item
|
||||||
{
|
{
|
||||||
struct list entry;
|
struct list entry;
|
||||||
IMFSample *sample;
|
enum scheduled_item_type type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
IMFSample *sample;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
MFSTREAMSINK_MARKER_TYPE type;
|
||||||
|
PROPVARIANT context;
|
||||||
|
} marker;
|
||||||
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sample_grabber_stream
|
struct sample_grabber_stream
|
||||||
|
@ -52,7 +67,7 @@ struct sample_grabber_stream
|
||||||
struct sample_grabber *sink;
|
struct sample_grabber *sink;
|
||||||
IMFMediaEventQueue *event_queue;
|
IMFMediaEventQueue *event_queue;
|
||||||
enum sink_state state;
|
enum sink_state state;
|
||||||
struct list samples;
|
struct list items;
|
||||||
IUnknown *cancel_key;
|
IUnknown *cancel_key;
|
||||||
CRITICAL_SECTION cs;
|
CRITICAL_SECTION cs;
|
||||||
};
|
};
|
||||||
|
@ -156,18 +171,26 @@ static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface)
|
||||||
return refcount;
|
return refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stream_release_pending_entry(struct sample_grabber_stream *stream, struct scheduled_sample *sample)
|
static void stream_release_pending_item(struct sample_grabber_stream *stream, struct scheduled_item *item)
|
||||||
{
|
{
|
||||||
list_remove(&sample->entry);
|
list_remove(&item->entry);
|
||||||
IMFSample_Release(sample->sample);
|
switch (item->type)
|
||||||
heap_free(sample);
|
{
|
||||||
|
case ITEM_TYPE_SAMPLE:
|
||||||
|
IMFSample_Release(item->u.sample);
|
||||||
|
break;
|
||||||
|
case ITEM_TYPE_MARKER:
|
||||||
|
PropVariantClear(&item->u.marker.context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
heap_free(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
|
static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
|
||||||
{
|
{
|
||||||
struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
|
struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
|
||||||
ULONG refcount = InterlockedDecrement(&stream->refcount);
|
ULONG refcount = InterlockedDecrement(&stream->refcount);
|
||||||
struct scheduled_sample *sample, *next_sample;
|
struct scheduled_item *item, *next_item;
|
||||||
|
|
||||||
TRACE("%p, refcount %u.\n", iface, refcount);
|
TRACE("%p, refcount %u.\n", iface, refcount);
|
||||||
|
|
||||||
|
@ -186,9 +209,9 @@ static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
|
||||||
IMFMediaEventQueue_Shutdown(stream->event_queue);
|
IMFMediaEventQueue_Shutdown(stream->event_queue);
|
||||||
IMFMediaEventQueue_Release(stream->event_queue);
|
IMFMediaEventQueue_Release(stream->event_queue);
|
||||||
}
|
}
|
||||||
LIST_FOR_EACH_ENTRY_SAFE(sample, next_sample, &stream->samples, struct scheduled_sample, entry)
|
LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &stream->items, struct scheduled_item, entry)
|
||||||
{
|
{
|
||||||
stream_release_pending_entry(stream, sample);
|
stream_release_pending_item(stream, item);
|
||||||
}
|
}
|
||||||
DeleteCriticalSection(&stream->cs);
|
DeleteCriticalSection(&stream->cs);
|
||||||
heap_free(stream);
|
heap_free(stream);
|
||||||
|
@ -321,7 +344,7 @@ static HRESULT sample_grabber_report_sample(struct sample_grabber *grabber, IMFS
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT stream_schedule_sample(struct sample_grabber_stream *stream, struct scheduled_sample *pending)
|
static HRESULT stream_schedule_sample(struct sample_grabber_stream *stream, struct scheduled_item *item)
|
||||||
{
|
{
|
||||||
LONGLONG sampletime;
|
LONGLONG sampletime;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -329,7 +352,7 @@ static HRESULT stream_schedule_sample(struct sample_grabber_stream *stream, stru
|
||||||
if (!stream->sink)
|
if (!stream->sink)
|
||||||
return MF_E_STREAMSINK_REMOVED;
|
return MF_E_STREAMSINK_REMOVED;
|
||||||
|
|
||||||
if (FAILED(hr = IMFSample_GetSampleTime(pending->sample, &sampletime)))
|
if (FAILED(hr = IMFSample_GetSampleTime(item->u.sample, &sampletime)))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
if (stream->cancel_key)
|
if (stream->cancel_key)
|
||||||
|
@ -349,26 +372,27 @@ static HRESULT stream_schedule_sample(struct sample_grabber_stream *stream, stru
|
||||||
|
|
||||||
static HRESULT stream_queue_sample(struct sample_grabber_stream *stream, IMFSample *sample)
|
static HRESULT stream_queue_sample(struct sample_grabber_stream *stream, IMFSample *sample)
|
||||||
{
|
{
|
||||||
struct scheduled_sample *pending;
|
struct scheduled_item *item;
|
||||||
LONGLONG sampletime;
|
LONGLONG sampletime;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (FAILED(hr = IMFSample_GetSampleTime(sample, &sampletime)))
|
if (FAILED(hr = IMFSample_GetSampleTime(sample, &sampletime)))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
if (!(pending = heap_alloc_zero(sizeof(*pending))))
|
if (!(item = heap_alloc_zero(sizeof(*item))))
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
pending->sample = sample;
|
item->type = ITEM_TYPE_SAMPLE;
|
||||||
IMFSample_AddRef(pending->sample);
|
item->u.sample = sample;
|
||||||
list_init(&pending->entry);
|
IMFSample_AddRef(item->u.sample);
|
||||||
if (list_empty(&stream->samples))
|
list_init(&item->entry);
|
||||||
hr = stream_schedule_sample(stream, pending);
|
if (list_empty(&stream->items))
|
||||||
|
hr = stream_schedule_sample(stream, item);
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
list_add_tail(&stream->samples, &pending->entry);
|
list_add_tail(&stream->items, &item->entry);
|
||||||
else
|
else
|
||||||
stream_release_pending_entry(stream, pending);
|
stream_release_pending_item(stream, item);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -407,12 +431,58 @@ static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface,
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sample_grabber_stream_report_marker(struct sample_grabber_stream *stream, const PROPVARIANT *context,
|
||||||
|
HRESULT hr)
|
||||||
|
{
|
||||||
|
IMFStreamSink_QueueEvent(&stream->IMFStreamSink_iface, MEStreamSinkMarker, &GUID_NULL, hr, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT stream_place_marker(struct sample_grabber_stream *stream, MFSTREAMSINK_MARKER_TYPE marker_type,
|
||||||
|
const PROPVARIANT *context_value)
|
||||||
|
{
|
||||||
|
struct scheduled_item *item;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (list_empty(&stream->items))
|
||||||
|
{
|
||||||
|
sample_grabber_stream_report_marker(stream, context_value, S_OK);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(item = heap_alloc_zero(sizeof(*item))))
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
item->type = ITEM_TYPE_MARKER;
|
||||||
|
item->u.marker.type = marker_type;
|
||||||
|
list_init(&item->entry);
|
||||||
|
hr = PropVariantCopy(&item->u.marker.context, context_value);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
list_add_tail(&stream->items, &item->entry);
|
||||||
|
else
|
||||||
|
stream_release_pending_item(stream, item);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
|
static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
|
||||||
const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
|
const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
|
||||||
{
|
{
|
||||||
FIXME("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
|
struct sample_grabber_stream *stream = impl_from_IMFStreamSink(iface);
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
return E_NOTIMPL;
|
TRACE("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
|
||||||
|
|
||||||
|
if (!stream->sink)
|
||||||
|
return MF_E_STREAMSINK_REMOVED;
|
||||||
|
|
||||||
|
EnterCriticalSection(&stream->cs);
|
||||||
|
|
||||||
|
if (stream->state == SINK_STATE_RUNNING)
|
||||||
|
hr = stream_place_marker(stream, marker_type, context_value);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&stream->cs);
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
|
static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
|
||||||
|
@ -602,15 +672,15 @@ static HRESULT WINAPI sample_grabber_stream_timer_callback_GetParameters(IMFAsyn
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct scheduled_sample *stream_get_next_sample(struct sample_grabber_stream *stream)
|
static struct scheduled_item *stream_get_next_item(struct sample_grabber_stream *stream)
|
||||||
{
|
{
|
||||||
struct scheduled_sample *sample = NULL;
|
struct scheduled_item *item = NULL;
|
||||||
struct list *e;
|
struct list *e;
|
||||||
|
|
||||||
if ((e = list_head(&stream->samples)))
|
if ((e = list_head(&stream->items)))
|
||||||
sample = LIST_ENTRY(e, struct scheduled_sample, entry);
|
item = LIST_ENTRY(e, struct scheduled_item, entry);
|
||||||
|
|
||||||
return sample;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sample_grabber_stream_request_sample(struct sample_grabber_stream *stream)
|
static void sample_grabber_stream_request_sample(struct sample_grabber_stream *stream)
|
||||||
|
@ -621,25 +691,38 @@ static void sample_grabber_stream_request_sample(struct sample_grabber_stream *s
|
||||||
static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
||||||
{
|
{
|
||||||
struct sample_grabber_stream *stream = impl_from_IMFAsyncCallback(iface);
|
struct sample_grabber_stream *stream = impl_from_IMFAsyncCallback(iface);
|
||||||
struct scheduled_sample *sample;
|
struct scheduled_item *item;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
EnterCriticalSection(&stream->cs);
|
EnterCriticalSection(&stream->cs);
|
||||||
|
|
||||||
/* Report and schedule next. */
|
/* Report and schedule next. */
|
||||||
if (stream->sink && (sample = stream_get_next_sample(stream)))
|
if (stream->sink && (item = stream_get_next_item(stream)))
|
||||||
{
|
{
|
||||||
if (FAILED(hr = sample_grabber_report_sample(stream->sink, sample->sample)))
|
while (item)
|
||||||
WARN("Failed to report a sample, hr %#x.\n", hr);
|
|
||||||
|
|
||||||
stream_release_pending_entry(stream, sample);
|
|
||||||
|
|
||||||
if ((sample = stream_get_next_sample(stream)))
|
|
||||||
{
|
{
|
||||||
if (FAILED(hr = stream_schedule_sample(stream, sample)))
|
switch (item->type)
|
||||||
WARN("Failed to schedule a sample, hr %#x.\n", hr);
|
{
|
||||||
|
case ITEM_TYPE_SAMPLE:
|
||||||
|
if (FAILED(hr = sample_grabber_report_sample(stream->sink, item->u.sample)))
|
||||||
|
WARN("Failed to report a sample, hr %#x.\n", hr);
|
||||||
|
stream_release_pending_item(stream, item);
|
||||||
|
item = stream_get_next_item(stream);
|
||||||
|
if (item && item->type == ITEM_TYPE_SAMPLE)
|
||||||
|
{
|
||||||
|
if (FAILED(hr = stream_schedule_sample(stream, item)))
|
||||||
|
WARN("Failed to schedule a sample, hr %#x.\n", hr);
|
||||||
|
sample_grabber_stream_request_sample(stream);
|
||||||
|
item = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_TYPE_MARKER:
|
||||||
|
sample_grabber_stream_report_marker(stream, &item->u.marker.context, S_OK);
|
||||||
|
stream_release_pending_item(stream, item);
|
||||||
|
item = stream_get_next_item(stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sample_grabber_stream_request_sample(stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&stream->cs);
|
LeaveCriticalSection(&stream->cs);
|
||||||
|
@ -1132,7 +1215,7 @@ static HRESULT sample_grabber_create_stream(struct sample_grabber *sink, struct
|
||||||
object->refcount = 1;
|
object->refcount = 1;
|
||||||
object->sink = sink;
|
object->sink = sink;
|
||||||
IMFMediaSink_AddRef(&object->sink->IMFMediaSink_iface);
|
IMFMediaSink_AddRef(&object->sink->IMFMediaSink_iface);
|
||||||
list_init(&object->samples);
|
list_init(&object->items);
|
||||||
InitializeCriticalSection(&object->cs);
|
InitializeCriticalSection(&object->cs);
|
||||||
|
|
||||||
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
|
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
|
||||||
|
|
Loading…
Reference in New Issue