RK3399上實現視頻(MIPI CSI)攝像頭獲取轉至OPENCV

應上次有留言朋友的要求,我把部分代碼帖出來:

頭文件:

#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>
 
#include <glib-2.0/glib.h>
#include "gdk-pixbuf-2.0/gdk-pixbuf/gdk-pixbuf.h"
 
#include "../defines.h"
 
#ifndef GSTCODE_H
#define GSTCODE_H
 
 
#ifdef __JETSON_TX2__
    #define VIDEOSRC            "nvarguscamerasrc"
    #define VIDEOTYPE           "NV12"
    #define VIDEOCONVERT        "nvvidconv"
    #define VIDEOSINK           "nvoverlaysink"
    #define VIDEOSRCCAPS        "video/x-raw(memory:NVMM)"
    #define VIDEOENCODER        "nvv4l2h264enc"
#else
    #define VIDEOSRC            "rkisp"
    #define VIDEOTYPE           "NV12"
    #define VIDEOCONVERT        "videoconvert"
    #define VIDEOSINK           "rkximagesink"
    #define VIDEOSRCCAPS        "video/x-raw"
    #define VIDEOENCODER        "nvv4l2h264enc"
#endif
#define FILESINK                "filesink"
 
typedef struct {
    GstPipeline *pipeline;
    GstElement   *src;
    GstElement  *srcconvert;
    GstCaps     *caps;
    GstElement  *tee;
        //
    GstElement  *queue;
    GstElement  *convert;
    GstElement  *videosink;
        //
    GstElement  *appqueue;
    GstElement  *appconvert;
    GstCaps     *appcaps;
    GstElement  *appsink;
        //
    GMainLoop   *loop;
    guint       sourceid;
}gst_app_t;
 
extern gst_app_t gst_app;
extern gst_app_t *app;
 
void init_gst_elements(int argc, char *argv[]);
 
void terminal_gst_element();
 
class gstcode
{
public:
    gstcode();
};
 
#endif // GSTCODE_H

程序源文件:

#include "gstcode.h"
 
#define CVWIN                   "cvwindows"
 
gst_app_t gst_app;
gst_app_t *app = &gst_app;
 
gstcode::gstcode()
{
 
}
 
static int idx = 0;
 
