place external live video frames from non supported V4L file into Gstreamer Qt , C++ Qthreads

空扰寡人 提交于 2019-12-22 13:34:52

问题


OS: Ubuntu 14.04
SDK: Qt
GStreamer: > 1.0

I am wondering how would I put continuously captured frames from a non supported V4L camera into GStreamer. Actually my task is to grab frames from the camera and use only GStreamer to send them to different computer via UDP. But at the moment, I just want to display it on my machine.

What I did so far:

a) Implemented code in Qt for an IDS camera that captures frames and displays then on Qt as live streaming.

b) Separately, I have written ( or rather copied ) code that displays live streaming via gstreamer using a webcam that supports V4L file.

Now as I mentioned, I want to use gstreamer to display capture frames in Qt environment.

I have developed code in qt 5.5 which makes use of multithreading to run separate threads for gstreamer, capturing frames and GUI. The code has become quite long but I will try best to place minimum code here.

Issue: when I try to run the code and added debug message, I can see frames are continuously coming from another thread into main but gstreamer function start successfully and at the very first time I get debug message from cb_need_data` but nothing after data.

Source code is shown below.

streaming gstream class:

class StreamG : public QObject
{
    Q_OBJECT
public:
    explicit StreamG(QObject *parent = 0);
    bool addLinkElements();

static void cb_need_data (GstElement *appsrc,
          guint       unused_size,
          gpointer    user_data);

 static GMainLoop *loop;
 static char* bufferFrame;
signals:
void sigFinish();

public slots:

 void start();
 void stop();

private:
    GstElement *pipeline, *source, *sink, *convert;
      GstBus *bus;
      GstMessage *msg;
      GstStateChangeReturn ret;     

};

Streaming using gstreaming cpp file below

GMainLoop* StreamG::loop;
char* StreamG::bufferFrame = NULL; // this will take buffer frames from other function
void StreamG::cb_need_data (GstElement *appsrc,
                            guint       unused_size,
                            gpointer    user_data )
{
    qDebug()<< " cb_need_data is called ...";
    static GstClockTime timestamp = 0;
    GstBuffer *buffer;
    guint size;
    GstFlowReturn ret;
    guchar *data1;
    GstMapInfo map;

    data1 = (guchar *)bufferFrame;
    size  = 385*288*2;
  if( data1 )
  {
    buffer = gst_buffer_new_allocate (NULL, size, NULL);
    gst_buffer_map (buffer, &map, GST_MAP_WRITE);
    memcpy( (guchar *)map.data, data1,  gst_buffer_get_size( buffer ) );

    GST_BUFFER_PTS (buffer) = timestamp;
    GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 2);

    timestamp += GST_BUFFER_DURATION (buffer);

    g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);

    if (ret != GST_FLOW_OK)
    {
        // something wrong, stop pushing //

        g_debug("push buffer returned %d for %d bytes \n", ret, size);
        g_main_loop_quit (loop);
    }
  }
}


static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE (msg)) {

    case GST_MESSAGE_EOS:
        g_print ("End of stream\n");
        qDebug() <<" end of msg in gstreamer";
        g_main_loop_quit (loop);
        break;

    case GST_MESSAGE_ERROR: {
        gchar  *debug;
        GError *error;

        gst_message_parse_error (msg, &error, &debug);
        g_free (debug);

        g_printerr ("Error: %s\n", error->message);
        qDebug() <<" end of msg in gstreamer";
        g_error_free (error);

        g_main_loop_quit (loop);
        break;
    }
    default:
        break;
    }

    return TRUE;
}

StreamG::StreamG(QObject *parent) : QObject(parent)
{
    // Initialize GStreamer /
    gst_init( NULL, NULL );
    loop = g_main_loop_new( NULL, FALSE );

    // Create the elements
    source = gst_element_factory_make ("appsrc", "source");
    sink = gst_element_factory_make ("autovideosink", "sink");
    convert =gst_element_factory_make("videoconvert","convert");
    g_assert( convert );
    pipeline = gst_pipeline_new ("test-pipeline");

   /* g_object_set (G_OBJECT (source), "caps",
                  gst_caps_new_simple ("video/x-raw",
                                       "format", G_TYPE_STRING, "RGB",
                                       "width", G_TYPE_INT, 640,
                                       "height", G_TYPE_INT, 360,
                                       "framerate", GST_TYPE_FRACTION, 1, 1,
                                       NULL), NULL);*/

    g_object_set (G_OBJECT (source), "caps",
                  gst_caps_new_simple ("video/x-raw",
                                       "format", G_TYPE_STRING, "RGB",
                                       "width", G_TYPE_INT, 640,
                                       "height", G_TYPE_INT, 360, NULL), NULL);

}

void StreamG::start()
{
    addLinkElements();
    gst_element_set_state (pipeline, GST_STATE_PLAYING);
    // Iterate
    g_print ("Running...Gstreamer\n");
    g_main_loop_run (loop);

    // Out of the main loop, clean up nicely
    g_print ("Returned, stopping playback\n");
    gst_element_set_state (pipeline, GST_STATE_NULL);
}
void StreamG::stop()
{
    g_print ("Deleting pipeline\n");
    g_main_loop_quit(loop);
    gst_object_unref(GST_OBJECT(pipeline));
    gst_object_unref (bus);
    g_main_loop_unref (loop);
    emit sigFinish();
}

bool StreamG::addLinkElements()
{
    if (!pipeline || !source || !sink || !convert )
    {
        g_printerr ("Not all elements could be created.\n");
        return false;
    }
    // g_object_set (G_OBJECT ( source ), "device", "/dev/video0", NULL);
    gst_bin_add_many( GST_BIN (pipeline), source , sink,  convert, NULL );
    if (gst_element_link (convert, sink) != TRUE)
    {
        g_printerr ("Elements could not be linked confert sink.\n");
        gst_object_unref (pipeline);
        return false;
    }

    if (gst_element_link (source, convert) != TRUE)
    {
        g_printerr ("Elements could not be linked source -convert.\n");
        gst_object_unref (pipeline);
        return false;
    }
    g_print("Linked all the Elements together\n");


    /* we add a message handler */
    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
    gst_bus_add_watch (bus, bus_call, loop);
    g_object_set (G_OBJECT (source),
                  "stream-type", 0,
                  "format", GST_FORMAT_TIME, NULL);
    g_signal_connect (source, "need-data", G_CALLBACK (cb_need_data), NULL);
    return true;
}

Function in MainWidget .. I have places only imp member variables and functions

class UEYEMain : public QWidget
{
    Q_OBJECT
public:

    int openCamera( bool bStartLive );
    INT _GetImageID (char* pbuf);// 
    bool _AllocImages(); //function for IDS camera
    void onLive(); // function for IDS camera 
    void transferLastFrameToGstream();

private slots:
   void eventreceived (int event); // this is slot which receives frames and copied into StreamingG static varibale


private:
    Ui::UEYEMain *ui;
     .......
     .......
    StreamG* StreamingG;
    QElapsedTimer   m_Time;
      QRgb m_table[256];
    int  m_nUpdateTicks;
    QThread* threadForStream;
     char *m_pLastBuffer;

     EventThread *m_pEvFrame; // Another thread to recive frames

     void ProcessFrame(); // function on receiving frames

     void DrawImage (char *pBuffer); // this draw image to Qt widget , I use it for testing purpose

};

void UEYEMain::eventreceived (int event)
{
    bool bUpdateCameraList = false;
    switch (event)
    {... some other cases 
    case IS_SET_EVENT_FRAME:
        qDebug() << " new frame received";
        if (!m_hCamera)
        {
            break;
        }
        ProcessFrame ();
        break;

    default:
        break;
    }
}



 void UEYEMain::transferLastFrameToGstream()
 {
     //memcpy( StreamingG->bufferFrame, m_pLastBuffer, sizeof(m_pLastBuffer) );

     if(m_pLastBuffer ) // just pointing buffer to streamG variable
     {
         StreamingG->bufferFrame = m_pLastBuffer;
     }
 }


  void UEYEMain::ProcessFrame ()
{
    INT dummy = 0;
    char *pLast = NULL, *pMem = NULL;
    qDebug() << " counter for frame recv -->" << countFrameDebug;
    countFrameDebug++;
    is_GetActSeqBuf (m_hCamera, &dummy, &pMem, &pLast);
    m_pLastBuffer = pLast;
    if (m_bReady)
    {
        m_bReady = FALSE;
        update();
        if (m_pLastBuffer )
        {
            int nTicks = 0;
            // Frame rate limit ?
            if (m_nUpdateTicks > 0)
            {
               nTicks = m_Time.elapsed();
                bDraw = (nTicks >= m_nUpdateTicks) ? true : false;
            }

            if (bDraw)
            {
                nDisplayed++;
                m_Time.restart();
                transferLastFrameToGstream();
                //DrawImage(m_pLastBuffer); // this func succesffully stream video on Qt widget 
            }
        }
    }
} 

void UEYEMain::onLive()
{
    INT nRet = 1;
    time_t start;
    static char str[64];

    if (!m_bLive)
    {
        m_bLive = TRUE;
        m_bReady = TRUE;
        is_CaptureVideo (m_hCamera, IS_DONT_WAIT);
         threadForStream->start();

    }
}

The above function onLive() is called from another thread workThreadFinished

connect(m_workThread, SIGNAL(finished()), this, SLOT(workThreadFinished()), Qt::QueuedConnection);

The following is the output I get and I dont see StreamG::cb_need_data has been called more than once.

no of camera  detected :  1    
started event 2 detection!// this thread acquire frames     
started event 8 detection!     
Linked all the Elements together // gst        
Running...Gstreamer //gstreamer     
 cb_need_data is called ... // gstreamer        
 new frame received //     
 counter for frame recv --> 0    
 new frame received    
 counter for frame recv --> 1    
 new frame received     
 counter for frame recv --> 2    
 new frame received

........... and so on

来源:https://stackoverflow.com/questions/33943704/place-external-live-video-frames-from-non-supported-v4l-file-into-gstreamer-qt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!