Skip to content
This repository has been archived by the owner on May 4, 2024. It is now read-only.

Commit

Permalink
bench color convert
Browse files Browse the repository at this point in the history
  • Loading branch information
rbernon committed May 15, 2023
1 parent 3b91a77 commit a299ad4
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 12 deletions.
108 changes: 108 additions & 0 deletions dlls/mf/tests/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -5783,6 +5783,111 @@ static void test_wmv_decoder_media_object(void)
winetest_pop_context();
}

static void bench_color_convert(void)
{
const GUID *const class_id = &CLSID_CColorConvertDMO;
static const DWORD actual_width = 1280, actual_height = 720;
const struct attribute_desc input_type_desc[] =
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420, .required = TRUE),
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
{0},
};
const struct attribute_desc output_type_desc[] =
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE),
ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE),
{0},
};
const MFT_OUTPUT_STREAM_INFO output_info =
{
.cbSize = actual_width * actual_height * 4,
.cbAlignment = 1,
};
const MFT_INPUT_STREAM_INFO input_info =
{
.cbSize = actual_width * actual_height * 3 / 2,
.cbAlignment = 1,
};

IMFSample *input_sample, *output_sample;
QWORD input_duration, output_duration;
LARGE_INTEGER frequency, counter;
IMFTransform *transform;
DWORD output_status;
ULONG i, ret;
void *data;
HRESULT hr;

hr = CoInitialize(NULL);
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);

winetest_push_context("colorconv");

if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER,
&IID_IMFTransform, (void **)&transform)))
goto failed;

check_mft_set_input_type(transform, input_type_desc);
check_mft_set_output_type(transform, output_type_desc, S_OK);

check_mft_get_input_stream_info(transform, &input_info);
check_mft_get_output_stream_info(transform, &output_info);

data = calloc(1, input_info.cbSize);
input_sample = create_sample(data, input_info.cbSize);
free(data);

hr = IMFSample_SetSampleTime(input_sample, 0);
ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr);
hr = IMFSample_SetSampleDuration(input_sample, 0);
ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr);

output_sample = create_sample(NULL, output_info.cbSize);


QueryPerformanceFrequency(&frequency);
input_duration = output_duration = 0;


for (i = 0; i < 1000; ++i)
{
QueryPerformanceCounter(&counter);
input_duration += -counter.QuadPart;

hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);

QueryPerformanceCounter(&counter);
input_duration += counter.QuadPart;
output_duration += -counter.QuadPart;

hr = check_mft_process_output(transform, output_sample, &output_status);
ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);

QueryPerformanceCounter(&counter);
output_duration += counter.QuadPart;
}

ok(0, "input %f us, output %f us\n", input_duration * 1000000. / frequency.QuadPart / i, output_duration * 1000000. / frequency.QuadPart / i);


ret = IMFSample_Release(input_sample);
ok(ret == 0, "Release returned %ld\n", ret);
ret = IMFSample_Release(output_sample);
ok(ret == 0, "Release returned %lu\n", ret);

ret = IMFTransform_Release(transform);
ok(ret == 0, "Release returned %ld\n", ret);

failed:
winetest_pop_context();
CoUninitialize();
}

