-
Notifications
You must be signed in to change notification settings - Fork 0
/
videoitem.cpp
79 lines (63 loc) · 2.6 KB
/
videoitem.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "videoitem.h"
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <QImage>
#include <QPainter>
VideoItem::VideoItem(QQuickItem *parent) : QQuickPaintedItem(parent), port(5600) {
qRegisterMetaType<cv::Mat>("cv::Mat");
_frame = cv::Mat(480, 640, CV_8UC3); // Initialize a 480x640 color (3-channel) matrix
gst_init(nullptr, nullptr);
run();
}
void VideoItem::paint(QPainter *painter) {
if (!_frame.empty()) { // Check if the frame is not empty
QImage img(_frame.data, _frame.cols, _frame.rows, _frame.step, QImage::Format_RGB888);
painter->drawImage(boundingRect(), img);
}
}
GstFlowReturn VideoItem::callback(GstElement *sink, gpointer data) {
VideoItem *self = static_cast<VideoItem*>(data);
GstSample *sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
GstBuffer *buf = gst_sample_get_buffer(sample);
GstCaps *caps = gst_sample_get_caps(sample);
GstStructure *structure = gst_caps_get_structure(caps, 0);
int width = 0, height = 0;
gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height);
GstMapInfo map;
gst_buffer_map(buf, &map, GST_MAP_READ);
self->_frame = cv::Mat(height, width, CV_8UC3, map.data).clone();
gst_buffer_unmap(buf, &map);
gst_sample_unref(sample);
QMetaObject::invokeMethod(self, "updateFrame", Qt::QueuedConnection, Q_ARG(cv::Mat, self->_frame));
return GST_FLOW_OK;
}
void VideoItem::start_gst() {
gchar *descr = g_strdup_printf("udpsrc port=%d ! application/x-rtp, payload=96 ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! video/x-raw,format=BGR ! videoconvert ! appsink name=sink", port);
GError *error = nullptr;
video_pipe = gst_parse_launch(descr, &error);
g_free(descr);
if (error) {
g_printerr("Error creating pipeline: %s\n", error->message);
g_error_free(error);
return;
}
GstElement *sink = gst_bin_get_by_name(GST_BIN(video_pipe), "sink");
if (!sink) {
g_printerr("Error: appsink not found in the pipeline\n");
return;
}
gst_app_sink_set_emit_signals(GST_APP_SINK(sink), true);
gst_app_sink_set_drop(GST_APP_SINK(sink), true);
gst_app_sink_set_max_buffers(GST_APP_SINK(sink), 2);
gst_base_sink_set_sync(GST_BASE_SINK(sink), false);
g_signal_connect(sink, "new-sample", G_CALLBACK(callback), this);
gst_element_set_state(video_pipe, GST_STATE_PLAYING);
}
void VideoItem::updateFrame(const cv::Mat &frame) {
_frame = frame.clone();
update(); // Trigger repaint in the GUI thread
}
void VideoItem::run() {
start_gst();
}