[PATCH v2 5/5] winegstreamer: Implement IMFMediaStream::RequestSample.

Zebediah Figura zfigura at codeweavers.com
Tue Oct 6 22:02:25 CDT 2020


On 10/6/20 10:59 AM, Derek Lesho wrote:
> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
> ---
> v2: Addressed comments.
> ---
>  dlls/mfplat/tests/mfplat.c        |  4 --
>  dlls/winegstreamer/gst_private.h  |  1 +
>  dlls/winegstreamer/media_source.c | 89 ++++++++++++++++++++++++++++++-
>  dlls/winegstreamer/mfplat.c       | 69 ++++++++++++++++++++++++
>  4 files changed, 158 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 5eb4465fea6..1593a60dfe1 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;
>  };
>  
> @@ -341,6 +347,59 @@ static void start_pipeline(struct media_source *source, struct source_async_comm
>      gst_element_get_state(source->container, NULL, NULL, -1);
>  }
>  
> +static void dispatch_end_of_presentation(struct media_source *source)
> +{
> +    PROPVARIANT empty = {.vt = VT_EMPTY};
> +    unsigned int i;
> +
> +    /* A stream has ended, check whether all have */
> +    for (i = 0; i < source->stream_count; i++)
> +    {
> +        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 void wait_on_sample(struct media_stream *stream, IUnknown *token)
> +{
> +    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);
> +    }
> +}
> +
>  static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
>  {
>      struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
> @@ -360,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;
>      }
>  
>      IUnknown_Release(state);
> @@ -647,13 +709,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 put into a stream queue, and synchronization will need to be added*/
> +        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 =
> @@ -738,6 +824,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;

This doesn't look like it belongs in this patch.

>  
>      if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
>          goto fail;
> diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
> index 9aa17ad00ab..f28ef8f117c 100644
> --- a/dlls/winegstreamer/mfplat.c
> +++ b/dlls/winegstreamer/mfplat.c
> @@ -750,3 +750,72 @@ 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)
> +{
> +    IMFMediaBuffer *mf_buffer = NULL;
> +    GstMapInfo map_info = {0};
> +    LONGLONG duration, time;
> +    BYTE *mapped_buf = NULL;
> +    IMFSample *out = NULL;
> +    HRESULT hr;
> +
> +    if (FAILED(hr = MFCreateSample(&out)))
> +        goto done;
> +
> +    duration = GST_BUFFER_DURATION(gst_buffer);
> +    time = GST_BUFFER_PTS(gst_buffer);
> +
> +    if (FAILED(hr = IMFSample_SetSampleDuration(out, duration / 100)))
> +        goto done;
> +
> +    if (FAILED(hr = IMFSample_SetSampleTime(out, time / 100)))
> +        goto done;
> +
> +    if (!gst_buffer_map(gst_buffer, &map_info, GST_MAP_READ))
> +    {
> +        hr = E_FAIL;
> +        goto done;
> +    }
> +
> +    if (FAILED(hr = MFCreateMemoryBuffer(map_info.maxsize, &mf_buffer)))
> +        goto done;
> +
> +    if (FAILED(hr = IMFMediaBuffer_Lock(mf_buffer, &mapped_buf, NULL, NULL)))
> +        goto done;
> +
> +    memcpy(mapped_buf, map_info.data, map_info.size);
> +
> +    if (FAILED(hr = IMFMediaBuffer_Unlock(mf_buffer)))
> +        goto done;
> +
> +    if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(mf_buffer, map_info.size)))
> +        goto done;
> +
> +    if (FAILED(hr = IMFSample_AddBuffer(out, mf_buffer)))
> +        goto done;
> +
> +done:
> +    if (mf_buffer)
> +        IMFMediaBuffer_Release(mf_buffer);
> +    if (map_info.data)
> +        gst_buffer_unmap(gst_buffer, &map_info);
> +    if (FAILED(hr))
> +    {
> +        ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr);
> +        if (out)
> +            IMFSample_Release(out);
> +        out = NULL;
> +    }
> +
> +    return out;
> +}
> 


-------------- 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/20201006/6a8c67aa/attachment.sig>


More information about the wine-devel mailing list