基於OpenCV的視頻圖像組態 (13):VLC Player解碼幀數據

網上示例

vlc是一套優秀的開源媒體庫,其特點是提供了完整的流媒體框架, 用它可以非常方便的實現抓取解碼幀的功能。

與此功能有關的關鍵API爲

libvlc_video_set_callbacks /*設置回調,用來抓取解碼後的幀*/

libvlc_video_set_format /*設置解碼幀的格式 yuv or rgba ?*/

這個函數將三個函數指針作爲參數

/*callback function, lock the shared memory, and tell vlc

where to put the output frame data*/

static void *lock(void *data, void **p_pixels);

 

 

/*##get the out frame data AND u can save it to file, or sent it

to a next module*/

static void unlock(void *data, void *id, void *const *p_pixels);

 

/*how to display the result frame data, u can let vlc do not pop out the displaying gui via this fuction. */

static void display(void *data, void *id);

 

下面是完整示例子:

#include "stdafx.h"

#include <Windows.h>

#include "vlc/vlc.h"

#include <vector>

#include <qmutex>

#include <sstream>

#include <qimage>

 

QMutex g_mutex;

bool g_isInit = false;

int IMG_WIDTH = 640;

int IMG_HEIGHT = 480;

char in_buffer[640*480*4];

char out_buffer[640*480*4];

FILE *local;

int frameNum = 0;

 

const char* TestFile = "b040_20170106.dat";

//////////////////////////////////////////////////////////////////////////

static void *lock(void *data, void **p_pixels)

{

g_mutex.lock();

*p_pixels = out_buffer; /*tell VLC to put decoded data to this buffer*/

return 0; /* picture identifier, not needed here */

}

 

/*##get the argb picture AND save to file*/

static void unlock(void *data, void *id, void *const *p_pixels)

{

QImage image((unsigned char*)out_buffer,640,480,QImage::Format_ARGB32);

std::ostringstream oss;

oss << "d:/img"

<< frameNum

<< ".jpg";

frameNum++;

image.save(oss.str().c_str());

g_mutex.unlock();

}

 

static void display(void *data, void *id)

{

/* do not display the video */

(void) data;

}

 

 

 

//////////////////////////////////////////////////////////////////////////

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

{

libvlc_instance_t * inst;

libvlc_media_player_t *mp;

libvlc_media_t *m;

 

libvlc_time_t length;

int wait_time=5000;

 

/* Load the VLC engine */

inst = libvlc_new (int(options.size()), options.data());

 

 

// Configure any transcoding or streaming

// options for the media source.

options.clear();

 

//Create a new item

//Method 1:

//m = libvlc_media_new_location (inst, "file:///F:\\movie\\cuc_ieschool.flv");

//Screen Capture

//m = libvlc_media_new_location (inst, "screen://");

//Method 2:


m = libvlc_media_new_path (inst, "D:\\warehouse\\data\\615\\haze.mp4");

/* Create a media player playing environment */

mp = libvlc_media_player_new_from_media (m);

 

 

/* No need to keep the media now */

libvlc_media_release (m);

 

/*##comment the followint 2 lines , if you want the out frame display in screen*/

libvlc_video_set_callbacks(mp, lock, unlock, display, 0);

libvlc_video_set_format(mp, "RGBA", IMG_WIDTH, IMG_HEIGHT,IMG_WIDTH*4);

 

// play the media_player

libvlc_media_player_play (mp);

 

//wait until the tracks are created

_sleep (wait_time);

length = libvlc_media_player_get_length(mp);

IMG_WIDTH = libvlc_video_get_width(mp);

IMG_HEIGHT = libvlc_video_get_height(mp);

printf("Stream Duration: %ds\n",length/1000);

printf("Resolution: %d x %d\n",IMG_WIDTH,IMG_HEIGHT);

 

//Let it play

_sleep (length-wait_time);

 

// Stop playing

libvlc_media_player_stop (mp);

 

// Free the media_player

libvlc_media_player_release (mp);

 

libvlc_release (inst);

 

return 0;

}



改編實現

 

仔細研究網上代碼,最終將VLCWrapper改造一下。

static void *lock(void *opaque, void **plane) {

    VLCWrapper *vlcWrapper = (VLCWrapper*)opaque;

    vlcWrapper->Lock();

    *plane = vlcWrapper->FMat.data;

    return NULL;

}

 

static void unlock(void *opaque, void *pic, void * const *plane) {

    VLCWrapper *vlcWrapper = (VLCWrapper*)opaque;

    vlcWrapper->Draw();

    vlcWrapper->Unlock();

}

 

static void display(void *opaque, void *pic) {
    (void)opaque;
}

 

void __fastcall VLCWrapper::Lock() {

    EnterCriticalSection(&g_VlcCriticalSection);

}

 

void __fastcall VLCWrapper::Unlock() {
    LeaveCriticalSection(&g_VlcCriticalSection);
}

void __fastcall VLCWrapper::Draw() {

    static int radius = 100; // 測試畫一個不斷長大的圓

    radius += 3;

    if(radius > 1000)

        radius = 100;

    circle(FMat, cv::Point(100, 100), radius / 10, cv::Scalar(255, 255, 255), 3);

    GlobalOpenCVObject->DrawMat(hWnd, FMat, FDisplayWidth, FDisplayHeight);

}

 void __fastcall VLCWrapper::SetTriggleCallback(bool value) {
	Lock();
	try {
		FTriggleCallback = value;
		if(FTriggleCallback)
			libvlc_video_set_callbacks(pImpl_->pMediaPlayer_, lock, unlock, display, this);
		else
			libvlc_video_set_callbacks(pImpl_->pMediaPlayer_, NULL, NULL, NULL, NULL);
	} __finally {
		Unlock();
	}
}



演示效果

  

 (因爲視頻文件大小限制,所以最終生成的幀頻爲2,導致看起來很不流暢)


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