Commit efe8bc01 authored by Alfred Agrell's avatar Alfred Agrell Committed by Alexandre Julliard

winegstreamer: Implement compressed output support in WMSyncReader.

parent 2cdb8cda
...@@ -30,10 +30,6 @@ struct wm_stream ...@@ -30,10 +30,6 @@ struct wm_stream
WMT_STREAM_SELECTION selection; WMT_STREAM_SELECTION selection;
WORD index; WORD index;
bool eos; bool eos;
/* Note that we only pretend to read compressed samples, and instead output
* uncompressed samples regardless of whether we are configured to read
* compressed samples. Rather, the behaviour of the reader objects differs
* in nontrivial ways depending on this field. */
bool read_compressed; bool read_compressed;
IWMReaderAllocatorEx *output_allocator; IWMReaderAllocatorEx *output_allocator;
...@@ -1541,6 +1537,78 @@ out_destroy_parser: ...@@ -1541,6 +1537,78 @@ out_destroy_parser:
return hr; return hr;
} }
static HRESULT reinit_stream(struct wm_reader *reader, bool read_compressed)
{
wg_parser_t wg_parser;
HRESULT hr;
WORD i;
wg_parser_disconnect(reader->wg_parser);
EnterCriticalSection(&reader->shutdown_cs);
reader->read_thread_shutdown = true;
LeaveCriticalSection(&reader->shutdown_cs);
WaitForSingleObject(reader->read_thread, INFINITE);
CloseHandle(reader->read_thread);
reader->read_thread = NULL;
wg_parser_destroy(reader->wg_parser);
reader->wg_parser = 0;
if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, read_compressed)))
return E_OUTOFMEMORY;
reader->wg_parser = wg_parser;
reader->read_thread_shutdown = false;
if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL)))
{
hr = E_OUTOFMEMORY;
goto out_destroy_parser;
}
if (FAILED(hr = wg_parser_connect(reader->wg_parser, reader->file_size)))
{
ERR("Failed to connect parser, hr %#lx.\n", hr);
goto out_shutdown_thread;
}
assert(reader->stream_count == wg_parser_get_stream_count(reader->wg_parser));
for (i = 0; i < reader->stream_count; ++i)
{
struct wm_stream *stream = &reader->streams[i];
struct wg_format format;
stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i);
stream->reader = reader;
wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
if (stream->selection == WMT_ON)
wg_parser_stream_enable(stream->wg_stream, read_compressed ? &format : &stream->format);
}
/* 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);
return S_OK;
out_shutdown_thread:
EnterCriticalSection(&reader->shutdown_cs);
reader->read_thread_shutdown = true;
LeaveCriticalSection(&reader->shutdown_cs);
WaitForSingleObject(reader->read_thread, INFINITE);
CloseHandle(reader->read_thread);
reader->read_thread = NULL;
out_destroy_parser:
wg_parser_destroy(reader->wg_parser);
reader->wg_parser = 0;
return hr;
}
static struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number) static 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) if (stream_number && stream_number <= reader->stream_count)
...@@ -2352,6 +2420,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st ...@@ -2352,6 +2420,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st
} }
stream->read_compressed = compressed; stream->read_compressed = compressed;
reinit_stream(reader, compressed);
LeaveCriticalSection(&reader->cs); LeaveCriticalSection(&reader->cs);
return S_OK; return S_OK;
...@@ -2397,9 +2466,18 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface, ...@@ -2397,9 +2466,18 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface,
FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n", FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
selections[i], stream_numbers[i]); selections[i], stream_numbers[i]);
TRACE("Enabling stream %u.\n", stream_numbers[i]); TRACE("Enabling stream %u.\n", stream_numbers[i]);
if (stream->read_compressed)
{
struct wg_format format;
wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
wg_parser_stream_enable(stream->wg_stream, &format);
}
else
{
wg_parser_stream_enable(stream->wg_stream, &stream->format); wg_parser_stream_enable(stream->wg_stream, &stream->format);
} }
} }
}
LeaveCriticalSection(&reader->cs); LeaveCriticalSection(&reader->cs);
return S_OK; return S_OK;
......
...@@ -455,6 +455,7 @@ struct teststream ...@@ -455,6 +455,7 @@ struct teststream
HANDLE file; HANDLE file;
DWORD input_tid; DWORD input_tid;
DWORD main_tid; DWORD main_tid;
DWORD input_tid_changes;
}; };
static struct teststream *impl_from_IStream(IStream *iface) static struct teststream *impl_from_IStream(IStream *iface)
...@@ -494,12 +495,10 @@ static HRESULT WINAPI stream_Read(IStream *iface, void *data, ULONG size, ULONG ...@@ -494,12 +495,10 @@ static HRESULT WINAPI stream_Read(IStream *iface, void *data, ULONG size, ULONG
if (winetest_debug > 2) if (winetest_debug > 2)
trace("%04lx: IStream::Read(size %lu)\n", GetCurrentThreadId(), size); trace("%04lx: IStream::Read(size %lu)\n", GetCurrentThreadId(), size);
if (!stream->input_tid) if (stream->input_tid != GetCurrentThreadId())
stream->input_tid = GetCurrentThreadId();
else
{ {
todo_wine_if(stream->input_tid == stream->main_tid) ++stream->input_tid_changes;
ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); stream->input_tid = GetCurrentThreadId();
} }
ok(size > 0, "Got zero size.\n"); ok(size > 0, "Got zero size.\n");
...@@ -523,12 +522,10 @@ static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD me ...@@ -523,12 +522,10 @@ static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD me
if (winetest_debug > 2) if (winetest_debug > 2)
trace("%04lx: IStream::Seek(offset %I64u, method %#lx)\n", GetCurrentThreadId(), offset.QuadPart, method); trace("%04lx: IStream::Seek(offset %I64u, method %#lx)\n", GetCurrentThreadId(), offset.QuadPart, method);
if (!stream->input_tid) if (stream->input_tid != GetCurrentThreadId())
stream->input_tid = GetCurrentThreadId();
else
{ {
todo_wine_if(stream->input_tid == stream->main_tid) ++stream->input_tid_changes;
ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); stream->input_tid = GetCurrentThreadId();
} }
GetFileSizeEx(stream->file, &size); GetFileSizeEx(stream->file, &size);
...@@ -588,12 +585,10 @@ static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) ...@@ -588,12 +585,10 @@ static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stat, DWORD flags)
if (winetest_debug > 1) if (winetest_debug > 1)
trace("%04lx: IStream::Stat(flags %#lx)\n", GetCurrentThreadId(), flags); trace("%04lx: IStream::Stat(flags %#lx)\n", GetCurrentThreadId(), flags);
if (!stream->input_tid) if (stream->input_tid != GetCurrentThreadId())
stream->input_tid = GetCurrentThreadId();
else
{ {
todo_wine_if(stream->input_tid == stream->main_tid) ++stream->input_tid_changes;
ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); stream->input_tid = GetCurrentThreadId();
} }
ok(flags == STATFLAG_NONAME, "Got flags %#lx.\n", flags); ok(flags == STATFLAG_NONAME, "Got flags %#lx.\n", flags);
...@@ -1173,6 +1168,7 @@ static void test_sync_reader_settings(void) ...@@ -1173,6 +1168,7 @@ static void test_sync_reader_settings(void)
IWMSyncReader_Release(reader); IWMSyncReader_Release(reader);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount);
todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes);
CloseHandle(stream.file); CloseHandle(stream.file);
ret = DeleteFileW(filename); ret = DeleteFileW(filename);
ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError());
...@@ -1404,7 +1400,6 @@ static void test_sync_reader_streaming(void) ...@@ -1404,7 +1400,6 @@ static void test_sync_reader_streaming(void)
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount);
stream.input_tid = 0; /* FIXME: currently required as Wine calls IStream_Stat synchronously in OpenStream */
SetFilePointer(stream.file, 0, NULL, FILE_BEGIN); SetFilePointer(stream.file, 0, NULL, FILE_BEGIN);
hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface);
ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(hr == S_OK, "Got hr %#lx.\n", hr);
...@@ -1415,6 +1410,7 @@ static void test_sync_reader_streaming(void) ...@@ -1415,6 +1410,7 @@ static void test_sync_reader_streaming(void)
ok(!ref, "Got outstanding refcount %ld.\n", ref); ok(!ref, "Got outstanding refcount %ld.\n", ref);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount);
todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes);
CloseHandle(stream.file); CloseHandle(stream.file);
ret = DeleteFileW(filename); ret = DeleteFileW(filename);
ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError());
...@@ -1775,6 +1771,7 @@ static void test_sync_reader_types(void) ...@@ -1775,6 +1771,7 @@ static void test_sync_reader_types(void)
ok(!ref, "Got outstanding refcount %ld.\n", ref); ok(!ref, "Got outstanding refcount %ld.\n", ref);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount);
todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes);
CloseHandle(stream.file); CloseHandle(stream.file);
ret = DeleteFileW(filename); ret = DeleteFileW(filename);
ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError());
...@@ -2053,7 +2050,7 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, ...@@ -2053,7 +2050,7 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
GetTickCount(), GetCurrentThreadId(), output, time, duration, flags); GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
/* uncompressed samples are slightly out of order because of decoding delay */ /* uncompressed samples are slightly out of order because of decoding delay */
ok(callback->last_pts[output] <= time, "got time %I64d\n", time); ok(callback->last_pts[output] <= time, "expected %I64d <= %I64d\n", callback->last_pts[output], time);
callback->last_pts[output] = time; callback->last_pts[output] = time;
callback->next_pts[output] = time + duration; callback->next_pts[output] = time + duration;
...@@ -2134,7 +2131,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced ...@@ -2134,7 +2131,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced
trace("%lu: %04lx: IWMReaderCallbackAdvanced::OnStreamSample(stream %u, pts %I64u, duration %I64u, flags %#lx)\n", trace("%lu: %04lx: IWMReaderCallbackAdvanced::OnStreamSample(stream %u, pts %I64u, duration %I64u, flags %#lx)\n",
GetTickCount(), GetCurrentThreadId(), stream_number, pts, duration, flags); GetTickCount(), GetCurrentThreadId(), stream_number, pts, duration, flags);
ok(callback->last_pts[output] <= pts, "got pts %I64d\n", pts); ok(callback->last_pts[output] <= pts, "expected %I64d <= %I64d\n", callback->last_pts[output], pts);
callback->last_pts[output] = pts; callback->last_pts[output] = pts;
callback->next_pts[output] = pts + duration; callback->next_pts[output] = pts + duration;
...@@ -2146,7 +2143,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced ...@@ -2146,7 +2143,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced
else else
{ {
ok(callback->callback_tid == GetCurrentThreadId(), "got wrong thread\n"); ok(callback->callback_tid == GetCurrentThreadId(), "got wrong thread\n");
ok(callback->last_pts[1 - output] <= pts, "got pts %I64d\n", pts); ok(callback->last_pts[1 - output] <= pts, "expected %I64d <= %I64d\n", callback->last_pts[1 - output], pts);
} }
if (!callback->output_tid[output]) if (!callback->output_tid[output])
...@@ -2572,8 +2569,6 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ...@@ -2572,8 +2569,6 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
callback->last_pts[1] = 0; callback->last_pts[1] = 0;
callback->next_pts[1] = 0; callback->next_pts[1] = 0;
memset(callback->output_tid, 0, sizeof(callback->output_tid)); memset(callback->output_tid, 0, sizeof(callback->output_tid));
if (callback->stream)
callback->stream->input_tid = 0;
check_async_set_output_setting(advanced, 0, L"DedicatedDeliveryThread", check_async_set_output_setting(advanced, 0, L"DedicatedDeliveryThread",
WMT_TYPE_BOOL, callback->dedicated_threads, S_OK); WMT_TYPE_BOOL, callback->dedicated_threads, S_OK);
...@@ -2709,6 +2704,17 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ...@@ -2709,6 +2704,17 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
todo_wine todo_wine
ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
/* FIXME: native can switch mode without rewinding, but Wine can't */
IWMReader_Stop(reader);
wait_stopped_callback(callback);
callback->last_pts[0] = 0;
callback->next_pts[0] = 0;
callback->last_pts[1] = 0;
callback->next_pts[1] = 0;
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
wait_started_callback(callback);
callback->expect_time = 13460000; callback->expect_time = 13460000;
hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000); hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000);
ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(hr == S_OK, "Got hr %#lx.\n", hr);
...@@ -2716,7 +2722,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ...@@ -2716,7 +2722,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
todo_wine todo_wine
ok(callback->last_pts[0] == 13460000, "Got pts %I64d.\n", callback->last_pts[0]); ok(callback->last_pts[0] == 13460000, "Got pts %I64d.\n", callback->last_pts[0]);
todo_wine todo_wine
ok(callback->next_pts[0] == 13930000, "Got pts %I64d.\n", callback->next_pts[0]); ok(callback->next_pts[0] == 13920000, "Got pts %I64d.\n", callback->next_pts[0]);
todo_wine todo_wine
ok(callback->last_pts[1] == 13260000, "Got pts %I64d.\n", callback->last_pts[1]); ok(callback->last_pts[1] == 13260000, "Got pts %I64d.\n", callback->last_pts[1]);
todo_wine todo_wine
...@@ -2729,6 +2735,16 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ...@@ -2729,6 +2735,16 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(hr == S_OK, "Got hr %#lx.\n", hr);
hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE);
ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(hr == S_OK, "Got hr %#lx.\n", hr);
IWMReader_Stop(reader);
wait_stopped_callback(callback);
callback->last_pts[0] = 0;
callback->next_pts[0] = 0;
callback->last_pts[1] = 0;
callback->next_pts[1] = 0;
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
wait_started_callback(callback);
} }
callback->expect_time = test_wmv_duration * 2; callback->expect_time = test_wmv_duration * 2;
...@@ -3233,7 +3249,6 @@ static void test_async_reader_streaming(void) ...@@ -3233,7 +3249,6 @@ static void test_async_reader_streaming(void)
ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount);
wait_opened_callback(&callback); wait_opened_callback(&callback);
stream.input_tid = 0; /* FIXME: currently required as Wine calls IStream_Stat synchronously in OpenStream */
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0);
ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment