149 lines
4.3 KiB
C++
149 lines
4.3 KiB
C++
/*
|
|
* Based on this example
|
|
* https://stackoverflow.com/a/26402282/3312367
|
|
*/
|
|
#include <gst/gst.h>
|
|
#include <gst/app/gstappsink.h>
|
|
//#include <stdlib.h>
|
|
#include <cstdlib>
|
|
#include <deque>
|
|
|
|
#include "opencv2/opencv.hpp"
|
|
//using namespace cv;
|
|
|
|
// TODO: use synchronized deque
|
|
std::deque<cv::Mat> frameQueue;
|
|
|
|
GstFlowReturn new_preroll(GstAppSink *appsink, gpointer data) {
|
|
g_print ("Got preroll!\n");
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
GstFlowReturn new_sample(GstAppSink *appsink, gpointer data) {
|
|
static int framecount = 0;
|
|
framecount++;
|
|
|
|
GstSample *sample = gst_app_sink_pull_sample(appsink);
|
|
GstCaps *caps = gst_sample_get_caps(sample);
|
|
GstBuffer *buffer = gst_sample_get_buffer(sample);
|
|
const GstStructure *info = gst_sample_get_info(sample);
|
|
|
|
// ---- Read frame and convert to opencv format ---------------
|
|
|
|
GstMapInfo map;
|
|
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
|
|
|
// convert gstreamer data to OpenCV Mat, you could actually
|
|
// resolve height / width from caps...
|
|
cv::Mat frame(cv::Size(320, 240), CV_8UC3, (char*)map.data, cv::Mat::AUTO_STEP);
|
|
int frameSize = map.size;
|
|
|
|
// TODO: synchronize this....
|
|
frameQueue.push_back(frame);
|
|
|
|
gst_buffer_unmap(buffer, &map);
|
|
|
|
// ------------------------------------------------------------
|
|
|
|
// print dot every 30 frames
|
|
if (framecount%30 == 0) {
|
|
g_print (".");
|
|
}
|
|
|
|
// show caps on first frame
|
|
if (framecount == 1) {
|
|
g_print ("%s\n", gst_caps_to_string(caps));
|
|
}
|
|
|
|
gst_sample_unref (sample);
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) {
|
|
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
|
|
switch (GST_MESSAGE_TYPE (message)) {
|
|
case GST_MESSAGE_ERROR: {
|
|
GError *err;
|
|
gchar *debug;
|
|
|
|
gst_message_parse_error (message, &err, &debug);
|
|
g_print ("Error: %s\n", err->message);
|
|
g_error_free (err);
|
|
g_free (debug);
|
|
break;
|
|
}
|
|
case GST_MESSAGE_EOS:
|
|
/* end-of-stream */
|
|
break;
|
|
default:
|
|
/* unhandled message */
|
|
break;
|
|
}
|
|
/* we want to be notified again the next time there is a message
|
|
* on the bus, so returning TRUE (FALSE means we want to stop watching
|
|
* for messages on the bus and our callback should not be called again)
|
|
*/
|
|
return TRUE;
|
|
}
|
|
|
|
int main (int argc, char *argv[]) {
|
|
GError *error = NULL;
|
|
|
|
gst_init (&argc, &argv);
|
|
|
|
gchar *descr = g_strdup(
|
|
"videotestsrc pattern=ball ! "
|
|
"video/x-raw,format=RGB ! "
|
|
"videoconvert ! "
|
|
"appsink name=sink sync=true"
|
|
);
|
|
GstElement *pipeline = gst_parse_launch (descr, &error);
|
|
|
|
if (error != NULL) {
|
|
g_print ("could not construct pipeline: %s\n", error->message);
|
|
g_error_free (error);
|
|
exit (-1);
|
|
}
|
|
|
|
/* get sink */
|
|
GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
|
|
|
|
gst_app_sink_set_emit_signals((GstAppSink*)sink, true);
|
|
gst_app_sink_set_drop((GstAppSink*)sink, true);
|
|
gst_app_sink_set_max_buffers((GstAppSink*)sink, 1);
|
|
GstAppSinkCallbacks callbacks = { NULL, new_preroll, new_sample };
|
|
gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, NULL, NULL);
|
|
|
|
GstBus *bus;
|
|
guint bus_watch_id;
|
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
|
bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
|
|
gst_object_unref (bus);
|
|
|
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
|
|
|
cv::namedWindow("edges", 1);
|
|
bool is_terminated = false;
|
|
while (!is_terminated) {
|
|
// g_main_iteration(false);
|
|
g_main_context_iteration(NULL, false);
|
|
// TODO: synchronize...
|
|
if (frameQueue.size() > 0) {
|
|
// this lags pretty badly even when grabbing frames from webcam
|
|
cv::Mat frame = frameQueue.front();
|
|
cv::Mat edges;
|
|
cvtColor(frame, edges, cv::COLOR_BGR2BGRA);
|
|
// GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
|
|
// Canny(edges, edges, 0, 30, 3);
|
|
cv::imshow("edges", edges);
|
|
cv::waitKey(30);
|
|
frameQueue.clear();
|
|
}
|
|
}
|
|
|
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
|
gst_object_unref (GST_OBJECT (pipeline));
|
|
|
|
return 0;
|
|
}
|