static void test_color_convert(void)
{
const GUID *const class_id = &CLSID_CColorConvertDMO;
Expand Down Expand Up @@ -8087,6 +8192,9 @@ START_TEST(transform)
{
init_functions();

bench_color_convert();
return;

test_sample_copier();
test_sample_copier_output_processing();
test_aac_encoder();
Expand Down
4 changes: 2 additions & 2 deletions dlls/winegstreamer/wg_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ typedef enum
GST_AUTOPLUG_SELECT_SKIP,
} GstAutoplugSelectResult;

static GstGLDisplay *gl_display;
static GstGLContext *gl_context;
GstGLDisplay *gl_display;
GstGLContext *gl_context;

struct request
{
Expand Down
107 changes: 97 additions & 10 deletions dlls/winegstreamer/wg_transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#include <gst/video/video.h>
#include <gst/audio/audio.h>

#include <gst/gl/gl.h>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h"
Expand All @@ -41,6 +43,9 @@

#define GST_SAMPLE_FLAG_WG_CAPS_CHANGED (GST_MINI_OBJECT_FLAG_LAST << 0)

extern GstGLDisplay *gl_display;
extern GstGLContext *gl_context;

struct wg_transform
{
GstElement *container;
Expand All @@ -50,6 +55,7 @@ struct wg_transform
GstQuery *drain_query;
bool broken_timestamps;

bool push_input_early;
guint input_max_length;
GstAtomicQueue *input_queue;

Expand Down Expand Up @@ -266,9 +272,31 @@ static struct wg_sample *transform_request_sample(gsize size, void *context)
return InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL);
}

static bool wg_format_video_is_flipped(const struct wg_format *format)
static bool is_rgb_format(enum wg_video_format format)
{
return format->major_type == WG_MAJOR_TYPE_VIDEO && (format->u.video.height < 0);
switch (format)
{
case WG_VIDEO_FORMAT_BGRA:
case WG_VIDEO_FORMAT_BGRx:
case WG_VIDEO_FORMAT_BGR:
case WG_VIDEO_FORMAT_RGBA:
case WG_VIDEO_FORMAT_RGB15:
case WG_VIDEO_FORMAT_RGB16:
return true;

case WG_VIDEO_FORMAT_AYUV:
case WG_VIDEO_FORMAT_I420:
case WG_VIDEO_FORMAT_NV12:
case WG_VIDEO_FORMAT_UYVY:
case WG_VIDEO_FORMAT_YUY2:
case WG_VIDEO_FORMAT_YV12:
case WG_VIDEO_FORMAT_YVYU:
case WG_VIDEO_FORMAT_UNKNOWN:
return false;
}

assert(0);
return false;
}

NTSTATUS wg_transform_create(void *args)
Expand All @@ -281,6 +309,7 @@ NTSTATUS wg_transform_create(void *args)
NTSTATUS status = STATUS_UNSUCCESSFUL;
GstPadTemplate *template = NULL;
struct wg_transform *transform;
GstContext *context = NULL;
const gchar *media_type;
GstEvent *event;

Expand Down Expand Up @@ -322,6 +351,17 @@ NTSTATUS wg_transform_create(void *args)
gst_pad_set_query_function(transform->my_sink, transform_sink_query_cb);
gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb);

if (!gl_display)
GST_WARNING("No OpenGL display available, using CPU video conversion.");
else if (!(context = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, false)))
GST_ERROR("Failed to create OpenGL GStreamer context");
else
{
gst_context_set_gl_display(context, gl_display);
gst_element_set_context(transform->container, context);
gst_context_unref(context);
}

/* Since we append conversion elements, we don't want to filter decoders
* based on the actual output caps now. Matching decoders with the
* raw output media type should be enough.
Expand Down Expand Up @@ -395,17 +435,54 @@ NTSTATUS wg_transform_create(void *args)

case WG_MAJOR_TYPE_VIDEO:
case WG_MAJOR_TYPE_VIDEO_WMV:
if (!(transform->video_flip = create_element("videoflip", "base"))
|| !append_element(transform->container, transform->video_flip, &first, &last))
if (context && !is_rgb_format(input_format.u.video.format) && is_rgb_format(output_format.u.video.format) && !getenv("NOGSTGL"))
{
/*
GstCaps *gl_caps = gst_caps_copy(transform->output_caps);
gst_caps_set_features_simple(gl_caps, gst_caps_features_new_single("memory:GLMemory"));
*/
transform->push_input_early = true;

