網上示例
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,導致看起來很不流暢)