2016年3月15日 星期二

IP Camera Access using OpenCV and VLC

IP Camera Access using OpenCV and VLC

如果想要用OpenCV接收IPcam的串流來源,其中一種方法可以透過VLC的Library實現。

OpenCV下載

下載Windows版本,解壓縮後會看到build資料夾裡有已經編譯完的Visual Studio library,指要選擇你需要的版本便可。
- Header檔位置 : \opencv\build\include
- Library檔位置: \opencv\build\x86\vc10\lib
- Bin檔位置 : \opencv\build\x86\vc10\bin

此專案所需lib包含opencv_core248.lib、opencv_highgui248.lib
如果最後沒有設定環境變數,請將opencv_core248.dll及opencv_highgui248.dll移至執行目錄下。

VLC下載

請至官網下載VLC,安裝目錄下就會包含Visual Studio編譯的SDK。
- Header檔位置 : \VideoLAN\VLC\sdk\include
- Library檔位置: \VideoLAN\VLC\sdk\lib
- Bin檔位置 : \VideoLAN\VLC

此專案所需lib包含libvlc.lib、libvlccore.lib
如果最後沒有設定環境變數,請將plugins資料夾與libvlc.dll、axvlc.dll、libvlccore.dll及npvlc.dll移至執行目錄下。

#include "stdafx.h"
#include "cvaux.h"
#include "highgui.h"
#include <windows.h>
#include <iostream>
#include "vlc\libvlc.h"
#include "vlc\vlc.h"

#define VIDEO_WIDTH   640
#define VIDEO_HEIGHT  480

using namespace cv;

struct ctx
{
    Mat* image;
    HANDLE mutex;
    uchar *pixels;
};

void *lock( void *data, void**p_pixels )
{
    struct ctx *ctx = (struct ctx*)data;
    WaitForSingleObject( ctx->mutex, INFINITE );
    *p_pixels = ctx->pixels;
    return NULL;
}

void display( void *data, void *id )
{
    (void) data;
    assert( id == NULL );
}

void unlock( void *data, void *id, void *const *p_pixels )
{
    struct ctx *ctx = (struct ctx*)data;
    cv::Mat img = *ctx->image;
    imshow("test", img);
    ReleaseMutex( ctx->mutex );
    std::cout << "Image " << img.cols << std::endl;
    // cv::imwrite("cam.jpg", img);
}

int main()
{
    libvlc_instance_t  *vlcInstance;
    libvlc_media_player_t *mp;
    libvlc_media_t   *media;

    const char *const vlc_args[] = {
        "-I",
        "dummy",
        "--ignore-config",
        "--extraintf=logger",
        "--verbose=2",
    };

    int vlc_argc = sizeof(vlc_args) / sizeof(vlc_args[0]);

    //libvlc_instance_t* libvlc_new ( int argc, const char *const *argv )
    //用於初始化一個libvlc的實例,argc表示參數的個數,argv表示參數,返回創建的實例若當發生錯誤時返回NULL
    vlcInstance = libvlc_new( vlc_argc, vlc_args );
    if ( vlcInstance == NULL ) {
        std::cout << "Create Media Stream Error" << std::endl;
        return 0;
    }

    //LIBVLC_API libvlc_media_t* libvlc_media_new_location( libvlc_instance_t *p_instance, const char *psz_mrl )
    //使用一個給定的媒體資源路徑來建立一個libvlc_media對象,參數psz_mrl為要讀取的MRL(Media Resource Location),此函數返回新建的對像或NULL.
    const char *psz_mrl = "rtsp://admin:admin@192.168.10.216:554/stream1";
    media = libvlc_media_new_location( vlcInstance, psz_mrl );
    if ( media == NULL ) {
        std::cout << "Media Stream is Null" << std::endl;
        return 0;
    }

    //LIBVLC_API libvlc_media_player_t* libvlc_media_player_new_from_media( libvlc_media_t *p_md )
    //根據給定的媒體對象創建一個播放器對象
    mp = libvlc_media_player_new_from_media( media );

    // LIBVLC_API void libvlc_media_release( libvlc_media_t *p_md )
    //減少一個libvlc_media_t的引用計數,如果減少到0時,此函數將釋放此對象(銷毀).它將發送一個libvlc_MediaFreed事件到所有的監聽者那裡。如果一個libvlc_media_t被釋放了,它就再也不能使用了。
    libvlc_media_release(media);


    struct ctx* context = (struct ctx*)malloc( sizeof(*context) );
    context->mutex      = CreateMutex( NULL, false, NULL );
    context->image      = new Mat( VIDEO_HEIGHT, VIDEO_WIDTH, CV_8UC3 );
    context->pixels     = (unsigned char *)context->image->data;

    // show blank image
    cv::Mat img = *context->image;
    imshow("test", img);


    // LIBVLC_API void libvlc_video_set_callbacks( libvlc_media_player_t  *mp,
    //                                             libvlc_video_lock_cb    lock,
    //                                             libvlc_video_unlock_cb  unlock,
    //                                             libvlc_video_display_cb display,
    //                                             void *opaque )

    //設定Callback Function複製影像資訊,可藉由libvlc_video_set_format和libvlc_video_set_format_callbacks設定解碼資訊
    libvlc_video_set_callbacks( mp, lock, unlock, display, context );


    // LIBVLC_API void libvlc_video_set_format( libvlc_media_player_t *mp,
    //                                          const char *chroma,
    //                                          unsigned    width,
    //                                          unsigned    height,
    //                                          unsigned    pitch )
    //設定影像解碼資訊
    const char *chroma = "RV24";
    unsigned width     = VIDEO_WIDTH;
    unsigned height    = VIDEO_HEIGHT;
    unsigned pitch     = VIDEO_WIDTH * 24 / 8;
    libvlc_video_set_format( mp, chroma, width, height, pitch);


    // LIBVLC_API int libvlc_media_player_play( libvlc_media_player_t *p_mi )
    //開始播放串流影片
    libvlc_media_player_play(mp);


    while ( true ) {
        cv::waitKey( 1000 );
    }

    libvlc_media_player_stop( mp );
    libvlc_media_player_release( mp );
    libvlc_release( vlcInstance );

    return 0;
}

更多OpenCV文章請參考:OpenCV Tutorial (學習筆記)

0 意見:

張貼留言