if (!(element = create_element("glupload", "base"))
|| !append_element(GST_BIN(transform->container), element, &first, &last))
goto out;
if (!(element = create_element("glcolorconvert", "base"))
|| !append_element(GST_BIN(transform->container), element, &first, &last))
goto out;
/*
if (!(element = create_element("capsfilter", "base"))
|| !append_element(GST_BIN(transform->container), element, &first, &last))
goto out;
g_object_set(G_OBJECT(element), "caps", gl_caps, NULL);
*/
if (wg_format_is_flipped(&input_format) != wg_format_is_flipped(&output_format))
{
if (!(element = create_element("glvideoflip", "base"))
|| !append_element(GST_BIN(transform->container), element, &first, &last))
goto out;
transform->input_is_flipped = wg_format_video_is_flipped(&input_format);
if (transform->input_is_flipped != wg_format_video_is_flipped(&output_format))
gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", "vertical-flip");
gst_util_set_object_arg(G_OBJECT(element), "method", "vertical-flip");
}

if (!(element = create_element("gldownload", "base"))
|| !append_element(GST_BIN(transform->container), element, &first, &last))
goto out;
}
else
{
if (!(element = create_element("videoconvert", "base"))
|| !append_element(transform->container, element, &first, &last))
goto out;
/* Let GStreamer choose a default number of threads. */
gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0");
gst_util_set_object_arg(G_OBJECT(element), "n-threads", getenv("THREADS") ? getenv("THREADS") : "0");

if (wg_format_is_flipped(&input_format) != wg_format_is_flipped(&output_format))
{
if (!(element = create_element("videoflip", "base"))
|| !transform_append_element(transform, element, &first, &last))
goto out;
gst_util_set_object_arg(G_OBJECT(element), "method", "vertical-flip");
}
}
break;

case WG_MAJOR_TYPE_AUDIO_MPEG1:
Expand All @@ -429,6 +506,8 @@ NTSTATUS wg_transform_create(void *args)
if (!gst_pad_set_active(transform->my_src, 1))
goto out;

GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(transform->container), GST_DEBUG_GRAPH_SHOW_ALL, "wg_transform-null");

gst_element_set_state(transform->container, GST_STATE_PAUSED);
if (!gst_element_get_state(transform->container, NULL, NULL, -1))
goto out;
Expand All @@ -455,6 +534,8 @@ NTSTATUS wg_transform_create(void *args)

gst_caps_unref(src_caps);

GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(transform->container), GST_DEBUG_GRAPH_SHOW_ALL, "wg_transform-done");

GST_INFO("Created winegstreamer transform %p.", transform);
params->transform = transform;
return STATUS_SUCCESS;
Expand Down Expand Up @@ -560,6 +641,7 @@ NTSTATUS wg_transform_push_data(void *args)
struct wg_transform_push_data_params *params = args;
struct wg_transform *transform = params->transform;
struct wg_sample *sample = params->sample;
GstFlowReturn ret;
GstBuffer *buffer;
guint length;

Expand Down Expand Up @@ -593,7 +675,11 @@ NTSTATUS wg_transform_push_data(void *args)
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DISCONT);
if (sample->flags & WG_SAMPLE_FLAG_PREROLL)
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_LIVE);
gst_atomic_queue_push(transform->input_queue, buffer);

if (!transform->push_input_early)
gst_atomic_queue_push(transform->input_queue, buffer);
else if ((ret = gst_pad_push(transform->my_src, buffer)))
GST_ERROR("Failed to push transform input, error %d", ret);

params->result = S_OK;
return STATUS_SUCCESS;
Expand Down Expand Up @@ -755,7 +841,8 @@ static bool get_transform_output(struct wg_transform *transform, struct wg_sampl
InterlockedIncrement(&sample->refcount);
InterlockedExchangePointer((void **)&transform->output_wg_sample, sample);

while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue)))
while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))
&& !transform->push_input_early)
{
if (!(input_buffer = gst_atomic_queue_pop(transform->input_queue)))
break;
Expand Down

0 comments on commit a299ad4

Please sign in to comment.