c++ - 使用libVLC读取RTSP视频流+将数据转换为OpenCV Mat

标签 c++ opencv libvlc

我正在尝试使用 libVLC 库通过 IP 接口(interface)从 Sony FCB-EV7520 相机读取 RTSP 流,并将数据转换为 OpenCV 使用的格式,即 Mat 类型。几天来我一直试图找到一个很好的例子,但到目前为止我找到的唯一结果是 thisthis .我遵循了第一个示例中的代码,使其适应 RTSP 用例,但我还没有检索到 Mat 中的任何数据。但是,从终端输出来看,我似乎实现了与相机的连接。您是否看到代码中有任何明显的缺陷?还有其他(更简单的)方法可以实现我的目标吗?还有其他可以使用的库吗?任何帮助,将不胜感激!我运行的代码是:

#include <stdio.h>
#include <vlc/vlc.h>
#include <stdint.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

struct VideoDataStruct {
    int param;
};

int done = 0; 
libvlc_media_player_t *mp;
unsigned int videoBufferSize = 0;
uint8_t *videoBuffer = 0;

void cbVideoPrerender(void *p_video_data, uint8_t **pp_pixel_buffer, int size) {

    // Locking

    // Locking a mutex here once I get the code to work.    

    if (size > videoBufferSize || !videoBuffer){

        printf("Reallocate raw video buffer\n");
        free(videoBuffer);
        videoBuffer = (uint8_t *) malloc(size);
        videoBufferSize = size;

    }

    *pp_pixel_buffer = videoBuffer;
}  

void cbVideoPostrender(void *p_video_data, uint8_t *p_pixel_buffer, int width, int height, int pixel_pitch, int size, int64_t pts) {

    // Unlocking

    // Unlocking the mutex here once I get the code to work.

}

static void handleEvent(const libvlc_event_t* pEvt, void* pUserData) {
    libvlc_time_t time;
    switch(pEvt->type){

        case libvlc_MediaPlayerTimeChanged:

            time = libvlc_media_player_get_time(mp);
            printf("MediaPlayerTimeChanged %lld ms\n", (long long)time);
            break;

        case libvlc_MediaPlayerEndReached:

            printf ("MediaPlayerEndReached\n");
            done = 1;
            break;

        default:

            printf("%s\n", libvlc_event_type_name(pEvt->type));

    }
}

int main(int argc, char* argv[]) {

    // VLC pointers: 

    libvlc_instance_t *inst;
    libvlc_media_t *m;
    void *pUserData = 0;
    VideoDataStruct dataStruct;

    // VLC options:

    char smem_options[1000];

    // RV24:

    sprintf(smem_options
            , "#transcode{vcodec=h264}:smem{"
            "video-prerender-callback=%lld,"
            "video-postrender-callback=%lld,"
            "video-data=%lld,"
            "no-time-sync},"
            , (long long int)(intptr_t)(void*)&cbVideoPrerender
            , (long long int)(intptr_t)(void*)&cbVideoPostrender
            , (long long int)(intptr_t)(void*)&dataStruct
           );

    const char * const vlc_args[] = {
        "-I", "dummy",            // Don't use any interface
        "--ignore-config",        // Don't use VLC's config
        "--extraintf=logger",     // Log anything
        "--verbose=2",            // Be verbose
        "--sout", smem_options    // Stream to memory
    };

    // We launch VLC

    inst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);

    /* Create a new item */

    m = libvlc_media_new_location(inst, "rtsp://*****:*******@IP/videoinput_1/h264_1/media.stm");

    /* Create a media player playing environement */

    mp = libvlc_media_player_new_from_media (m);

    libvlc_event_manager_t* eventManager = libvlc_media_player_event_manager(mp);
    libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged, handleEvent, pUserData);
    libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, handleEvent, pUserData);
    libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, handleEvent, pUserData);

    libvlc_video_set_format(mp, "h264", 1920, 1080, 1920* 3 );

    /* play the media_player */
    libvlc_media_player_play (mp);

    while(1){

        if(videoBuffer){            // Check for invalid input

            Mat img = Mat(Size(1920, 1080), CV_8UC3, videoBuffer);  // CV_8UC3 = 8 bits, 3 chanels
            namedWindow("Display window", WINDOW_AUTOSIZE);     // Create a window for display.
            imshow("Display window", img);              // Show our image inside it.

        }
    }

    libvlc_release (inst);

}

我正在使用 OpenCV 3.2 和 libVLC 2.2.5.1 在 Ubuntu 16.04 上运行代码。如果您需要任何其他信息,请直接询问。

PS:我知道流正在工作,因为我可以通过 VLC 播放器的流媒体界面打开它。我也知道 libVLC 可以解码流,因为我已经成功打开流的录制 mp4。

最佳答案

不是一个完整的答案,但对于评论来说太长了:

cbVideoPrerender中,videoBuffer总是根据vlc的需要进行分配。
但是,在 main 中,您有循环 while(1){ if (videoBuffer) { ... } } ,其中 videoBuffer 始终为真从第一次调用 cbVideoPrerender 开始。这意味着从那时起,循环是无限的和非阻塞的,所以视频的输入和处理之间没有同步,如果你只是想得到第一张图像,你就太早了。

你的 first link建议使用 cbVideoPostrender 作为同步点,这样您就知道可以读取帧,从而将其转换为所需的格式。它是在函数本身中完成的,但是您可以使用 condition variable 的某种机制。 (队列、事件、...)在另一个线程中处理帧并将图像传递给 openCV。

顺便说一下:通过在一个线程中设置并在另一个没有线程机制(互斥锁、原子)的情况下读取变量来使用变量是一个坏主意。

关于c++ - 使用libVLC读取RTSP视频流+将数据转换为OpenCV Mat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43654051/

相关文章:

c# - Vlc.DotNet - 在播放音频之前无法设置音量

c++ - 在 .cpp 中的类主体外部定义内联函数

python - OpenCV 在 vi​​deo.read 上返回一个全零数组

stream - vlcj::无法在 64 位操作系统中加载库 'libvlc'

python - OpenCV python上的人脸识别问题

c# - 鼠标点击事件坐标与找到的棋盘角坐标不匹配或对齐 - EmguCV/WPF

c++ - LibVLC 的新手 - 在 VS2010 上试用 libVLC

c++ - 我们可以假设以下任何一对浮点算术语句总是产生相同的结果吗?

c++ - 这种 boost 条件代码的使用有问题吗?

c++ - 不能包含 cliext header (对于 c++ cli、Visual Studio)