Я тестирую потоковое видео с помощью appsr c. Похоже, что есть искажение в зависимости от размера тестового изображения, которое я использую. Если я использую изображение 1024 x 768, то искажения нет. Если я использую изображение размером 659 x 494, я получаю искажение, показанное на скриншоте. Текст стал наклонным, переведенным и упакованным.
// 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;
}