mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 20:07:17 +00:00
winegstreamer: Implement compressed output support in WMSyncReader.
This commit is contained in:
parent
2cdb8cdae1
commit
efe8bc0151
|
@ -30,10 +30,6 @@ struct wm_stream
|
|||
WMT_STREAM_SELECTION selection;
|
||||
WORD index;
|
||||
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;
|
||||
|
||||
IWMReaderAllocatorEx *output_allocator;
|
||||
|
@ -1541,6 +1537,78 @@ out_destroy_parser:
|
|||
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)
|
||||
{
|
||||
if (stream_number && stream_number <= reader->stream_count)
|
||||
|
@ -2352,6 +2420,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st
|
|||
}
|
||||
|
||||
stream->read_compressed = compressed;
|
||||
reinit_stream(reader, compressed);
|
||||
|
||||
LeaveCriticalSection(&reader->cs);
|
||||
return S_OK;
|
||||
|
@ -2397,7 +2466,16 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface,
|
|||
FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
|
||||
selections[i], stream_numbers[i]);
|
||||
TRACE("Enabling stream %u.\n", stream_numbers[i]);
|
||||
wg_parser_stream_enable(stream->wg_stream, &stream->format);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -455,6 +455,7 @@ struct teststream
|
|||
HANDLE file;
|
||||
DWORD input_tid;
|
||||
DWORD main_tid;
|
||||
DWORD input_tid_changes;
|
||||
};
|
||||
|
||||
static struct teststream *impl_from_IStream(IStream *iface)
|
||||
|
@ -494,12 +495,10 @@ static HRESULT WINAPI stream_Read(IStream *iface, void *data, ULONG size, ULONG
|
|||
if (winetest_debug > 2)
|
||||
trace("%04lx: IStream::Read(size %lu)\n", GetCurrentThreadId(), size);
|
||||
|
||||
if (!stream->input_tid)
|
||||
stream->input_tid = GetCurrentThreadId();
|
||||
else
|
||||
if (stream->input_tid != GetCurrentThreadId())
|
||||
{
|
||||
todo_wine_if(stream->input_tid == stream->main_tid)
|
||||
ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n");
|
||||
++stream->input_tid_changes;
|
||||
stream->input_tid = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
ok(size > 0, "Got zero size.\n");
|
||||
|
@ -523,12 +522,10 @@ static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD me
|
|||
if (winetest_debug > 2)
|
||||
trace("%04lx: IStream::Seek(offset %I64u, method %#lx)\n", GetCurrentThreadId(), offset.QuadPart, method);
|
||||
|
||||
if (!stream->input_tid)
|
||||
stream->input_tid = GetCurrentThreadId();
|
||||
else
|
||||
if (stream->input_tid != GetCurrentThreadId())
|
||||
{
|
||||
todo_wine_if(stream->input_tid == stream->main_tid)
|
||||
ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n");
|
||||
++stream->input_tid_changes;
|
||||
stream->input_tid = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
GetFileSizeEx(stream->file, &size);
|
||||
|
@ -588,12 +585,10 @@ static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stat, DWORD flags)
|
|||
if (winetest_debug > 1)
|
||||
trace("%04lx: IStream::Stat(flags %#lx)\n", GetCurrentThreadId(), flags);
|
||||
|
||||
if (!stream->input_tid)
|
||||
stream->input_tid = GetCurrentThreadId();
|
||||
else
|
||||
if (stream->input_tid != GetCurrentThreadId())
|
||||
{
|
||||
todo_wine_if(stream->input_tid == stream->main_tid)
|
||||
ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n");
|
||||
++stream->input_tid_changes;
|
||||
stream->input_tid = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
ok(flags == STATFLAG_NONAME, "Got flags %#lx.\n", flags);
|
||||
|
@ -1173,6 +1168,7 @@ static void test_sync_reader_settings(void)
|
|||
IWMSyncReader_Release(reader);
|
||||
|
||||
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);
|
||||
ret = DeleteFileW(filename);
|
||||
ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError());
|
||||
|
@ -1404,7 +1400,6 @@ static void test_sync_reader_streaming(void)
|
|||
|
||||
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);
|
||||
hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface);
|
||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||
|
@ -1415,6 +1410,7 @@ static void test_sync_reader_streaming(void)
|
|||
ok(!ref, "Got outstanding refcount %ld.\n", ref);
|
||||
|
||||
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);
|
||||
ret = DeleteFileW(filename);
|
||||
ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError());
|
||||
|
@ -1775,6 +1771,7 @@ static void test_sync_reader_types(void)
|
|||
ok(!ref, "Got outstanding refcount %ld.\n", ref);
|
||||
|
||||
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);
|
||||
ret = DeleteFileW(filename);
|
||||
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,
|
|||
GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
|
||||
|
||||
/* 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->next_pts[output] = time + duration;
|
||||
|
||||
|
@ -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",
|
||||
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->next_pts[output] = pts + duration;
|
||||
|
||||
|
@ -2146,7 +2143,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced
|
|||
else
|
||||
{
|
||||
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])
|
||||
|
@ -2572,8 +2569,6 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
|
|||
callback->last_pts[1] = 0;
|
||||
callback->next_pts[1] = 0;
|
||||
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",
|
||||
WMT_TYPE_BOOL, callback->dedicated_threads, S_OK);
|
||||
|
@ -2709,6 +2704,17 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
|
|||
todo_wine
|
||||
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;
|
||||
hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000);
|
||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||
|
@ -2716,7 +2722,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
|
|||
todo_wine
|
||||
ok(callback->last_pts[0] == 13460000, "Got pts %I64d.\n", callback->last_pts[0]);
|
||||
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
|
||||
ok(callback->last_pts[1] == 13260000, "Got pts %I64d.\n", callback->last_pts[1]);
|
||||
todo_wine
|
||||
|
@ -2729,6 +2735,16 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
|
|||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||
hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE);
|
||||
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;
|
||||
|
@ -3233,7 +3249,6 @@ static void test_async_reader_streaming(void)
|
|||
ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount);
|
||||
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);
|
||||
ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
|
||||
|
||||
|
|
Loading…
Reference in a new issue