网上示例
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
#include "vlc/vlc.h"
#include
#include
#include
#include
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,导致看起来很不流畅)