On 6/10/21 11:33 AM, Giovanni Mascellani wrote:
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com
dlls/winegstreamer/media_source.c | 95 +++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 10 deletions(-)
This patch probably warrants a few tests. I would test at least
- what happens to ::RequestSample calls when a stream is paused.
- whether MESourcePaused or the MEStreamPaused events come first.
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3c87bbb2146..496aab545e7 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -27,6 +27,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct pending_sample +{
- struct list entry;
- IMFSample *sample;
+};
- struct media_stream { IMFMediaStream IMFMediaStream_iface;
@@ -34,6 +40,7 @@ struct media_stream struct media_source *parent_source; IMFMediaEventQueue *event_queue; IMFStreamDescriptor *descriptor;
struct list pending_samples;
struct wg_parser_stream *wg_stream;
@@ -50,6 +57,7 @@ struct media_stream enum source_async_op { SOURCE_ASYNC_START,
- SOURCE_ASYNC_PAUSE, SOURCE_ASYNC_STOP, SOURCE_ASYNC_REQUEST_SAMPLE, };
@@ -96,6 +104,7 @@ struct media_source { SOURCE_OPENING, SOURCE_STOPPED,
SOURCE_PAUSED, SOURCE_RUNNING, SOURCE_SHUTDOWN, } state;
@@ -257,6 +266,23 @@ static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor return NULL; }
+static void flush_pending_queue(struct media_stream *stream, BOOL send_events) +{
- struct pending_sample *pending, *pending2;
- LIST_FOR_EACH_ENTRY_SAFE(pending, pending2, &stream->pending_samples, struct pending_sample, entry)
- {
if (send_events)
{
IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
&GUID_NULL, S_OK, (IUnknown *)pending->sample);
}
IMFSample_Release(pending->sample);
list_remove(&pending->entry);
free(pending);
- }
+}
- static void start_pipeline(struct media_source *source, struct source_async_command *command) { PROPVARIANT *position = &command->u.start.position;
@@ -269,7 +295,8 @@ static void start_pipeline(struct media_source *source, struct source_async_comm position->vt = VT_I8; position->hVal.QuadPart = 0; }
- source->start_time = position->hVal.QuadPart;
if (position->vt != VT_EMPTY)
source->start_time = position->hVal.QuadPart; for (i = 0; i < source->stream_count; i++) {
@@ -318,6 +345,8 @@ static void start_pipeline(struct media_source *source, struct source_async_comm
IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
flush_pending_queue(stream, TRUE); } }
@@ -327,11 +356,30 @@ static void start_pipeline(struct media_source *source, struct source_async_comm
source->state = SOURCE_RUNNING;
- unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0,
position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
- if (position->vt != VT_EMPTY)
unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0,
}position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); unix_funcs->wg_parser_end_flush(source->wg_parser);
+static void pause_pipeline(struct media_source *source) +{
- unsigned int i;
- for (i = 0; i < source->stream_count; i++)
- {
struct media_stream *stream = source->streams[i];
if (stream->state != STREAM_INACTIVE)
{
IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, &GUID_NULL, S_OK, NULL);
}
- }
- IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL);
- source->state = SOURCE_PAUSED;
+}
- static void stop_pipeline(struct media_source *source) { unsigned int i;
@@ -343,6 +391,7 @@ static void stop_pipeline(struct media_source *source) struct media_stream *stream = source->streams[i]; if (stream->state != STREAM_INACTIVE) {
flush_pending_queue(stream, FALSE); IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL); unix_funcs->wg_parser_stream_disable(stream->wg_stream); }
@@ -437,12 +486,26 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even if (token) IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
- IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
&GUID_NULL, S_OK, (IUnknown *)sample);
- if (stream->parent_source->state == SOURCE_PAUSED)
- {
struct pending_sample *pending = malloc(sizeof(*pending));
if (!pending)
{
ERR("Cannot allocate pending sample\n");
goto out;
}
pending->sample = sample;
sample = NULL;
list_add_tail(&stream->pending_samples, &pending->entry);
Since our media source outputs uncompressed samples, if it's common behavior for an application to request a significant amount of samples while the source is paused, we might instead want to add a separate sample request queue. (Lest we use too much memory) I think this is what I was referring to in my old comment.
}
else
IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
&GUID_NULL, S_OK, (IUnknown *)sample);
out: IMFMediaBuffer_Release(buffer);
- IMFSample_Release(sample);
if (sample)
IMFSample_Release(sample);
}
static void wait_on_sample(struct media_stream *stream, IUnknown *token)
@@ -501,6 +564,9 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA case SOURCE_ASYNC_START: start_pipeline(source, command); break;
case SOURCE_ASYNC_PAUSE:
pause_pipeline(source);
break; case SOURCE_ASYNC_STOP: stop_pipeline(source); break;
@@ -597,6 +663,7 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) { if (stream->event_queue) IMFMediaEventQueue_Release(stream->event_queue);
flush_pending_queue(stream, FALSE); free(stream); }
@@ -699,7 +766,6 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown 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); }
@@ -738,6 +804,7 @@ static HRESULT new_media_stream(struct media_source *source, object->state = STREAM_INACTIVE; object->eos = FALSE; object->wg_stream = wg_stream;
list_init(&object->pending_samples);
if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) goto fail;
@@ -1123,7 +1190,7 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- *characteristics = MFMEDIASOURCE_CAN_SEEK;
*characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
return S_OK; }
@@ -1187,13 +1254,21 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface);
- struct source_async_command *command;
- HRESULT hr;
- FIXME("(%p): stub\n", source);
TRACE("(%p)\n", source);
if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- return E_NOTIMPL;
if (source->state != SOURCE_RUNNING)
return MF_E_INVALID_STATE_TRANSITION;
if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command)))
hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
return hr; }
static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)