From: Charlotte Pabst <cpabst(a)codeweavers.com> --- dlls/mfsrcsnk/media_source.c | 123 +++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 28 deletions(-) diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 0d5dd098db1..42862260b7c 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -276,6 +276,7 @@ struct media_stream { IMFMediaStream IMFMediaStream_iface; IMFAsyncCallback async_request_iface; + IMFAsyncCallback async_update_thin_iface; LONG refcount; IMFMediaSource *source; @@ -286,6 +287,8 @@ struct media_stream BOOL active; BOOL eos; + BOOL thin; + BOOL pending_thin; }; struct media_source @@ -307,6 +310,7 @@ struct media_source IMFByteStream *stream; WCHAR *url; float rate; + BOOL thin; struct winedmo_demuxer winedmo_demuxer; struct winedmo_stream winedmo_stream; @@ -356,28 +360,6 @@ static struct media_stream *media_stream_from_index(struct media_source *source, return NULL; } -static HRESULT media_source_send_sample(struct media_source *source, UINT index, IMFSample *sample) -{ - struct media_stream *stream; - IUnknown *token; - HRESULT hr; - - if (!(stream = media_stream_from_index(source, index)) || !stream->active) - return S_FALSE; - - if (SUCCEEDED(hr = object_queue_pop(&stream->tokens, &token))) - { - media_stream_send_sample(stream, sample, token); - if (token) IUnknown_Release(token); - return S_OK; - } - - if (FAILED(hr = object_queue_push(&stream->samples, (IUnknown *)sample))) - return hr; - - return S_FALSE; -} - static void queue_media_event_object(IMFMediaEventQueue *queue, MediaEventType type, IUnknown *object) { HRESULT hr; @@ -401,6 +383,58 @@ static void queue_media_source_read(struct media_source *source) source->pending_reads++; } + +static void media_stream_update_thin(struct media_stream *stream) +{ + PROPVARIANT param; + if (stream->pending_thin != stream->thin) + { + stream->thin = stream->pending_thin; + param.vt = VT_INT; + param.iVal = stream->thin; + queue_media_event_value(stream->queue, MEStreamThinMode, ¶m); + } +} + +static BOOL media_stream_filter_sample(struct media_stream *stream, IMFSample *sample) +{ + BOOL thin = stream->pending_thin || stream->thin; + BOOL keyframe; + + if (!thin) + return TRUE; + if (FAILED(IMFSample_GetUINT32( sample, &MFSampleExtension_CleanPoint, (UINT32*)&keyframe ))) + keyframe = FALSE; + if (keyframe != stream->pending_thin) + media_stream_update_thin(stream); + return keyframe; +} + +#define S_SAMPLE_FILTERED ((HRESULT) 2) + +static HRESULT media_source_send_sample(struct media_source *source, UINT index, IMFSample *sample) +{ + struct media_stream *stream; + IUnknown *token; + HRESULT hr; + + if (!(stream = media_stream_from_index(source, index)) || !stream->active) + return S_FALSE; + if (!list_head(&stream->tokens)) + { + if (FAILED(hr = object_queue_push(&stream->samples, (IUnknown *)sample))) + return hr; + return S_FALSE; + } + if (!media_stream_filter_sample(stream, sample)) + return S_SAMPLE_FILTERED; + if (FAILED(hr = object_queue_pop(&stream->tokens, &token))) + return hr; + media_stream_send_sample(stream, sample, token); + if (token) IUnknown_Release(token); + return S_OK; +} + static void media_stream_start(struct media_stream *stream, UINT index, const PROPVARIANT *position) { struct media_source *source = media_source_from_IMFMediaSource(stream->source); @@ -711,7 +745,10 @@ static HRESULT media_source_read(struct media_source *source) if (hr == MF_E_END_OF_STREAM) { for (i = 0; i < source->stream_count; i++) + { + media_stream_update_thin(source->streams[i]); media_source_send_eos(source, source->streams[i]); + } return S_OK; } @@ -719,6 +756,9 @@ static HRESULT media_source_read(struct media_source *source) queue_media_source_read(source); IMFSample_Release(sample); + if (hr == S_SAMPLE_FILTERED) + return media_source_read(source); + return hr; } @@ -867,6 +907,17 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM return hr; } +static HRESULT media_stream_pop_sample(struct media_stream *stream, IMFSample **pSample) +{ + HRESULT hr; + + while (SUCCEEDED(hr = object_queue_pop(&stream->samples, (IUnknown **)pSample)) + && !media_stream_filter_sample(stream, *pSample)) + IMFSample_Release(*pSample); + + return hr; +} + static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncResult *result) { struct media_source *source = media_source_from_IMFMediaSource(stream->source); @@ -878,7 +929,7 @@ static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncR if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; - else if (source->state == SOURCE_RUNNING && SUCCEEDED(hr = object_queue_pop(&stream->samples, (IUnknown **)&sample))) + else if (source->state == SOURCE_RUNNING && SUCCEEDED(hr = media_stream_pop_sample(stream, &sample))) { media_stream_send_sample(stream, sample, token); IMFSample_Release(sample); @@ -893,6 +944,19 @@ static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncR DEFINE_MF_ASYNC_CALLBACK(media_stream, async_request, IMFMediaStream_iface) +static HRESULT media_stream_async_update_thin(struct media_stream *stream, IMFAsyncResult *result) +{ + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + + EnterCriticalSection(&source->cs); + stream->pending_thin = source->thin; + LeaveCriticalSection(&source->cs); + + return S_OK; +} + +DEFINE_MF_ASYNC_CALLBACK(media_stream, async_update_thin, IMFMediaStream_iface) + static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) { struct media_stream *stream = media_stream_from_IMFMediaStream(iface); @@ -910,7 +974,11 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown else if (stream->eos) hr = MF_E_END_OF_STREAM; else + { + if (stream->pending_thin != source->thin) + MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_update_thin_iface, NULL); hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_request_iface, token); + } LeaveCriticalSection(&source->cs); @@ -943,6 +1011,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor * object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; object->async_request_iface.lpVtbl = &media_stream_async_request_vtbl; + object->async_update_thin_iface.lpVtbl = &media_stream_async_update_thin_vtbl; object->refcount = 1; if (FAILED(hr = MFCreateEventQueue(&object->queue))) @@ -1115,6 +1184,7 @@ static HRESULT media_source_async_setrate(struct media_source *source, IMFAsyncR EnterCriticalSection(&source->cs); source->rate = params->rate; + source->thin = params->thin; LeaveCriticalSection(&source->cs); return IMFMediaEventQueue_QueueEventParamVar(source->queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); @@ -1132,8 +1202,6 @@ static HRESULT WINAPI media_source_IMFRateControl_SetRate(IMFRateControl *iface, if (rate < 0.0f) return MF_E_REVERSE_UNSUPPORTED; - if (thin) - return MF_E_THINNING_UNSUPPORTED; if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) return hr; @@ -1153,11 +1221,10 @@ static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface, TRACE("source %p, thin %p, rate %p\n", source, thin, rate); - if (thin) - *thin = FALSE; - EnterCriticalSection(&source->cs); *rate = source->rate; + if (thin) + *thin = source->thin; LeaveCriticalSection(&source->cs); return S_OK; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8505