static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer *ptr)
{
    gst_app_t *app = (gst_app_t*)ptr;
 
    switch(GST_MESSAGE_TYPE(message)){
 
        case GST_MESSAGE_ERROR:{
                gchar *debug;
                GError *err;
 
                gst_message_parse_error(message, &err, &debug);
                g_print("Error %s\n", err->message);
                g_error_free(err);
                g_free(debug);
                g_main_loop_quit(app->loop);
            }
            break;
 
        case GST_MESSAGE_WARNING:{
                gchar *debug;
                GError *err;
                gchar *name;
 
                gst_message_parse_warning(message, &err, &debug);
                g_print("Warning %s\nDebug %s\n", err->message, debug);
 
                name = GST_MESSAGE_SRC_NAME(message);
 
                g_print("Name of src %s\n", name ? name : "nil");
                g_error_free(err);
                g_free(debug);
            }
            break;
 
        case GST_MESSAGE_EOS:
            g_print("End of stream\n");
            g_main_loop_quit(app->loop);
            break;
 
        case GST_MESSAGE_STATE_CHANGED:
            break;
 
        default:
            g_print("got message %s\n", \
            gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
            break;
    }
 
    return TRUE;
}
 
static char filename[256] = {0};
 
static int exitticks = 0;
 
static int deel_appsink_buffer(GstAppSink * sink){
    GstSample *sample;
    GstBuffer *buffer;
    GstCaps *caps;
    GstStructure *s;
    gint width, height;
    bool res;
//        g_print("new sample %d\n", idx);
    sample = gst_app_sink_pull_sample(sink); //blocks
//    sample = gst_base_sink_get_last_sample(GST_BASE_SINK_CAST(self));
 
    if(sample){
 
        /* get the snapshot buffer format now. We set the caps on the appsink so
         * that it can only be an rgb buffer. The only thing we have not specified
         * on the caps is the height, which is dependant on the pixel-aspect-ratio
         * of the source material */
        caps = gst_sample_get_caps (sample);
        if (!caps) {
          g_print ("could not get snapshot format\n");
          exit (-1);
        }
        s = gst_caps_get_structure (caps, 0);
 
        /* we need to get the final caps on the buffer to get the size */
        res = gst_structure_get_int (s, "width", &width);
        res |= gst_structure_get_int (s, "height", &height);
        if (!res) {
          g_print ("could not get snapshot dimension\n");
          exit (-1);
        }
 
        /* create pixmap from buffer and save, gstreamer video buffers have a stride
         * that is rounded up to the nearest multiple of 4 */
        buffer = gst_sample_get_buffer (sample);
 
//        GstMemory * mem = gst_buffer_get_all_memory(buffer);
        GstMapInfo map;
 
        /* Mapping a buffer can fail (non-readable) */
        if (gst_buffer_map (buffer, &map, GST_MAP_READ)) {
//            g_print("buffer size:%lu\n", map.size);
//            g_print("img width:%d, height:%d\n", width, height);
            if(map.data != NULL){
 
//                cv::Mat mat = cv::Mat(cv::Size(width, height), CV_8U, (char*)map.data);
//                cv::imshow(CVWIN, mat);                                                                   //測試顯示OPENCV的窗體
                gst_buffer_unmap (buffer, &map);
            }else{
                g_print("data is null!\n");
                if(gst_app_sink_is_eos(GST_APP_SINK_CAST(gst_app.appsink))){
                    g_warning("gst_app_sink_is_eos !\n");
                }
            }
//            g_print("deel frame: %d !\n", idx);
        }else{
            g_warning("buffer cant map, buffer size:%lu !\n", gst_buffer_get_size(buffer));
            if(exitticks > 1){
                g_main_loop_quit(gst_app.loop);
            }else{
                exitticks ++;
            }
        }
        gst_buffer_unref(buffer);
        idx++;
    }else{
        g_warning("cant get sample from appsink !\n");
    }
//    g_print("\n\n\n##################################################################################################\n\n\n");
    return 1;
}
 
static GstFlowReturn Freturn;
 
static GstFlowReturn * new_sample_callback(GstAppSink * self, gst_app_t * app){
    deel_appsink_buffer(self);
    Freturn = GST_FLOW_OK;
    return &Freturn;
}
 
int frame_deel_thread(void *){
    deel_appsink_buffer(GST_APP_SINK_CAST(gst_app.appsink));
}
 
GstStateChangeReturn state_ret;
 
void init_gst_elements(int argc, char *argv[]){
    GstBus *bus;
    GstSample *sample;
    GSourceFunc func = frame_deel_thread;
    gst_init(&argc, &argv);
 
    app->pipeline = (GstPipeline*)gst_pipeline_new("mypipeline");
    /*bus = gst_pipeline_get_bus(app->pipeline);
    gst_bus_add_watch(bus, (GstBusFunc)bus_callback, app);
    gst_object_unref(bus);*/
 
    app->src = gst_element_factory_make(VIDEOSRC, "mysrc");
#ifdef JETSON_TX2
    g_object_set(app->src, "sensor-id", 1, NULL);
#else
    g_object_set(app->src, "io-mode", 4, "device", "/dev/video0", NULL);
#endif
 
    app->srcconvert = gst_element_factory_make(VIDEOCONVERT, "mysrcconvert");
#ifdef JETSON_TX2
    g_object_set(app->srcconvert, "flip-method", 6, NULL);
    app->caps = gst_caps_new_simple("video/x-raw(memory:NVMM)",//
                                    "width", G_TYPE_INT, VIDEO_WIDTH,
                                    "height", G_TYPE_INT, VIDEO_HEIGHT,
                                    "framerate", GST_TYPE_FRACTION, 30, 1,
                                    "format", G_TYPE_STRING, "NV12",
                                    NULL);
#else
    app->caps = gst_caps_new_simple("video/x-raw",//
                                    "width", G_TYPE_INT, VIDEO_WIDTH,
                                    "height", G_TYPE_INT, VIDEO_HEIGHT,
                                    "framerate", GST_TYPE_FRACTION, 30, 1,
                                    "format", G_TYPE_STRING, "NV12",
                                    NULL);
#endif
 
 
    app->tee = gst_element_factory_make("tee", "mytee");
    app->convert = gst_element_factory_make("videoconvert", "myconvert");
    app->queue = gst_element_factory_make("queue2", "myqueue");
    app->videosink = gst_element_factory_make(VIDEOSINK, "myvsink");
 
    app->appqueue = gst_element_factory_make("queue2", "myappqueue");
    app->appconvert = gst_element_factory_make("videoconvert", "myappvconvert");
    app->appcaps = gst_caps_new_simple("video/x-raw",
                                       "width", G_TYPE_INT, VIDEO_WIDTH,
                                       "height", G_TYPE_INT, VIDEO_HEIGHT,
                                       "framerate", GST_TYPE_FRACTION, 30, 1,
                                       "format", G_TYPE_STRING, "RGB",
                                       NULL);
    app->appsink = gst_element_factory_make("appsink", "myappsink");
 
    g_assert(app->src);
    g_assert(app->tee);
    g_assert(app->srcconvert);
    g_assert(app->queue);
    g_assert(app->convert);
    g_assert(app->videosink);
    g_assert(app->appqueue);
    g_assert(app->appconvert);
    g_assert(app->appsink);
 
 
    g_object_set(app->appsink, "emit-signals", false, "drop", true, "max-buffers", 1, "buffer-list", false, NULL);
 
    g_object_set(app->appqueue, "max-size-time", 500, NULL);
 
    gst_app_sink_set_emit_signals(GST_APP_SINK_CAST(app->appsink), true);
 
    gst_bin_add_many(GST_BIN(app->pipeline), (GstElement*)app->src,
    app->srcconvert, app->tee, app->queue, app->convert, app->videosink, app->appqueue, app->appconvert, app->appsink, NULL);
 
    if(!gst_element_link_filtered((GstElement*)app->src, app->srcconvert, app->caps)){
        g_warning("failed to link src and convert");
    }
    /*if(!gst_element_link((GstElement*)app->src, app->srcconvert)){
        g_warning("failed to link src and convert");
    }*/
 
    if(!gst_element_link(app->srcconvert, app->tee)){
        g_warning("failed to link convert and tee");
    }
 
    if(!gst_element_link(app->tee, app->queue)){
        g_warning("failed to link tee and queue");
    }
 
    if(!gst_element_link(app->queue, app->convert)){
        g_warning("failed to link queue and convert");
    }
 
    if(!gst_element_link(app->convert, app->videosink)){
        g_warning("failed to link convert and videosink");
    }
 
    if(!gst_element_link(app->tee, app->appqueue)){
        g_warning("failed to link tee and appqueue");
    }
 
 
    if(!gst_element_link(app->appqueue, app->appsink)){
        g_warning("failed to link appconvert and appsink");
    }
 
    state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_PLAYING);
    g_warning("set state returned %d\n", state_ret);
 
    app->loop = g_main_loop_new(NULL, FALSE);
 
    if(gst_app_sink_pull_sample(GST_APP_SINK_CAST(app->appsink)) == NULL){
        g_warning("app sink sample is null");
    }
 
    if(gst_app_sink_get_emit_signals(GST_APP_SINK_CAST(app->appsink))){
        g_warning("app sink signal true");
    }
 
    if(!gst_app_sink_get_drop(GST_APP_SINK_CAST(app->appsink))){
        g_warning("app sink drop is false");
    }
 
 
    g_idle_add(func, app);
 
}
 
void terminal_gst_element(){
    state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_NULL);
    g_warning("set state null returned %d\n", state_ret);
}

主程序:

/*
  I don't know if it is syntax highlighter or blogger, but I can't seem to
  put angle brackets around header file names properly.
*/
#include <stdio.h>
#include <stdint.h>
 
#include <fstream>
#include <X11/Xlib.h>
 
#include "defines.h"
#include "src/gstcode.h"
 
#define BUFF_SIZE               (1024)
 
#ifndef VIDEO_WIDTH
#define VIDEO_WIDTH             640
#define VIDEO_HEIGHT            480
#endif
 
 
int main(int argc, char *argv[])
{
    XInitThreads();
 
 
    init_gst_elements(argc, argv);
 
 
    g_main_loop_run(app->loop);
 
    terminal_gst_element();
 
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章