Marked as WIP since it depends on !8175 for the test to run reliably (and currently includes its commits).
Tests should be run both with HKCU\Software\Wine\MediaFoundation\DisableGstByteStreamHandler enabled and disabled.
-- v2: mfsrcsnk: Support thinning. winedmo: Support thinning. winegstreamer: Support thinning in media source.
From: Charlotte Pabst cpabst@codeweavers.com
Before this, stopping and restarting the media session could cause MFT streams to get stuck in the "already pending" state, which would lead to no more samples getting delivered. --- dlls/mf/session.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 483ea6f904f..a9213d2cf18 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1014,8 +1014,13 @@ static void session_flush_nodes(struct media_session *session) { if (node->type == MF_TOPOLOGY_OUTPUT_NODE) IMFStreamSink_Flush(node->object.sink_stream); - else if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) + else if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) { + UINT i; + for (i = 0; i < node->u.transform.output_count; i++) + node->u.transform.outputs[i].requests = 0; + IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + } } }
From: Charlotte Pabst cpabst@codeweavers.com
This reverts commit 18c0dd7390b354d2e505e54cd3f3f9b08226b265.
The actual bug that broke sample delivery was in mf session code.
This commit is faulty since the Flush() method - which is called at session Stop, but runs after sample_grabber_set_state - already releases pending items, while processing markers immediately. --- dlls/mf/samplegrabber.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 016c68f98b8..de599139736 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -1191,7 +1191,6 @@ static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sin sample_grabber_cancel_timer(grabber); release_samples(grabber); grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH; - sample_grabber_release_pending_items(grabber); }
if (state == SINK_STATE_RUNNING && grabber->state != SINK_STATE_RUNNING)
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mf/tests/longtest.mp4 | Bin 0 -> 22658 bytes dlls/mf/tests/mf.c | 250 +++++++++++++++++++++++++++++++- dlls/mf/tests/resource.rc | 13 ++ dlls/mf/tests/rgb32-3frames.bmp | Bin 0 -> 49314 bytes dlls/mf/tests/thinning_test.mp4 | Bin 0 -> 7199 bytes 5 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 dlls/mf/tests/longtest.mp4 create mode 100644 dlls/mf/tests/rgb32-3frames.bmp create mode 100644 dlls/mf/tests/thinning_test.mp4
diff --git a/dlls/mf/tests/longtest.mp4 b/dlls/mf/tests/longtest.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..9015490d8f415313a9a7c0479238af6c8caad52d GIT binary patch literal 22658 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
literal 0 HcmV?d00001
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 37c1b0be456..dc31e0c2228 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2625,6 +2625,9 @@ struct test_grabber_callback IMFCollection *samples; HANDLE ready_event; HANDLE done_event; + HANDLE new_ready_event; + + BOOL enable_timestamps; };
static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) @@ -2661,6 +2664,8 @@ static ULONG WINAPI test_grabber_callback_Release(IMFSampleGrabberSinkCallback * if (!refcount) { IMFCollection_Release(grabber->samples); + if (grabber->new_ready_event && grabber->new_ready_event != grabber->ready_event) + CloseHandle(grabber->new_ready_event); if (grabber->ready_event) CloseHandle(grabber->ready_event); if (grabber->done_event) @@ -2673,6 +2678,10 @@ static ULONG WINAPI test_grabber_callback_Release(IMFSampleGrabberSinkCallback *
static HRESULT WINAPI test_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface, MFTIME time, LONGLONG offset) { + struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); + IMFCollection_RemoveAllElements(grabber->samples); + if (grabber->new_ready_event) + grabber->ready_event = grabber->new_ready_event; return S_OK; }
@@ -2717,7 +2726,7 @@ static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSink hr = IMFSample_SetSampleFlags(sample, sample_flags); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); /* FIXME: sample time is inconsistent across windows versions, ignore it */ - hr = IMFSample_SetSampleTime(sample, 0); + hr = IMFSample_SetSampleTime(sample, grabber->enable_timestamps ? sample_time : 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSample_SetSampleDuration(sample, sample_duration); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -6802,6 +6811,244 @@ static void test_media_session_Close(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
+static void grab_samples_from_start(IMFMediaSession *session, IMFAsyncCallback *callback, struct test_grabber_callback *grabber_callback, UINT n) +{ + DWORD res; + PROPVARIANT propvar; + HRESULT hr; + IMFMediaStream *stream = NULL; + + hr = IMFMediaSession_Stop(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + propvar.vt = VT_I8; + propvar.hVal.QuadPart = 0; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + for (UINT i = 0; i < n; i++) { + res = WaitForSingleObject(grabber_callback->new_ready_event, 5000); + ok(!res, "WaitForSingleObject returned %#lx\n", res); + + if (res) + break; + + if (i+1 == n) + grabber_callback->ready_event = NULL; + + SetEvent(grabber_callback->done_event); + } +} + +static void test_media_session_thinning(void) +{ + media_type_desc video_rgb32_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + }; + const struct buffer_desc buffer_desc = + { + .length = 64 * 64 * 4, + .compare = compare_rgb32, .compare_rect = {.right = 64, .bottom = 64}, + .dump = dump_rgb32, .size = {.cx = 64, .cy = 64}, + }; + struct sample_desc thin_sample_desc[3] = + { + { .sample_duration = 333667, .buffer_count = 1, .buffers = &buffer_desc, .total_length = 64*64*4, .sample_time = 333666.666 * 0, }, + { .sample_duration = 333667, .buffer_count = 1, .buffers = &buffer_desc, .total_length = 64*64*4, .sample_time = 333666.666 * 5, }, + { .sample_duration = 333667, .buffer_count = 1, .buffers = &buffer_desc, .total_length = 64*64*4, .sample_time = 333666.666 * 10, }, + }; + struct sample_desc nonthin_sample_desc = + { .sample_duration = 333667, .buffer_count = 1, .buffers = &buffer_desc, .total_length = 64*64*4, .sample_time = 0, .repeat_count = 2, }; + struct test_grabber_callback *grabber_callback; + IMFRateControl *rate_control, *clock_rate_control; + IMFActivate *sink_activate; + IMFAsyncCallback *callback; + IMFMediaType *output_type; + IMFMediaSession *session; + IMFMediaSource *source; + IMFTopology *topology; + IMFClock *clock; + IMFSample *first_sample; + LONGLONG first_sample_time = 0; + PROPVARIANT propvar; + float rate; + BOOL thin; + HRESULT hr; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + if (!(source = create_media_source(L"thinning_test.mp4", L"video/mp4"))) + { + todo_wine /* Gitlab CI Debian runner */ + win_skip("MP4 media source is not supported, skipping tests.\n"); + MFShutdown(); + return; + } + + callback = create_test_callback(TRUE); + + grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + grabber_callback->done_event = CreateEventW(NULL, FALSE, FALSE, NULL); + grabber_callback->enable_timestamps = TRUE; + ok(!!grabber_callback->done_event, "CreateEventW failed, error %lu\n", GetLastError()); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(output_type, video_rgb32_desc, -1); + hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + IMFMediaType_Release(output_type); + + topology = create_test_topology(source, sink_activate, NULL); + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* get rate control interfaces */ + + hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); + ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr); + + hr = IMFMediaSession_GetClock(session, &clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&clock_rate_control); + ok(hr == S_OK, "Failed to get rate control, hr %#lx.\n", hr); + IMFClock_Release(clock); + + /* try faster rate */ + + hr = IMFRateControl_SetRate(rate_control, FALSE, 1.5f); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + rate = 0.0f; + thin = TRUE; + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!thin, "Unexpected thin.\n"); + ok(rate == 1.5f, "Unexpected rate %f.\n", rate); + + /* try thinning */ + + hr = IMFRateControl_SetRate(rate_control, TRUE, 5.0f); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionRateChanged, 1000, &propvar); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + rate = 0.0f; + thin = FALSE; + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(thin, "Unexpected !thin.\n"); + todo_wine + ok(rate == 5.0f, "Unexpected rate %f.\n", rate); + + /* clock is unaware of thinning */ + + hr = IMFMediaSession_GetClock(session, &clock); + ok(hr == S_OK, "Failed to get clock, hr %#lx.\n", hr); + + hr = IMFClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&clock_rate_control); + ok(hr == S_OK, "Failed to get rate control, hr %#lx.\n", hr); + + rate = 0.0f; + thin = TRUE; + hr = IMFRateControl_GetRate(clock_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!thin, "Unexpected thin.\n"); + todo_wine + ok(rate == 5.0f, "Unexpected rate %f.\n", rate); + + /* get first sample time */ + + grabber_callback->new_ready_event = grabber_callback->new_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!grabber_callback->new_ready_event, "CreateEventW failed, error %lu\n", GetLastError()); + + grab_samples_from_start(session, callback, grabber_callback, 1); + + hr = IMFCollection_GetElement(grabber_callback->samples, 0, (IUnknown **) &first_sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (hr == S_OK) { + hr = IMFSample_GetSampleTime(first_sample, &first_sample_time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFSample_Release(first_sample); + + nonthin_sample_desc.sample_time += first_sample_time; + for (UINT i = 0; i < 3; i++) + thin_sample_desc[i].sample_time += first_sample_time; + } + + /* test thinned */ + + thin_sample_desc[1].todo_time = TRUE; + thin_sample_desc[2].todo_time = TRUE; + + grab_samples_from_start(session, callback, grabber_callback, 3); + check_mf_sample_collection(grabber_callback->samples, thin_sample_desc, L"rgb32-3frames.bmp"); + + /* test non-thinned */ + + hr = IMFRateControl_SetRate(rate_control, FALSE, 1.0f); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + grab_samples_from_start(session, callback, grabber_callback, 3); + check_mf_sample_collection(grabber_callback->samples, &nonthin_sample_desc, L"rgb32-3frames.bmp"); + + /* shut down */ + + CloseHandle(grabber_callback->new_ready_event); + grabber_callback->new_ready_event = NULL; + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFActivate_ShutdownObject(sink_activate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFRateControl_Release(rate_control); + IMFRateControl_Release(clock_rate_control); + IMFMediaSource_Release(source); + IMFAsyncCallback_Release(callback); + IMFMediaSession_Release(session); + IMFActivate_ShutdownObject(sink_activate); + IMFActivate_Release(sink_activate); + IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); + + hr = MFShutdown(); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + START_TEST(mf) { init_functions(); @@ -6838,4 +7085,5 @@ START_TEST(mf) test_MFEnumDeviceSources(); test_media_session_Close(); test_media_session_source_shutdown(); + test_media_session_thinning(); } diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index 873d373e079..8f093bd1af5 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -141,6 +141,10 @@ abgr32frame-crop.bmp RCDATA abgr32frame-crop.bmp /* @makedep: rgb32frame-grabber.bmp */ rgb32frame-grabber.bmp RCDATA rgb32frame-grabber.bmp
+/* Generated from running the tests on Windows */ +/* @makedep: rgb32-3frames.bmp */ +rgb32-3frames.bmp RCDATA rgb32-3frames.bmp + /* Generated from running the tests on Windows */ /* @makedep: rgb32frame-extra-width.bmp */ rgb32frame-extra-width.bmp RCDATA rgb32frame-extra-width.bmp @@ -177,3 +181,12 @@ rgb24frame.bmp RCDATA rgb24frame.bmp */ /* @makedep: test.mp4 */ test.mp4 RCDATA test.mp4 + +/* Generated with: + * gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte100 ! \ + * video/x-raw,format=I420,width=64,height=64,framerate=30000/1001 ! \ + * videoflip method=clockwise ! videoconvert ! \ + * x264enc key-int-max=5 ! mp4mux ! filesink location=dlls/mf/tests/thinning_test.mp4 + */ +/* @makedep: thinning_test.mp4 */ +thinning_test.mp4 RCDATA thinning_test.mp4 diff --git a/dlls/mf/tests/rgb32-3frames.bmp b/dlls/mf/tests/rgb32-3frames.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cc29ad6e0faf5b02b99cf136832632be77ab6204 GIT binary patch literal 49314 zcmZ?rHFID912YB&1`P%V1`rp785k76;$Q&?3r_y~_m5!|kA}f$8W>FjqiJB|rGd-; z|1*qa{P6#OhLMbC|NqZ0l5z0YPYfd&yMF(|Fp@FD|Gx|)8T0=8!!VNZNRInazyD=W z{r_Y{<B^^Q_WZA57|Gb_aU;V>#{d5_FpOk;^S30!NX8>M?nnL3!0_=u<A}y1Jq_&q z&&e>7@v8sa3?msQe`a79$ynwu1H(wh+P@eWMlxpj&%iK>N5fz=4UEh*P`I&>VI*Vq zr)mr%8Q+k)$uN>}pI;xtNXCB|{xOW=(J&ZI10ypHTw?prFp}{@=Kl;M8PDSV&oGj4 zFvBN?k&Im!zA%hr%)s!MVI*T7hCd7=8IR<+ANBiR1{KyPBN~tNG_YH?hG8UQM}|g* zk&OQ_GBAu}e1k!fVI<>`9QUJsAK7_-H2z29e>4q@>@+ZXYQX5O=aIMTc{I*P<9sv? zke>!d@`(W;zmMb-13-Qs$tMPY{63OT3;_9kB%c@n^7}~NH9L||3;_9kq{shA_y6dr z0VDg=l#zU50Lbqn`NRN_-$(kc*^zu=0LbqnJ^n|!|3^;^7}=+$jN}soKz<*|CkBB0 zK9Wxi0Qr3+pBMo0`$#@90Oa@4-Qpv2xA<thkH$MF4UFUy13-Qs$tMPY{63OT3;_9k zB%c@n^84s+@sYV(d^Fxi;~kU+M)HXPAis~~69YhgAIT>Mfc!p^PYeM0eI%b40P_1t z-!(guPYeM0eWb_#NcaEfsR1MV)Rd8YVgShRBl*Mtkl#o8uE~*nVgShRBR&2{{XepI z4UfkEX#9_+fsvaAMo$eG-91eH?%~m}8x6bBG%)hg0BGm@NXDR@^CKC9cFvDv4B9zA zk}+uK{7A+leb+Q-=ln><BR&2{y8lN{4H!K&0JM94q+-y{`H_rA`mSlv&iRpyM|%8^ zbpMZ@8Zdfl0BHC8NX4L?^CKC9cFvDv4B9zAk}+uK{7A;2ox`JebO-rp8W@>r0JL*{ zBxBId`H_r4JLg9-2JM_5$r!YAcodKBARkQwBQp(vcFvDv4B9zAk}+uK{7A;2o%16Z zgLcl3WIWP$O@nsMk7PX3<A0?4fArLV(NhCJyXQwL2JM_5$#|sim;~*dAIW&6$N#AR TNA8Z{(YPOt`_VKoveN(nPbC;h
literal 0 HcmV?d00001
diff --git a/dlls/mf/tests/thinning_test.mp4 b/dlls/mf/tests/thinning_test.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..7e9f7206b5686a2aa79bbe2808dee42c76016d3e GIT binary patch literal 7199 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 E0NSC6RsaA1
literal 0 HcmV?d00001
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mf/session.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index a9213d2cf18..823388c3065 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -260,6 +260,8 @@ struct media_session /* Latest SetRate() arguments. */ BOOL thin; float rate; + + BOOL thin_committed; } presentation; struct list topologies; struct list commands; @@ -1540,7 +1542,7 @@ static void session_set_rate(struct media_session *session, BOOL thin, float rat if (SUCCEEDED(hr)) hr = IMFRateControl_GetRate(session->clock_rate_control, NULL, &clock_rate);
- if (SUCCEEDED(hr) && (rate != clock_rate) && SUCCEEDED(hr = session_subscribe_sources(session))) + if (SUCCEEDED(hr) && (rate != clock_rate || thin != session->presentation.thin_committed) && SUCCEEDED(hr = session_subscribe_sources(session))) { LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -1553,6 +1555,7 @@ static void session_set_rate(struct media_session *session, BOOL thin, float rat { session->presentation.flags |= SESSION_FLAG_PENDING_RATE_CHANGE; session->presentation.rate = rate; + session->presentation.thin = thin; return; } } @@ -1577,7 +1580,8 @@ static void session_complete_rate_change(struct media_session *session) session->presentation.flags &= ~SESSION_FLAG_PENDING_RATE_CHANGE; session_set_presentation_clock(session);
- hr = IMFRateControl_SetRate(session->clock_rate_control, session->presentation.thin, + session->presentation.thin_committed = session->presentation.thin; + hr = IMFRateControl_SetRate(session->clock_rate_control, FALSE, session->presentation.rate);
param.vt = VT_R4; @@ -4742,7 +4746,10 @@ static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL *
TRACE("%p, %p, %p.\n", iface, thin, rate);
- return IMFRateControl_GetRate(session->clock_rate_control, thin, rate); + if (thin) + *thin = session->presentation.thin_committed; + + return IMFRateControl_GetRate(session->clock_rate_control, NULL, rate); }
static const IMFRateControlVtbl session_rate_control_vtbl =
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/main.c | 12 +++++++ dlls/winegstreamer/unixlib.h | 8 +++++ dlls/winegstreamer/wg_parser.c | 54 ++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 60e0c3af8bc..2d5986fdb1b 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -81,6 +81,8 @@ void wg_parser_disconnect(wg_parser_t parser); bool wg_parser_get_next_read_offset(wg_parser_t parser, uint64_t *offset, uint32_t *size); void wg_parser_push_data(wg_parser_t parser, const void *data, uint32_t size);
+void wg_parser_set_thinning(wg_parser_t parser, BOOL thinning); + uint32_t wg_parser_get_stream_count(wg_parser_t parser); wg_parser_stream_t wg_parser_get_stream(wg_parser_t parser, uint32_t index);
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index d18db8b21e8..c68cf0c04f1 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -240,6 +240,18 @@ void wg_parser_push_data(wg_parser_t parser, const void *data, uint32_t size) WINE_UNIX_CALL(unix_wg_parser_push_data, ¶ms); }
+void wg_parser_set_thinning(wg_parser_t parser, BOOL thinning) +{ + struct wg_parser_set_thinning_params params = + { + .parser = parser, + .thinning = thinning, + }; + TRACE("parser %#I64x, thinning %d.\n", parser, thinning); + + WINE_UNIX_CALL(unix_wg_parser_set_thinning, ¶ms); +} + uint32_t wg_parser_get_stream_count(wg_parser_t parser) { struct wg_parser_get_stream_count_params params = diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 83e38849fa9..1df26360aca 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -245,6 +245,12 @@ struct wg_parser_push_data_params UINT32 size; };
+struct wg_parser_set_thinning_params +{ + wg_parser_t parser; + BOOL thinning; +}; + struct wg_parser_get_stream_count_params { wg_parser_t parser; @@ -429,6 +435,8 @@ enum unix_funcs unix_wg_parser_get_next_read_offset, unix_wg_parser_push_data,
+ unix_wg_parser_set_thinning, + unix_wg_parser_get_stream_count, unix_wg_parser_get_stream,
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index e806298fb57..dd1812d2d0e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -80,6 +80,7 @@ struct wg_parser bool output_compressed; bool no_more_pads, has_duration, error; bool err_on, warn_on; + bool thinning;
pthread_cond_t read_cond, read_done_cond; struct @@ -226,6 +227,19 @@ static NTSTATUS wg_parser_push_data(void *args) return S_OK; }
+static NTSTATUS wg_parser_set_thinning(void *args) +{ + const struct wg_parser_set_thinning_params *params = args; + struct wg_parser *parser = get_parser(params->parser); + BOOL thinning = params->thinning; + + pthread_mutex_lock(&parser->mutex); + parser->thinning = thinning; + pthread_mutex_unlock(&parser->mutex); + + return S_OK; +} + static NTSTATUS wg_parser_stream_get_current_format(void *args) { const struct wg_parser_stream_get_current_format_params *params = args; @@ -600,10 +614,46 @@ static void no_more_pads_cb(GstElement *element, gpointer user) pthread_cond_signal(&parser->init_cond); }
+static GstPadProbeReturn decoder_pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user) +{ + struct wg_parser *parser = user; + GstBuffer *buffer; + bool thinning; + + pthread_mutex_lock(&parser->mutex); + thinning = parser->thinning; + pthread_mutex_unlock(&parser->mutex); + + if (thinning && (buffer = gst_pad_probe_info_get_buffer(info))) + { + if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) + { + GST_DEBUG("Stream is thinned; discarding delta frame."); + return GST_PAD_PROBE_DROP; + } + else + { + GST_DEBUG("Stream is thinned; found key frame."); + } + } + + return GST_PAD_PROBE_OK; +} + static void deep_element_added_cb(GstBin *self, GstBin *sub_bin, GstElement *element, gpointer user) { + struct wg_parser *parser = user; + if (element) + { + GstElementFactory *fact = GST_ELEMENT_GET_CLASS(element)->elementfactory; + const char *klass = gst_element_factory_get_klass(fact); + GstPad *sink; + if (strstr(klass, GST_ELEMENT_FACTORY_KLASS_DECODER) && (sink = gst_element_get_static_pad(element, "sink"))) + gst_pad_add_probe(sink, GST_PAD_PROBE_TYPE_BUFFER, decoder_pad_probe, parser, NULL); + set_max_threads(element); + } }
static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) @@ -1911,6 +1961,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_get_next_read_offset), X(wg_parser_push_data),
+ X(wg_parser_set_thinning), + X(wg_parser_get_stream_count), X(wg_parser_get_stream),
@@ -2308,6 +2360,8 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X(wg_parser_get_next_read_offset), X64(wg_parser_push_data),
+ X(wg_parser_set_thinning), + X(wg_parser_get_stream_count), X(wg_parser_get_stream),
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mf/tests/mf.c | 7 ------- dlls/winegstreamer/media_source.c | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index dc31e0c2228..c812344d38e 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6951,16 +6951,13 @@ static void test_media_session_thinning(void) hr = IMFRateControl_SetRate(rate_control, TRUE, 5.0f); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(session, callback, MESessionRateChanged, 1000, &propvar); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
rate = 0.0f; thin = FALSE; hr = IMFRateControl_GetRate(rate_control, &thin, &rate); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(thin, "Unexpected !thin.\n"); - todo_wine ok(rate == 5.0f, "Unexpected rate %f.\n", rate);
/* clock is unaware of thinning */ @@ -6976,7 +6973,6 @@ static void test_media_session_thinning(void) hr = IMFRateControl_GetRate(clock_rate_control, &thin, &rate); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!thin, "Unexpected thin.\n"); - todo_wine ok(rate == 5.0f, "Unexpected rate %f.\n", rate);
/* get first sample time */ @@ -7002,9 +6998,6 @@ static void test_media_session_thinning(void)
/* test thinned */
- thin_sample_desc[1].todo_time = TRUE; - thin_sample_desc[2].todo_time = TRUE; - grab_samples_from_start(session, callback, grabber_callback, 3); check_mf_sample_collection(grabber_callback->samples, thin_sample_desc, L"rgb32-3frames.bmp");
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ab842b3e438..7cf3ad7c5a3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -202,6 +202,7 @@ struct media_source SOURCE_SHUTDOWN, } state; float rate; + BOOL thin;
HANDLE read_thread; bool read_thread_shutdown; @@ -1279,23 +1280,36 @@ static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, B { struct media_source *source = impl_from_IMFRateControl(iface); HRESULT hr; + BOOL old_thin;
FIXME("%p, %d, %f.\n", iface, thin, rate);
if (rate < 0.0f) return MF_E_REVERSE_UNSUPPORTED;
- if (thin) - return MF_E_THINNING_UNSUPPORTED; - if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) return hr;
EnterCriticalSection(&source->cs); + old_thin = source->thin; source->rate = rate; + source->thin = thin; LeaveCriticalSection(&source->cs);
- return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); + wg_parser_set_thinning(source->wg_parser, thin); + + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL))) + return hr; + + if (old_thin != thin) + { + PROPVARIANT param; + param.vt = VT_BOOL; + param.boolVal = thin ? VARIANT_TRUE : VARIANT_FALSE; + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEStreamThinMode, &GUID_NULL, S_OK, ¶m); + } + + return hr; }
static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) @@ -1304,11 +1318,10 @@ static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, B
TRACE("%p, %p, %p.\n", iface, thin, rate);
- if (thin) - *thin = FALSE; - EnterCriticalSection(&source->cs); *rate = source->rate; + if (thin) + *thin = source->thin; LeaveCriticalSection(&source->cs);
return S_OK; @@ -1734,6 +1747,7 @@ static HRESULT media_source_create(struct object_context *context, IMFMediaSourc IMFByteStream_AddRef(context->stream); object->file_size = context->file_size; object->rate = 1.0f; + object->thin = FALSE; InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 2 +- dlls/winedmo/main.c | 6 +++--- dlls/winedmo/unix_demuxer.c | 18 +++++++++++++++--- dlls/winedmo/unixlib.h | 1 + include/wine/winedmo.h | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index d7f20e511c8..9203fd33374 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -588,7 +588,7 @@ static HRESULT demuxer_read_sample(struct winedmo_demuxer demuxer, UINT *index,
if (FAILED(hr = create_media_buffer_sample(buffer_size, &sample, &output.pBuffer))) return hr; - if ((status = winedmo_demuxer_read(demuxer, index, &output, &buffer_size))) + if ((status = winedmo_demuxer_read(demuxer, index, &output, &buffer_size, FALSE))) { if (status == STATUS_BUFFER_TOO_SMALL) hr = E_PENDING; else if (status == STATUS_END_OF_FILE) hr = MF_E_END_OF_STREAM; diff --git a/dlls/winedmo/main.c b/dlls/winedmo/main.c index 1e91d8e2e51..6a462555f71 100644 --- a/dlls/winedmo/main.c +++ b/dlls/winedmo/main.c @@ -222,12 +222,12 @@ NTSTATUS CDECL winedmo_demuxer_destroy( struct winedmo_demuxer *demuxer ) return status; }
-NTSTATUS CDECL winedmo_demuxer_read( struct winedmo_demuxer demuxer, UINT *stream, DMO_OUTPUT_DATA_BUFFER *buffer, UINT *buffer_size ) +NTSTATUS CDECL winedmo_demuxer_read( struct winedmo_demuxer demuxer, UINT *stream, DMO_OUTPUT_DATA_BUFFER *buffer, UINT *buffer_size, BOOL thin ) { - struct demuxer_read_params params = {.demuxer = demuxer}; + struct demuxer_read_params params = {.demuxer = demuxer, .thin = thin}; NTSTATUS status;
- TRACE( "demuxer %#I64x, stream %p, buffer %p, buffer_size %p\n", demuxer.handle, stream, buffer, buffer_size ); + TRACE( "demuxer %#I64x, stream %p, buffer %p, buffer_size %p, thin %d\n", demuxer.handle, stream, buffer, buffer_size, thin );
buffer_lock( buffer, ¶ms.sample ); status = UNIX_CALL( demuxer_read, ¶ms ); diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c index 7a1a262e6c9..ac41b2b8227 100644 --- a/dlls/winedmo/unix_demuxer.c +++ b/dlls/winedmo/unix_demuxer.c @@ -220,7 +220,7 @@ NTSTATUS demuxer_destroy( void *arg ) return STATUS_SUCCESS; }
-static NTSTATUS demuxer_filter_packet( struct demuxer *demuxer, AVPacket **packet ) +static NTSTATUS demuxer_filter_packet( struct demuxer *demuxer, AVPacket **packet, BOOL thin ) { struct stream *stream; int i, ret; @@ -233,7 +233,19 @@ static NTSTATUS demuxer_filter_packet( struct demuxer *demuxer, AVPacket **packe if (!(stream = demuxer->last_stream)) ret = 0; else { - if (!(ret = av_bsf_receive_packet( stream->filter, *packet ))) return STATUS_SUCCESS; + if (!(ret = av_bsf_receive_packet( stream->filter, *packet ))) { + if (thin) + { + if ((*packet)->flags & AV_PKT_FLAG_KEY) TRACE("Thinning: Found key frame.\n"); + else + { + TRACE("Thinning: Skipping delta frame.\n"); + av_packet_free( packet ); + continue; + } + } + return STATUS_SUCCESS; + } if (ret == AVERROR_EOF) stream->eos = TRUE; if (!ret || ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) ret = 0; else WARN( "Failed to read packet from filter, error %s.\n", debugstr_averr( ret ) ); @@ -280,7 +292,7 @@ NTSTATUS demuxer_read( void *arg )
TRACE( "demuxer %p, capacity %#x\n", demuxer, capacity );
- if ((status = demuxer_filter_packet( demuxer, &packet ))) return status; + if ((status = demuxer_filter_packet( demuxer, &packet, params->thin ))) return status;
params->sample.size = packet->size; if ((capacity < packet->size)) diff --git a/dlls/winedmo/unixlib.h b/dlls/winedmo/unixlib.h index cf37bd5342a..eda808e2cd0 100644 --- a/dlls/winedmo/unixlib.h +++ b/dlls/winedmo/unixlib.h @@ -121,6 +121,7 @@ struct demuxer_read_params struct winedmo_demuxer demuxer; UINT32 stream; struct sample sample; + BOOL thin; };
struct demuxer_seek_params diff --git a/include/wine/winedmo.h b/include/wine/winedmo.h index c068dfa1de8..ab592777eab 100644 --- a/include/wine/winedmo.h +++ b/include/wine/winedmo.h @@ -46,7 +46,7 @@ NTSTATUS CDECL winedmo_demuxer_check( const char *mime_type ); NTSTATUS CDECL winedmo_demuxer_create( const WCHAR *url, struct winedmo_stream *stream, UINT64 stream_size, INT64 *duration, UINT *stream_count, WCHAR *mime_type, struct winedmo_demuxer *demuxer ); NTSTATUS CDECL winedmo_demuxer_destroy( struct winedmo_demuxer *demuxer ); -NTSTATUS CDECL winedmo_demuxer_read( struct winedmo_demuxer demuxer, UINT *stream, DMO_OUTPUT_DATA_BUFFER *buffer, UINT *buffer_size ); +NTSTATUS CDECL winedmo_demuxer_read( struct winedmo_demuxer demuxer, UINT *stream, DMO_OUTPUT_DATA_BUFFER *buffer, UINT *buffer_size, BOOL thin ); NTSTATUS CDECL winedmo_demuxer_seek( struct winedmo_demuxer demuxer, INT64 timestamp ); NTSTATUS CDECL winedmo_demuxer_stream_lang( struct winedmo_demuxer demuxer, UINT stream, WCHAR *buffer, UINT len ); NTSTATUS CDECL winedmo_demuxer_stream_name( struct winedmo_demuxer demuxer, UINT stream, WCHAR *buffer, UINT len );
From: Charlotte Pabst cpabst@codeweavers.com
--- dlls/mfsrcsnk/media_source.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 9203fd33374..3d8b9e5bb73 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -240,6 +240,7 @@ struct media_source IMFByteStream *stream; WCHAR *url; float rate; + BOOL thin;
struct winedmo_demuxer winedmo_demuxer; struct winedmo_stream winedmo_stream; @@ -575,7 +576,7 @@ static HRESULT create_media_buffer_sample(UINT buffer_size, IMFSample **sample, return hr; }
-static HRESULT demuxer_read_sample(struct winedmo_demuxer demuxer, UINT *index, IMFSample **out) +static HRESULT demuxer_read_sample(struct winedmo_demuxer demuxer, UINT *index, IMFSample **out, BOOL thin) { UINT buffer_size = 0x1000; IMFSample *sample; @@ -588,7 +589,7 @@ static HRESULT demuxer_read_sample(struct winedmo_demuxer demuxer, UINT *index,
if (FAILED(hr = create_media_buffer_sample(buffer_size, &sample, &output.pBuffer))) return hr; - if ((status = winedmo_demuxer_read(demuxer, index, &output, &buffer_size, FALSE))) + if ((status = winedmo_demuxer_read(demuxer, index, &output, &buffer_size, thin))) { if (status == STATUS_BUFFER_TOO_SMALL) hr = E_PENDING; else if (status == STATUS_END_OF_FILE) hr = MF_E_END_OF_STREAM; @@ -635,7 +636,7 @@ static HRESULT media_source_read(struct media_source *source) if (source->state != SOURCE_RUNNING) return S_OK;
- if (FAILED(hr = demuxer_read_sample(source->winedmo_demuxer, &index, &sample)) && hr != MF_E_END_OF_STREAM) + if (FAILED(hr = demuxer_read_sample(source->winedmo_demuxer, &index, &sample, source->thin)) && hr != MF_E_END_OF_STREAM) { WARN("Failed to read stream %u data, hr %#lx\n", index, hr); return hr; @@ -1042,22 +1043,34 @@ static HRESULT WINAPI media_source_IMFRateControl_SetRate(IMFRateControl *iface, { struct media_source *source = media_source_from_IMFRateControl(iface); HRESULT hr; + BOOL old_thin;
FIXME("source %p, thin %d, rate %f, stub!\n", source, thin, rate);
if (rate < 0.0f) return MF_E_REVERSE_UNSUPPORTED; - if (thin) - return MF_E_THINNING_UNSUPPORTED;
if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) return hr;
EnterCriticalSection(&source->cs); + old_thin = source->thin; source->rate = rate; + source->thin = thin; LeaveCriticalSection(&source->cs);
- return IMFMediaEventQueue_QueueEventParamVar(source->queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL))) + return hr; + + if (old_thin != thin) + { + PROPVARIANT param; + param.vt = VT_BOOL; + param.boolVal = thin ? VARIANT_TRUE : VARIANT_FALSE; + hr = IMFMediaEventQueue_QueueEventParamVar(source->queue, MEStreamThinMode, &GUID_NULL, S_OK, ¶m); + } + + return hr; }
static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) @@ -1066,11 +1079,10 @@ static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface,
TRACE("source %p, thin %p, rate %p\n", source, thin, rate);
- if (thin) - *thin = FALSE; - EnterCriticalSection(&source->cs); *rate = source->rate; + if (thin) + *thin = source->thin; LeaveCriticalSection(&source->cs);
return S_OK;
On Fri May 30 23:00:07 2025 +0000, Nikolay Sivov wrote:
This doesn't look right. Was it tested?
what exactly isn't right? setting `old_thin = thin`? I've fixed that now.
On Fri May 30 23:00:07 2025 +0000, Nikolay Sivov wrote:
This one is documented to use VARIANT_TRUE/VARIANT_FALSE.
fixed
On Fri May 30 23:00:06 2025 +0000, Nikolay Sivov wrote:
This should probably be a separate change, going together with SetRate(thin=false).
so, one commit that removes the responsibility for `thin` from the clock, and another one that makes the media session handle it?
On Fri May 30 23:00:06 2025 +0000, Nikolay Sivov wrote:
This one is leaked I think.
Fixed by removing the useless second query later.