[PATCH 6/6] winegstreamer: Implement IMFMediaStream::RequestSample.
Zebediah Figura
zfigura at codeweavers.com
Fri Oct 2 11:40:13 CDT 2020
On 9/29/20 5:08 PM, Derek Lesho wrote:
> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
> ---
> dlls/mfplat/tests/mfplat.c | 4 --
> dlls/winegstreamer/gst_private.h | 1 +
> dlls/winegstreamer/media_source.c | 91 ++++++++++++++++++++++++++++++-
> dlls/winegstreamer/mfplat.c | 90 ++++++++++++++++++++++++++++++
> 4 files changed, 181 insertions(+), 5 deletions(-)
>
> diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
> index bffce2bc114..c54113e5588 100644
> --- a/dlls/mfplat/tests/mfplat.c
> +++ b/dlls/mfplat/tests/mfplat.c
> @@ -623,13 +623,10 @@ todo_wine
> hr = IMFMediaStream_RequestSample(video_stream, NULL);
> if (i == sample_count)
> break;
> -todo_wine
> ok(hr == S_OK, "Failed to request sample %u, hr %#x.\n", i + 1, hr);
> if (hr != S_OK)
> break;
> }
> - if (FAILED(hr))
> - goto skip_source_tests;
>
> for (i = 0; i < sample_count; ++i)
> {
> @@ -670,7 +667,6 @@ todo_wine
>
> get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
>
> -skip_source_tests:
> IMFMediaStream_Release(video_stream);
> IMFMediaTypeHandler_Release(handler);
> IMFPresentationDescriptor_Release(descriptor);
> diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
> index 07556802a51..ff5aff42482 100644
> --- a/dlls/winegstreamer/gst_private.h
> +++ b/dlls/winegstreamer/gst_private.h
> @@ -58,6 +58,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
> HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
> IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN;
> GstCaps *caps_from_mf_media_type(IMFMediaType *type) DECLSPEC_HIDDEN;
> +IMFSample *mf_sample_from_gst_buffer(GstBuffer *in) DECLSPEC_HIDDEN;
>
> HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
>
> diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
> index 581d30ced8f..9b67dfe9217 100644
> --- a/dlls/winegstreamer/media_source.c
> +++ b/dlls/winegstreamer/media_source.c
> @@ -64,6 +64,7 @@ struct media_stream
> enum source_async_op
> {
> SOURCE_ASYNC_START,
> + SOURCE_ASYNC_REQUEST_SAMPLE,
> };
>
> struct source_async_command
> @@ -79,6 +80,11 @@ struct source_async_command
> GUID format;
> PROPVARIANT position;
> } start;
> + struct
> + {
> + struct media_stream *stream;
> + IUnknown *token;
> + } request_sample;
> } u;
> };
>
> @@ -339,6 +345,61 @@ static HRESULT start_pipeline(struct media_source *source, struct source_async_c
> return S_OK;
> }
>
> +static void dispatch_end_of_presentation(struct media_source *source)
> +{
> + PROPVARIANT empty = {.vt = VT_EMPTY};
> +
> + /* A stream has ended, check whether all have */
> + for (unsigned int i = 0; i < source->stream_count; i++)
Misplaced variable initializer.
> + {
> + struct media_stream *stream = source->streams[i];
> +
> + if (stream->state != STREAM_INACTIVE && !stream->eos)
> + return;
> + }
> +
> + IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty);
> +}
> +
> +static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token)
The return value of this function is never used, and always S_OK.
> +{
> + PROPVARIANT empty_var = {.vt = VT_EMPTY};
> + GstSample *gst_sample;
> + GstBuffer *buffer;
> + IMFSample *sample;
> +
> + TRACE("%p, %p\n", stream, token);
> +
> + g_signal_emit_by_name(stream->appsink, "pull-sample", &gst_sample);
> + if (gst_sample)
> + {
> + buffer = gst_sample_get_buffer(gst_sample);
> +
> + TRACE("PTS = %llu\n", (unsigned long long int) GST_BUFFER_PTS(buffer));
> +
> + sample = mf_sample_from_gst_buffer(buffer);
> + gst_sample_unref(gst_sample);
> +
> + if (token)
> + IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
> +
> + IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, &GUID_NULL, S_OK, (IUnknown *)sample);
> + IMFSample_Release(sample);
> + }
> +
> + g_object_get(stream->appsink, "eos", &stream->eos, NULL);
> + if (stream->eos)
> + {
> + if (token)
> + IUnknown_Release(token);
> + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
> + dispatch_end_of_presentation(stream->parent_source);
> + return S_OK;
This statement is superfluous.
> + }
> +
> + return S_OK;
> +}
> +
> static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
> {
> struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
> @@ -358,6 +419,9 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA
> case SOURCE_ASYNC_START:
> start_pipeline(source, command);
> break;
> + case SOURCE_ASYNC_REQUEST_SAMPLE:
> + wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token);
> + break;
> default:
> ;
> }
> @@ -649,13 +713,37 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
> static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
> {
> struct media_stream *stream = impl_from_IMFMediaStream(iface);
> + struct source_async_command *command;
> + HRESULT hr;
>
> TRACE("(%p)->(%p)\n", iface, token);
>
> if (stream->state == STREAM_SHUTDOWN)
> return MF_E_SHUTDOWN;
>
> - return E_NOTIMPL;
> + if (stream->state == STREAM_INACTIVE)
> + {
> + WARN("Stream isn't active\n");
> + return MF_E_MEDIA_SOURCE_WRONGSTATE;
> + }
> +
> + if (stream->eos)
> + {
> + return MF_E_END_OF_STREAM;
> + }
> +
> + if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
> + {
> + command->u.request_sample.stream = stream;
> + if (token)
> + IUnknown_AddRef(token);
> + command->u.request_sample.token = token;
> +
> + /* Once pause support is added, this will need to into a stream queue, and synchronization will need to be added*/
"need to into"
> + hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
> + }
> +
> + return hr;
> }
>
> static const IMFMediaStreamVtbl media_stream_vtbl =
> @@ -739,6 +827,7 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD
> object->stream_id = stream_id;
>
> object->state = STREAM_INACTIVE;
> + object->eos = FALSE;
>
> if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
> goto fail;
> diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
> index 9aa17ad00ab..72da4539abf 100644
> --- a/dlls/winegstreamer/mfplat.c
> +++ b/dlls/winegstreamer/mfplat.c
> @@ -750,3 +750,93 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type)
> FIXME("Unrecognized major type %s\n", debugstr_guid(&major_type));
> return NULL;
> }
> +
> +/* IMFSample = GstBuffer
> + IMFBuffer = GstMemory */
> +
> +/* TODO: Future optimization could be to create a custom
> + IMFMediaBuffer wrapper around GstMemory, and to utilize
> + gst_memory_new_wrapped on IMFMediaBuffer data. However,
> + this wouldn't work if we allow the callers to allocate
> + the buffers. */
> +
> +IMFSample* mf_sample_from_gst_buffer(GstBuffer *gst_buffer)
> +{
> + IMFSample *out = NULL;
> + LONGLONG duration, time;
> + int buffer_count;
> + HRESULT hr;
> +
> + if (FAILED(hr = MFCreateSample(&out)))
> + goto fail;
> +
> + duration = GST_BUFFER_DURATION(gst_buffer);
> + time = GST_BUFFER_PTS(gst_buffer);
> +
> + if (FAILED(IMFSample_SetSampleDuration(out, duration / 100)))
> + goto fail;
> +
> + if (FAILED(IMFSample_SetSampleTime(out, time / 100)))
> + goto fail;
> +
> + buffer_count = gst_buffer_n_memory(gst_buffer);
> +
> + for (unsigned int i = 0; i < buffer_count; i++)
Misplaced initializer.
You may also find it distinctly easier to use gst_buffer_map().
> + {
> + GstMemory *memory = gst_buffer_get_memory(gst_buffer, i);
> + IMFMediaBuffer *mf_buffer = NULL;
> + GstMapInfo map_info;
> + BYTE *buf_data;
> +
> + if (!memory)
> + {
> + hr = E_FAIL;
> + goto loop_done;
> + }
> +
> + if (!(gst_memory_map(memory, &map_info, GST_MAP_READ)))
> + {
> + hr = E_FAIL;
> + goto loop_done;
> + }
> +
> + if (FAILED(hr = MFCreateMemoryBuffer(map_info.maxsize, &mf_buffer)))
> + {
> + gst_memory_unmap(memory, &map_info);
> + goto loop_done;
> + }
> +
> + if (FAILED(hr = IMFMediaBuffer_Lock(mf_buffer, &buf_data, NULL, NULL)))
> + {
> + gst_memory_unmap(memory, &map_info);
> + goto loop_done;
> + }
> +
> + memcpy(buf_data, map_info.data, map_info.size);
> +
> + gst_memory_unmap(memory, &map_info);
> +
> + if (FAILED(hr = IMFMediaBuffer_Unlock(mf_buffer)))
> + goto loop_done;
> +
> + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(mf_buffer, map_info.size)))
> + goto loop_done;
> +
> + if (FAILED(hr = IMFSample_AddBuffer(out, mf_buffer)))
> + goto loop_done;
> +
> + loop_done:
> + if (mf_buffer)
> + IMFMediaBuffer_Release(mf_buffer);
> + if (memory)
> + gst_memory_unref(memory);
> + if (FAILED(hr))
> + goto fail;
> + }
> +
> + return out;
> + fail:
Again, please omit spaces before labels.
> + ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr);
> + IMFSample_Release(out);
> + return NULL;
> +}
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20201002/f785521d/attachment-0001.sig>
More information about the wine-devel
mailing list