Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winegstreamer/media_source.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index dbc656a24da..913b1cc9e93 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1032,12 +1032,14 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO { struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p)->(%p): stub\n", source, characteristics); + TRACE("(%p)->(%p)\n", source, characteristics);
if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- return E_NOTIMPL; + *characteristics = MFMEDIASOURCE_CAN_SEEK; + + return S_OK; }
static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
--- dlls/winegstreamer/media_source.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 913b1cc9e93..41a738525ca 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -681,12 +681,15 @@ static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMedi { struct media_stream *stream = impl_from_IMFMediaStream(iface);
- FIXME("stub (%p)->(%p)\n", stream, source); + TRACE("(%p)->(%p)\n", stream, source);
if (stream->state == STREAM_SHUTDOWN) return MF_E_SHUTDOWN;
- return E_NOTIMPL; + IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface); + *source = &stream->parent_source->IMFMediaSource_iface; + + return S_OK; }
static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winegstreamer/media_source.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 41a738525ca..b7f3e6c2946 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1237,6 +1237,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
struct media_source *object = heap_alloc_zero(sizeof(*object)); IMFStreamDescriptor **descriptors = NULL; + gint64 total_pres_time = 0; unsigned int i; HRESULT hr; int ret; @@ -1347,6 +1348,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ heap_free(descriptors); descriptors = NULL;
+ for (unsigned int i = 0; i < object->stream_count; i++) + { + GstQuery *query = gst_query_new_duration(GST_FORMAT_TIME); + if (gst_pad_query(object->streams[i]->their_src, query)) + { + gint64 stream_pres_time; + gst_query_parse_duration(query, NULL, &stream_pres_time); + + TRACE("Stream %u has duration %llu\n", i, (unsigned long long int) stream_pres_time); + + if (stream_pres_time > total_pres_time) + total_pres_time = stream_pres_time; + } + else + { + WARN("Unable to get presentation time of stream %u\n", i); + } + } + + if (object->stream_count) + IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time / 100); + object->state = SOURCE_STOPPED;
*out_media_source = object;
On 11/2/20 10:26 AM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/media_source.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 41a738525ca..b7f3e6c2946 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1237,6 +1237,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
struct media_source *object = heap_alloc_zero(sizeof(*object)); IMFStreamDescriptor **descriptors = NULL;
- gint64 total_pres_time = 0; unsigned int i; HRESULT hr; int ret;
@@ -1347,6 +1348,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ heap_free(descriptors); descriptors = NULL;
- for (unsigned int i = 0; i < object->stream_count; i++)
Misplaced initializer.
- {
GstQuery *query = gst_query_new_duration(GST_FORMAT_TIME);
if (gst_pad_query(object->streams[i]->their_src, query))
{
gint64 stream_pres_time;
gst_query_parse_duration(query, NULL, &stream_pres_time);
There is a gst_pad_query_duration() helper for this.
TRACE("Stream %u has duration %llu\n", i, (unsigned long long int) stream_pres_time);
if (stream_pres_time > total_pres_time)
total_pres_time = stream_pres_time;
}
else
{
WARN("Unable to get presentation time of stream %u\n", i);
}
}
if (object->stream_count)
IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time / 100);
object->state = SOURCE_STOPPED;
*out_media_source = object;
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winegstreamer/media_source.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index b7f3e6c2946..62cee6880fd 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1237,6 +1237,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
struct media_source *object = heap_alloc_zero(sizeof(*object)); IMFStreamDescriptor **descriptors = NULL; + IMFAttributes *byte_stream_attributes; gint64 total_pres_time = 0; unsigned int i; HRESULT hr; @@ -1370,6 +1371,18 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (object->stream_count) IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time / 100);
+ if (SUCCEEDED(IMFByteStream_QueryInterface(object->byte_stream, &IID_IMFAttributes, (void **)&byte_stream_attributes))) + { + WCHAR *mimeW = NULL; + DWORD length; + if (SUCCEEDED(IMFAttributes_GetAllocatedString(byte_stream_attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length))) + { + IMFPresentationDescriptor_SetString(object->pres_desc, &MF_PD_MIME_TYPE, mimeW); + CoTaskMemFree(mimeW); + } + IMFAttributes_Release(byte_stream_attributes); + } + object->state = SOURCE_STOPPED;
*out_media_source = object;
I have two concerns, or questions:
- do we always return uncompressed types from winegstreamer source? If so won't this mime type contradict raw format that it actually returns? - if we need to return mime attribute, is it possible to get it from some gstreamer attribute and not from original bytestream attribute, that occasionally we set automatically?
On 11/2/20 11:02 AM, Nikolay Sivov wrote:
I have two concerns, or questions:
- do we always return uncompressed types from winegstreamer source? If
so won't this mime type contradict raw format that it actually returns?
Yes, as of right now, all the streams are uncompressed. The MF_PD_MIME_TYPE attribute on the other hand doesn't specify the type of the streams (after all, it's only set on a per presentation descriptor basis). I think it's safe to assume it represents the mime type of the input data, which all streams share. The documentation on this is again lacking.
- if we need to return mime attribute, is it possible to get it from
some gstreamer attribute and not from original bytestream attribute, that occasionally we set automatically?
Yes, this should be possible, I would assume it's sent through a tag event.
On 11/2/20 11:12 AM, Derek Lesho wrote:
On 11/2/20 11:02 AM, Nikolay Sivov wrote:
I have two concerns, or questions:
- do we always return uncompressed types from winegstreamer source? If
so won't this mime type contradict raw format that it actually returns?
Yes, as of right now, all the streams are uncompressed. The MF_PD_MIME_TYPE attribute on the other hand doesn't specify the type of the streams (after all, it's only set on a per presentation descriptor basis). I think it's safe to assume it represents the mime type of the input data, which all streams share. The documentation on this is again lacking.
Instead of assuming, can't we just write tests?
- if we need to return mime attribute, is it possible to get it from
some gstreamer attribute and not from original bytestream attribute, that occasionally we set automatically?
Yes, this should be possible, I would assume it's sent through a tag event.
On 11/2/20 11:13 AM, Zebediah Figura wrote:
On 11/2/20 11:12 AM, Derek Lesho wrote:
On 11/2/20 11:02 AM, Nikolay Sivov wrote:
I have two concerns, or questions:
- do we always return uncompressed types from winegstreamer source? If
so won't this mime type contradict raw format that it actually returns?
Yes, as of right now, all the streams are uncompressed. The MF_PD_MIME_TYPE attribute on the other hand doesn't specify the type of the streams (after all, it's only set on a per presentation descriptor basis). I think it's safe to assume it represents the mime type of the input data, which all streams share. The documentation on this is again lacking.
Instead of assuming, can't we just write tests?
I mean, yeah, but I'm not sure how useful that would be when real media sources always output uncompressed types anyway. Something useful to test though might be whether MF_PD_MIME_TYPE always mirrors MF_BYTESTREAM_CONTENT_TYPE.
- if we need to return mime attribute, is it possible to get it from
some gstreamer attribute and not from original bytestream attribute, that occasionally we set automatically?
Yes, this should be possible, I would assume it's sent through a tag event.
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winegstreamer/media_source.c | 111 ++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 62cee6880fd..ffc36de115b 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -91,6 +91,8 @@ struct source_async_command struct media_source { IMFMediaSource IMFMediaSource_iface; + IMFGetService IMFGetService_iface; + IMFSeekInfo IMFSeekInfo_iface; IMFAsyncCallback async_commands_callback; LONG ref; DWORD async_commands_queue; @@ -123,6 +125,16 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); }
+static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface); +} + +static inline struct media_source *impl_from_IMFSeekInfo(IMFSeekInfo *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFSeekInfo_iface); +} + static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface) { return CONTAINING_RECORD(iface, struct media_source, async_commands_callback); @@ -956,6 +968,10 @@ static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID { *out = &source->IMFMediaSource_iface; } + else if(IsEqualIID(riid, &IID_IMFGetService)) + { + *out = &source->IMFGetService_iface; + } else { FIXME("(%s, %p)\n", debugstr_guid(riid), out); @@ -1185,6 +1201,99 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, };
+static HRESULT WINAPI source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFGetService(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI source_get_service_AddRef(IMFGetService *iface) +{ + struct media_source *source = impl_from_IMFGetService(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI source_get_service_Release(IMFGetService *iface) +{ + struct media_source *source = impl_from_IMFGetService(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFGetService(iface); + + TRACE("(%p)->(%s, %s, %p)\n", source, debugstr_guid(service), debugstr_guid(riid), obj); + + if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + *obj = NULL; + + if (IsEqualIID(service, &MF_SCRUBBING_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMFSeekInfo)) + { + *obj = &source->IMFSeekInfo_iface; + } + } + + if (*obj) + IUnknown_AddRef((IUnknown*) *obj); + + return *obj ? S_OK : E_NOINTERFACE; +} + +static const IMFGetServiceVtbl IMFGetService_vtbl = +{ + source_get_service_QueryInterface, + source_get_service_AddRef, + source_get_service_Release, + source_get_service_GetService, +}; + +static HRESULT WINAPI source_seek_info_QueryInterface(IMFSeekInfo *iface, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFSeekInfo(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI source_seek_info_AddRef(IMFSeekInfo *iface) +{ + struct media_source *source = impl_from_IMFSeekInfo(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI source_seek_info_Release(IMFSeekInfo *iface) +{ + struct media_source *source = impl_from_IMFSeekInfo(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI source_seek_info_GetNearestKeyFrames(IMFSeekInfo *iface, const GUID *format, + const PROPVARIANT *position, PROPVARIANT *prev_frame, PROPVARIANT *next_frame) +{ + struct media_source *source = impl_from_IMFSeekInfo(iface); + + FIXME("(%p)->(%s, %p, %p, %p) - semi-stub\n", source, debugstr_guid(format), position, prev_frame, next_frame); + + if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + PropVariantCopy(prev_frame, position); + PropVariantCopy(next_frame, position); + + return S_OK; +} + +static const IMFSeekInfoVtbl IMFSeekInfo_vtbl = +{ + source_seek_info_QueryInterface, + source_seek_info_AddRef, + source_seek_info_Release, + source_seek_info_GetNearestKeyFrames, +}; + static void stream_added(GstElement *element, GstPad *pad, gpointer user) { struct media_source *source = user; @@ -1247,6 +1356,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ return E_OUTOFMEMORY;
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; + object->IMFGetService_iface.lpVtbl = &IMFGetService_vtbl; + object->IMFSeekInfo_iface.lpVtbl = &IMFSeekInfo_vtbl; object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl; object->ref = 1; object->byte_stream = bytestream;
On 11/2/20 7:26 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/media_source.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index dbc656a24da..913b1cc9e93 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1032,12 +1032,14 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO { struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p)->(%p): stub\n", source, characteristics);
TRACE("(%p)->(%p)\n", source, characteristics);
if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- return E_NOTIMPL;
- *characteristics = MFMEDIASOURCE_CAN_SEEK;
- return S_OK;
}
static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
I think if the choice is between 0 and CAN_SEEK, it should consider MFBYTESTREAM_IS_SEEKABLE. Unless of course if winegstreamer code currently won't work for non-seekable bytestreams at all.
On 11/2/20 10:47 AM, Nikolay Sivov wrote:
On 11/2/20 7:26 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/media_source.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index dbc656a24da..913b1cc9e93 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1032,12 +1032,14 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO { struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p)->(%p): stub\n", source, characteristics);
TRACE("(%p)->(%p)\n", source, characteristics);
if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- return E_NOTIMPL;
*characteristics = MFMEDIASOURCE_CAN_SEEK;
return S_OK; }
static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
I think if the choice is between 0 and CAN_SEEK, it should consider MFBYTESTREAM_IS_SEEKABLE. Unless of course if winegstreamer code currently won't work for non-seekable bytestreams at all.
Since we are now using typefind for the input because Zebediah wanted a generic source, it seems that the SetCurrentPosition is used after typefind figures out what type of data the input is. So if the absence of MFBYTESTREAM_IS_SEEKABLE means SetCurrentPosition doesn't work, then yeah, I don't think the current code would work with such a bytestream at all. On the other hand, if MFBYTESTREAM_IS_SEEKABLE only indicates whether IMFByteStream::Seek is functional, then we should be fine as we never use that method. The documentation on this isn't clear.
On 11/2/20 11:00 AM, Derek Lesho wrote:
On 11/2/20 10:47 AM, Nikolay Sivov wrote:
On 11/2/20 7:26 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/media_source.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index dbc656a24da..913b1cc9e93 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1032,12 +1032,14 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO { struct media_source *source = impl_from_IMFMediaSource(iface); - FIXME("(%p)->(%p): stub\n", source, characteristics); + TRACE("(%p)->(%p)\n", source, characteristics); if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN; - return E_NOTIMPL; + *characteristics = MFMEDIASOURCE_CAN_SEEK;
+ return S_OK; } static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
I think if the choice is between 0 and CAN_SEEK, it should consider MFBYTESTREAM_IS_SEEKABLE. Unless of course if winegstreamer code currently won't work for non-seekable bytestreams at all.
Since we are now using typefind for the input because Zebediah wanted a generic source, it seems that the SetCurrentPosition is used after typefind figures out what type of data the input is. So if the absence of MFBYTESTREAM_IS_SEEKABLE means SetCurrentPosition doesn't work, then yeah, I don't think the current code would work with such a bytestream at all. On the other hand, if MFBYTESTREAM_IS_SEEKABLE only indicates whether IMFByteStream::Seek is functional, then we should be fine as we never use that method. The documentation on this isn't clear.
It seems fair to assume that MFBYTESTREAM_IS_SEEKABLE also covers SetCurrentPosition(). I'd assume that flag covers all random access, and would be clear for e.g. a TCP byte stream.
[Incidentally, although this is an implementation detail, typefind does support streams which can't seek, although perhaps not very well, and it seems to need push mode.]
On 11/2/20 11:13 AM, Zebediah Figura wrote:
It seems fair to assume that MFBYTESTREAM_IS_SEEKABLE also covers SetCurrentPosition(). I'd assume that flag covers all random access, and would be clear for e.g. a TCP byte stream.
Shall we just fail media source creation when the byte stream doesn't have MFBYTESTREAM_IS_SEEKABLE for now and deal with it once somebody finds an application that actually requires us to handle it?