H.264 uses a 16-pixel alignment, and the stream sink media type should have the aligned height after the session has started.
-- v4: mf/tests: Test H.264 sink media type height alignment.
From: Conor McCarthy cmccarthy@codeweavers.com
H.264 uses a 16-pixel alignment, and the stream sink media type should have the aligned height after the session has started. --- dlls/mf/tests/mf.c | 223 +++++++++++++++++++++++++++++++ dlls/mf/tests/resource.rc | 9 ++ dlls/mf/tests/test-unaligned.mp4 | Bin 0 -> 3988 bytes 3 files changed, 232 insertions(+) create mode 100644 dlls/mf/tests/test-unaligned.mp4
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index a02f2859f91..80414392c68 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3039,6 +3039,12 @@ static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSink HRESULT hr; DWORD res;
+ if (grabber->ready_event && !grabber->done_event) + { + SetEvent(grabber->ready_event); + return S_OK; + } + if (!grabber->ready_event) return E_NOTIMPL;
@@ -8040,6 +8046,222 @@ static void test_media_session_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
+static IMFTransform *topology_get_transform(IMFTopology *topology) +{ + IMFTransform *transform; + IMFTopologyNode *node; + MF_TOPOLOGY_TYPE type; + HRESULT hr; + WORD count; + UINT i; + + hr = IMFTopology_GetNodeCount(topology, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < count; ++i) + { + hr = IMFTopology_GetNode(topology, i, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_GetNodeType(node, &type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (type == MF_TOPOLOGY_TRANSFORM_NODE) + { + hr = IMFTopologyNode_GetObject(node, (IUnknown **)&transform); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyNode_Release(node); + return transform; + } + IMFTopologyNode_Release(node); + } + + return NULL; +} + +#define check_transform_output_type(a, b, c) check_transform_output_type_(__LINE__, a, b, c) +static void check_transform_output_type_(int line, IMFTransform *transform, UINT expected_w, UINT expected_h) +{ + IMFMediaType *output_type; + UINT64 frame_size; + HRESULT hr; + + if (!transform) + { + skip("Wine does not currently use a transform.\n"); + return; + } + hr = IMFTransform_GetOutputCurrentType(transform, 0, &output_type); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(output_type, &MF_MT_FRAME_SIZE, &frame_size); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(expected_h > 72) + ok_(__FILE__, line)(frame_size == (((UINT64)expected_w << 32) | expected_h), "Unexpected frame size %#llx\n", frame_size); + IMFMediaType_Release(output_type); +} + +#define check_type_handler_output_type(a, b, c) check_type_handler_output_type_(__LINE__, a, b, c) +static void check_type_handler_output_type_(int line, IMFMediaTypeHandler *handler, UINT expected_w, UINT expected_h) +{ + IMFMediaType *output_type; + UINT64 frame_size; + HRESULT hr; + + hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &output_type); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(output_type, &MF_MT_FRAME_SIZE, &frame_size); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(expected_h > 72) + ok_(__FILE__, line)(frame_size == (((UINT64)expected_w << 32) | expected_h), "Unexpected frame size %#llx\n", frame_size); + IMFMediaType_Release(output_type); +} + +static void test_h264_output_alignment(void) +{ + media_type_desc video_nv12_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), + }; + struct test_grabber_callback *grabber_callback; + IMFTopology *topology, *resolved_topology; + struct test_callback *test_callback; + IMFMediaTypeHandler *handler; + IMFActivate *sink_activate; + IMFTopoLoader *topo_loader; + IMFStreamSink *stream_sink; + IMFAsyncCallback *callback; + IMFMediaType *output_type; + MediaEventType event_type; + IMFMediaSession *session; + IMFMediaSink *media_sink; + IMFTransform *transform; + IMFMediaSource *source; + PROPVARIANT propvar; + UINT64 frame_size; + HANDLE objects[2]; + UINT32 status; + HRESULT hr; + DWORD ret; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + if (!(source = create_media_source(L"test-unaligned.mp4", L"video/mp4"))) + { + todo_wine /* Gitlab CI Debian runner */ + win_skip("MP4 media source is not supported, skipping tests.\n"); + MFShutdown(); + return; + } + + grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + grabber_callback->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!grabber_callback->ready_event, "CreateEventW failed, error %lu\n", GetLastError()); + + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(output_type, video_nv12_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); + + IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&media_sink); + hr = IMFMediaSink_GetStreamSinkByIndex(media_sink, 0, &stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFActivate_Release(sink_activate); + topology = create_test_topology_unk(source, (IUnknown *)stream_sink, NULL, NULL); + hr = MFCreateTopoLoader(&topo_loader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopoLoader_Load(topo_loader, topology, &resolved_topology, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + IMFTopoLoader_Release(topo_loader); + + hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &handler); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetUINT64(output_type, &MF_MT_FRAME_SIZE, &frame_size); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(output_type); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_SetTopology(session, 0, resolved_topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + transform = topology_get_transform(resolved_topology); + IMFTopology_Release(resolved_topology); + + callback = create_test_callback(TRUE); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + test_callback = impl_from_IMFAsyncCallback(callback); + hr = wait_media_event(session, callback, MESessionTopologyStatus, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEvent_GetUINT32(test_callback->media_event, &MF_EVENT_TOPOLOGY_STATUS, &status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(status == MF_TOPOSTATUS_READY, "Unexpected status %d.\n", status); + + check_transform_output_type(transform, 64, 72); + check_type_handler_output_type(handler, 64, 72); + + 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, MESessionTopologyStatus, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEvent_GetUINT32(test_callback->media_event, &MF_EVENT_TOPOLOGY_STATUS, &status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(status == MF_TOPOSTATUS_STARTED_SOURCE, "Unexpected status %d.\n", status); + check_transform_output_type(transform, 64, 72); + check_type_handler_output_type(handler, 64, 72); + + /* frame size change occurs before MESessionStarted and delivery of the first sample to the sink */ + objects[0] = test_callback->event; + objects[1] = grabber_callback->ready_event; + do + { + hr = IMFMediaEventGenerator_BeginGetEvent((IMFMediaEventGenerator *)session, + &test_callback->IMFAsyncCallback_iface, (IUnknown *)session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForMultipleObjects(2, objects, FALSE, 5000); + ok(ret == WAIT_OBJECT_0 || ret == WAIT_OBJECT_0 + 1, "WaitForMultipleObjects returned %lu\n", ret); + if (ret == WAIT_OBJECT_0) + { + hr = IMFMediaEvent_GetType(test_callback->media_event, &event_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + } while (ret == WAIT_OBJECT_0 && event_type != MESessionStarted); + + check_transform_output_type(transform, 64, 80); + check_type_handler_output_type(handler, 64, 80); + + hr = IMFMediaSession_Stop(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); + + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFMediaTypeHandler_Release(handler); + if (transform) + IMFTransform_Release(transform); + IMFAsyncCallback_Release(callback); + IMFMediaSession_Release(session); + IMFStreamSink_Release(stream_sink); + IMFMediaSink_Release(media_sink); + IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); + IMFMediaSource_Release(source); + + hr = MFShutdown(); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + START_TEST(mf) { init_functions(); @@ -8078,4 +8300,5 @@ START_TEST(mf) test_media_session_source_shutdown(); test_media_session_thinning(); test_media_session_seek(); + test_h264_output_alignment(); } diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index dff5719dd3b..2a69a842ce8 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -185,3 +185,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=72,height=64,framerate=30000/1001 ! \ + * videoflip method=clockwise ! videoconvert ! \ + * x264enc ! mp4mux ! filesink location=dlls/mf/tests/test-unaligned.mp4 + */ +/* @makedep: test-unaligned.mp4 */ +test-unaligned.mp4 RCDATA test-unaligned.mp4 diff --git a/dlls/mf/tests/test-unaligned.mp4 b/dlls/mf/tests/test-unaligned.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..5920da40daaf55dc69a5a02577891c70906fed94 GIT binary patch literal 3988 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 V7(l&F1_lOOsKKVB7|a1O7yw{rbdCT3
literal 0 HcmV?d00001