GStreamer искажение зависит от размера изображения - PullRequest
4 голосов
/ 25 февраля 2020

Я тестирую потоковое видео с помощью appsr c. Похоже, что есть искажение в зависимости от размера тестового изображения, которое я использую. Если я использую изображение 1024 x 768, то искажения нет. Если я использую изображение размером 659 x 494, я получаю искажение, показанное на скриншоте. Текст стал наклонным, переведенным и упакованным.

enter image description here

// g++ gstreamer_test.cpp `pkg-config --cflags gstreamer-1.0` `pkg-config --libs gstreamer-1.0` -lopencv_core -lopencv_imgproc -lopencv_highgui

#include <gst/gst.h>

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <cstddef>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cerrno>


cv::Mat openCvImage;
int width;
int height;

struct gstreamer_data {
    GstElement* video_source;
    GstElement* video_convert;
    GstElement* video_sink;
    GstElement* pipeline;
    GMainLoop* main_loop;
    guint source_id;
};

static gboolean push_data(gstreamer_data* data) {
    GstBuffer* buffer;
    GstMemory* memory;
    GstMapInfo info;
    GstFlowReturn ret;
    gint size;


    size = width * height * 8;
    buffer = gst_buffer_new();
    memory = gst_allocator_alloc(NULL, size, NULL);
    gst_buffer_insert_memory(buffer, -1, memory);
    gst_buffer_map(buffer, &info, GST_MAP_WRITE);

    for (int i = 0; i < width * height; ++i) {
        info.data[i] = openCvImage.data[i];
    }

    gst_buffer_unmap(buffer, &info);

    g_signal_emit_by_name(data->video_source, "push-buffer", buffer, &ret);
    gst_buffer_unref(buffer);

    if (ret != GST_FLOW_OK) {
        printf("Error\n");

        return false;
    }

    return true;
}

static void start_feed(GstElement* source, guint size, gstreamer_data* data) {
    (void) source;
    (void) size;


    if (data->source_id == 0) {
        data->source_id = g_idle_add((GSourceFunc) push_data, data);
    }
}

static void stop_feed(GstElement* source, gstreamer_data* data) {
    (void) source;


    if (data->source_id != 0) {
        g_source_remove(data->source_id);
        data->source_id = 0;
    }
}

static void error_cb(GstBus* bus, GstMessage* msg, gstreamer_data* data) {
    (void) bus;
    GError* err;
    gchar* debug_info;


    gst_message_parse_error(msg, &err, &debug_info);
    g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
    g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
    g_clear_error(&err);
    g_free(debug_info);

    g_main_loop_quit(data->main_loop);
}

int main() {
    gstreamer_data data;
    GstStateChangeReturn ret;
    GstBus* bus;


    data.source_id = 0;

    gst_init(NULL, NULL);


    openCvImage = cv::imread("hello_659_494.png", 0);
    width = openCvImage.cols;
    height = openCvImage.rows;

    data.video_source = gst_element_factory_make("appsrc", "video_source");

    g_object_set(G_OBJECT(data.video_source),
        "stream-type", 0,
        "is-live", TRUE,
        "format", GST_FORMAT_TIME,
        "caps", gst_caps_new_simple(
            "video/x-raw",
            "format", G_TYPE_STRING, "GRAY8",
            "width", G_TYPE_INT, width,
            "height", G_TYPE_INT, height,
            "framerate", GST_TYPE_FRACTION, 0, 1, NULL),
        NULL);

    g_signal_connect(data.video_source, "need-data", G_CALLBACK(start_feed), &data);
    g_signal_connect(data.video_source, "enough-data", G_CALLBACK(stop_feed), &data);


    data.video_convert = gst_element_factory_make("videoconvert", "video_convert");


    data.video_sink = gst_element_factory_make("ximagesink", "video_sink");

    data.pipeline = gst_pipeline_new("pipeline");

    if (!data.pipeline || !data.video_source || !data.video_convert || !data.video_sink) {
        g_printerr("Not all elements could be created.\n");
        exit(-1);
    }

    gst_bin_add_many(GST_BIN(data.pipeline), data.video_source, data.video_convert, data.video_sink, NULL);
    if (gst_element_link_many(data.video_source, data.video_convert, data.video_sink, NULL) != TRUE) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(data.pipeline);
        exit(-1);
    }

    bus = gst_element_get_bus(data.pipeline);
    gst_bus_add_signal_watch(bus);
    g_signal_connect(G_OBJECT (bus), "message::error", (GCallback)error_cb, &data);
    gst_object_unref(bus);

    ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(data.pipeline);
        exit(-1);
    }

    data.main_loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(data.main_loop);

    return 0;
}

1 Ответ

0 голосов
/ 10 марта 2020

Функция gst_buffer_add_video_meta_full, кажется, исправляет это. Я не уверен почему.

static gboolean push_data(gstreamer_data* data) {
    GstBuffer* buffer;
    GstMemory* memory;
    GstMapInfo info;
    GstVideoMeta* meta;
    GstFlowReturn ret;
    gint size;
    gsize offset[1] = {0};
    gint stride[1] = {width};


    size = width * height * 8;
    buffer = gst_buffer_new();
    memory = gst_allocator_alloc(NULL, size, NULL);
    gst_buffer_insert_memory(buffer, -1, memory);
    gst_buffer_map(buffer, &info, GST_MAP_WRITE);

    for (int i = 0; i < width * height; ++i) {
        info.data[i] = openCvImage.data[i];
    }

    gst_buffer_unmap(buffer, &info);

    meta = gst_buffer_add_video_meta_full(buffer, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_FORMAT_GRAY8, width, height, 1, offset, stride);

    g_signal_emit_by_name(data->video_source, "push-buffer", buffer, &ret);
    gst_buffer_unref(buffer);

    if (ret != GST_FLOW_OK) {
        printf("Error\n");

        return false;
    }

    return true;
}
...