winegstreamer: Implement IWMSyncReader::GetNextSample().
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
970c1bc49b
commit
3b8579d8a5
|
@ -121,6 +121,7 @@ struct wm_stream
|
|||
struct wm_reader *reader;
|
||||
struct wg_parser_stream *wg_stream;
|
||||
WORD index;
|
||||
bool eos;
|
||||
struct wg_format format;
|
||||
};
|
||||
|
||||
|
@ -159,6 +160,10 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
|
|||
HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count);
|
||||
HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output,
|
||||
IWMOutputMediaProps **props);
|
||||
struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader,
|
||||
WORD stream_number);
|
||||
HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
|
||||
INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags);
|
||||
void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops);
|
||||
HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream);
|
||||
HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
|
||||
|
|
|
@ -167,6 +167,101 @@ static IWMOutputMediaProps *output_props_create(const struct wg_format *format)
|
|||
return &object->IWMOutputMediaProps_iface;
|
||||
}
|
||||
|
||||
struct buffer
|
||||
{
|
||||
INSSBuffer INSSBuffer_iface;
|
||||
LONG refcount;
|
||||
};
|
||||
|
||||
static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
|
||||
{
|
||||
struct buffer *buffer = impl_from_INSSBuffer(iface);
|
||||
|
||||
TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
|
||||
|
||||
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer))
|
||||
*out = &buffer->INSSBuffer_iface;
|
||||
else
|
||||
{
|
||||
*out = NULL;
|
||||
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IUnknown_AddRef((IUnknown *)*out);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
|
||||
{
|
||||
struct buffer *buffer = impl_from_INSSBuffer(iface);
|
||||
ULONG refcount = InterlockedIncrement(&buffer->refcount);
|
||||
|
||||
TRACE("%p increasing refcount to %u.\n", buffer, refcount);
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static ULONG WINAPI buffer_Release(INSSBuffer *iface)
|
||||
{
|
||||
struct buffer *buffer = impl_from_INSSBuffer(iface);
|
||||
ULONG refcount = InterlockedDecrement(&buffer->refcount);
|
||||
|
||||
TRACE("%p decreasing refcount to %u.\n", buffer, refcount);
|
||||
|
||||
if (!refcount)
|
||||
free(buffer);
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
|
||||
{
|
||||
FIXME("iface %p, size %p, stub!\n", iface, size);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
|
||||
{
|
||||
FIXME("iface %p, size %u, stub!\n", iface, size);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
|
||||
{
|
||||
FIXME("iface %p, size %p, stub!\n", iface, size);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
|
||||
{
|
||||
FIXME("iface %p, data %p, stub!\n", iface, data);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
|
||||
{
|
||||
FIXME("iface %p, data %p, size %p, stub!\n", iface, data, size);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const INSSBufferVtbl buffer_vtbl =
|
||||
{
|
||||
buffer_QueryInterface,
|
||||
buffer_AddRef,
|
||||
buffer_Release,
|
||||
buffer_GetLength,
|
||||
buffer_SetLength,
|
||||
buffer_GetMaxLength,
|
||||
buffer_GetBuffer,
|
||||
buffer_GetBufferAndLength,
|
||||
};
|
||||
|
||||
struct stream_config
|
||||
{
|
||||
IWMStreamConfig IWMStreamConfig_iface;
|
||||
|
@ -1231,8 +1326,15 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
|
|||
if (stream->format.u.video.format == WG_VIDEO_FORMAT_I420)
|
||||
stream->format.u.video.format = WG_VIDEO_FORMAT_YV12;
|
||||
}
|
||||
wg_parser_stream_enable(stream->wg_stream, &stream->format);
|
||||
}
|
||||
|
||||
wg_parser_end_flush(reader->wg_parser);
|
||||
/* We probably discarded events because streams weren't enabled yet.
|
||||
* Now that they're all enabled seek back to the start again. */
|
||||
wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
|
||||
AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
|
||||
|
||||
LeaveCriticalSection(&reader->cs);
|
||||
return S_OK;
|
||||
|
||||
|
@ -1281,6 +1383,14 @@ HRESULT wm_reader_close(struct wm_reader *reader)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
|
||||
{
|
||||
if (stream_number && stream_number <= reader->stream_count)
|
||||
return &reader->streams[stream_number - 1];
|
||||
WARN("Invalid stream number %u.\n", stream_number);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props)
|
||||
{
|
||||
struct wm_stream *stream;
|
||||
|
@ -1429,6 +1539,88 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static const char *get_major_type_string(enum wg_major_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case WG_MAJOR_TYPE_AUDIO:
|
||||
return "audio";
|
||||
case WG_MAJOR_TYPE_VIDEO:
|
||||
return "video";
|
||||
case WG_MAJOR_TYPE_UNKNOWN:
|
||||
return "unknown";
|
||||
}
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
|
||||
INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags)
|
||||
{
|
||||
struct wg_parser_stream *wg_stream = stream->wg_stream;
|
||||
struct wg_parser_event event;
|
||||
struct buffer *object;
|
||||
|
||||
if (stream->eos)
|
||||
return NS_E_NO_MORE_SAMPLES;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!wg_parser_stream_get_event(wg_stream, &event))
|
||||
{
|
||||
FIXME("Stream is flushing.\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
TRACE("Got event of type %#x for %s stream %p.\n", event.type,
|
||||
get_major_type_string(stream->format.major_type), stream);
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case WG_PARSER_EVENT_BUFFER:
|
||||
/* FIXME: Should these be pooled? */
|
||||
if (!(object = calloc(1, sizeof(*object))))
|
||||
{
|
||||
wg_parser_stream_release_buffer(wg_stream);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
|
||||
object->refcount = 1;
|
||||
|
||||
wg_parser_stream_release_buffer(wg_stream);
|
||||
|
||||
if (!event.u.buffer.has_pts)
|
||||
FIXME("Missing PTS.\n");
|
||||
if (!event.u.buffer.has_duration)
|
||||
FIXME("Missing duration.\n");
|
||||
|
||||
*pts = event.u.buffer.pts;
|
||||
*duration = event.u.buffer.duration;
|
||||
*flags = 0;
|
||||
if (event.u.buffer.discontinuity)
|
||||
*flags |= WM_SF_DISCONTINUITY;
|
||||
if (!event.u.buffer.delta)
|
||||
*flags |= WM_SF_CLEANPOINT;
|
||||
|
||||
TRACE("Created buffer %p.\n", object);
|
||||
*ret_sample = &object->INSSBuffer_iface;
|
||||
return S_OK;
|
||||
|
||||
case WG_PARSER_EVENT_EOS:
|
||||
stream->eos = true;
|
||||
TRACE("End of stream.\n");
|
||||
return NS_E_NO_MORE_SAMPLES;
|
||||
|
||||
case WG_PARSER_EVENT_SEGMENT:
|
||||
break;
|
||||
|
||||
case WG_PARSER_EVENT_NONE:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
|
||||
{
|
||||
reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
|
||||
|
|
|
@ -76,13 +76,42 @@ static HRESULT WINAPI WMSyncReader_GetMaxStreamSampleSize(IWMSyncReader2 *iface,
|
|||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface, WORD stream, INSSBuffer **sample,
|
||||
QWORD *sample_time, QWORD *sample_duration, DWORD *flags, DWORD *output_num, WORD *stream_num)
|
||||
static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface,
|
||||
WORD stream_number, INSSBuffer **sample, QWORD *pts, QWORD *duration,
|
||||
DWORD *flags, DWORD *output_number, WORD *ret_stream_number)
|
||||
{
|
||||
struct sync_reader *This = impl_from_IWMSyncReader2(iface);
|
||||
FIXME("(%p)->(%d %p %p %p %p %p %p): stub!\n", This, stream, sample, sample_time,
|
||||
sample_duration, flags, output_num, stream_num);
|
||||
return E_NOTIMPL;
|
||||
struct sync_reader *reader = impl_from_IWMSyncReader2(iface);
|
||||
struct wm_stream *stream;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p,"
|
||||
" flags %p, output_number %p, ret_stream_number %p.\n",
|
||||
reader, stream_number, sample, pts, duration, flags, output_number, ret_stream_number);
|
||||
|
||||
EnterCriticalSection(&reader->reader.cs);
|
||||
|
||||
if (!stream_number)
|
||||
{
|
||||
FIXME("Reading from all streams is not implemented yet.\n");
|
||||
hr = E_NOTIMPL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(stream = wm_reader_get_stream_by_stream_number(&reader->reader, stream_number)))
|
||||
{
|
||||
LeaveCriticalSection(&reader->reader.cs);
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
hr = wm_reader_get_stream_sample(stream, sample, pts, duration, flags);
|
||||
if (hr == S_OK && output_number)
|
||||
*output_number = stream->index;
|
||||
if (ret_stream_number)
|
||||
*ret_stream_number = stream->index + 1;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&reader->reader.cs);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI WMSyncReader_GetOutputCount(IWMSyncReader2 *iface, DWORD *count)
|
||||
|
|
|
@ -500,7 +500,7 @@ static void test_sync_reader_streaming(void)
|
|||
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[j], &sample,
|
||||
&pts, &duration, &flags, &output_number, &stream_number);
|
||||
if (first)
|
||||
todo_wine ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr);
|
||||
ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr);
|
||||
else if (eos[j])
|
||||
ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
else
|
||||
|
@ -527,7 +527,7 @@ static void test_sync_reader_streaming(void)
|
|||
eos[j] = true;
|
||||
}
|
||||
|
||||
todo_wine ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n",
|
||||
ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n",
|
||||
stream_numbers[j], stream_number);
|
||||
}
|
||||
first = false;
|
||||
|
@ -535,11 +535,11 @@ static void test_sync_reader_streaming(void)
|
|||
|
||||
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample,
|
||||
&pts, &duration, &flags, NULL, NULL);
|
||||
todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
|
||||
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample,
|
||||
&pts, &duration, &flags, NULL, NULL);
|
||||
todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
|
||||
hr = IWMSyncReader_SetRange(reader, 0, 0);
|
||||
todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
|
||||
|
@ -593,11 +593,11 @@ static void test_sync_reader_streaming(void)
|
|||
|
||||
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample,
|
||||
&pts, &duration, &flags, NULL, NULL);
|
||||
todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
|
||||
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample,
|
||||
&pts, &duration, &flags, NULL, NULL);
|
||||
todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
|
||||
|
||||
hr = IWMSyncReader_Close(reader);
|
||||
ok(hr == S_OK, "Got hr %#x.\n", hr);
|
||||
|
|
|
@ -81,6 +81,13 @@ typedef struct _WMReaderClientInfo
|
|||
WCHAR *wszPlayerUserAgent;
|
||||
} WM_READER_CLIENTINFO;
|
||||
|
||||
enum
|
||||
{
|
||||
WM_SF_CLEANPOINT = 0x1,
|
||||
WM_SF_DISCONTINUITY = 0x2,
|
||||
WM_SF_DATALOSS = 0x4,
|
||||
};
|
||||
|
||||
typedef enum WMT_ATTR_DATATYPE
|
||||
{
|
||||
WMT_TYPE_DWORD = 0,
|
||||
|
|
Loading…
Reference in New Issue