最近因为项目的原因,需要和网络摄像头进行沟通,以谋取摄像头视频帧(因鱼眼摄像头有畸变,采用将每帧进行畸变处理—利用opencv提供的方法),尝试了很多方法,讲方法所示方法列出(本人技术渣渣,如有错误,请指教)
- 采用VLC第三方库进行视频的获取
- 采用opencv中rtsp协议
-
采用opencv中http协议
方法比较:
方法 | 问题 |
---|---|
VLC | 通常会出现延迟性问题 |
rtsp | 坏包 |
http | 开始时有延迟,等待3s后恢复正常 |
vlc demo 示例及部分理解:
介绍:VLC Media Player是一款优秀的播放器,但是由于它的源代码编译的难度比较大,一直没有深入研究过它的开发方面的技术。此前触到了一些VLC开发方面的东西,因此总结了一下libVLC的开发示例程序。获取vlc很简单,只需网上下载即可(此处自动忽略自行编译方法,因为windows下编译过于麻烦)
开发vlc文件位置
: 动态链接库*.dll:安装目录下的libvlc.dll,libvlccore.dll以及plugins目录下的所有文件。
PS:VLC支持非常多的plugin。因此plugins目录的体积确实是非常大的。
: 静态链接库*.lib:安装目录/sdk/lib
: 头文件*.h:安装目录/sdk/include
具体流程如图(此处参考libvlc视频播放器流程图)
其中流程图中主要包括三个结构体,这些结构体实例用于创建相关的播放:
libVLC实例:libvlc_instance_t
播放媒体:libvlc_media_t
媒体播放器:libclv_media_player_t
以上的三个结构体通过以下函数进行创建和设置内容:
结构体函数 :
结构体 | 创建 | 释放 |
---|---|---|
libvlc_instance_t | libvlc_new() | libvlc_release |
libvlc_media_t | libvlc_new_from_media() | libvlc_media_release() |
libclv_media_player_t | libvlc_media_player_new_from_media | libvlc_media_player_release() |
注:1.函数控制媒体的播放和暂停(使用libvlc_media_player_t作为参数)
如:libvlc_media_player_X(),其中X={play,pause,stop}
2.创建libvlc_media_t方法:
方法 | 用途 | 示例 |
---|---|---|
libvlc_media_new_path() | 打开文件(就是普通的文件路径(绝对路径例如D:\xxx.flv,或者相对路径例如xxx.flv)) | libvlc_media_new_path(“F:\movie\demo.flv”) |
libvlc_media_new_location | 打开协议(广义协议,也可打开文件) | libvlc_media_new_location(inst,”rtsp://admin:admin@192.168.1.115:554”);\n文件: libvlc_media_new_location(inst, “file:///F:\movie\demo.flv”); |
此外,VLC还支持很多“神奇”的协议,比如输入“screen://”协议就可以进行屏幕录制,代码如下。
libvlc_media_new_location (inst, “screen://”);
示例代码:
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <vlc/vlc.h>
#pragma comment(lib, "libvlc.lib")
#pragma comment(lib, "libvlccore.lib")
int main(int argc,char* argv[])
{
libvlc_instance_t*inst;
libvlc_media_t *m;
libvlc_media_player_t *mp;
libvlc_time_t length;
int width;
int height;
int wait_time =5000;
/* Load the VLC engine*/
inst = libvlc_new(0,NULL);
//Create a new item;
//Method 1:
m = libvlc_media_new_location(inst,"rtsp://admin:admin@192.168.1.115:554"); //用于打开协议;
libvlc_media_add_option(m, ":network-caching=250");
//Screen Capture;
//m = libvlc_media_new_location(inst,"screen://");
//Method 2:
//m = libvlc_media_new_path(inst,"c:\\1.avi");//用于打开文件;
//m = libvlc_media_new_location(inst,"file:///c:\\1.avi");//广义协议;
/* Create a media player playing environement */
mp = libvlc_media_player_new_from_media(m);
length = libvlc_media_player_get_length(mp);
// play the media_player;
libvlc_media_player_play(mp);
//Let it play;
_sleep(length-wait_time);
//Stop playing;
libvlc_media_player_stop(mp);
//Free the media_player;
libvlc_media_player_release(mp);
libvlc_media_release(m);
libvlc_release(inst);
return 0;
}
说了这么多,可以简单实现播放视频数据了,现在进入我所需要的,获取视频中的每一帧;
为了从Rtsp地址获取实时帧数据, VLC作为Rtsp的客户端,拉网络视频流。然后进行实时解码(内部进行),自己获得码流(RGBA数据,32位RGB),显示
基本流程:
1.libvlc_new()
2.libvlc_media_new_location()
3.libvlc_media_player_new_from_meida() //构建mediaplayer;
4.libvlc_video_set_callbacks()
5.libvlc_media_player_play() //注:重要,获取视频帧时,需要将mp进行运行才行;
loop
6.release:
libvlc_media_player_release
libvlc_release
说明:
1、libvlc_video_set_callbacks //为了获得实时流,就需要进行回调libvlc_video_set_callbacks
需要设置三个回调,我们需要获得buffer的大小,视频的width和height
buffer = width*height*4;
在lock函数中需要锁住,在unlock中解锁。实际上的是display
相关函数 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 );
这个函数的作用如下:
1.mp是media player的一个实例。
2.lock,每当有视频进行新的一帧的解码时,会调用lock来锁住内存。
3.unlock,在解码完至显示之间,可对每一帧数据进行操作。
4.display,对数据进行显示。
5.opaque,唯一的一个传递参数的指针。所以,一般都是指向一个结构体,而结构体包括了很多其它需要的参数
libvlc_video_set_callbacks()函数 ,它的参数有三个回调函数,格式类似:
void *lock(void *opaque, void **plane); //opaque, 唯一的一个传递参数的指针,传递参数结构体
//planes 指向图像阵列
//此函数还会返回图像buffer的指针,供unlock和display使用,即为picture指针。
void unlock(void *opaque, void *picture, void *const *planes); //picture即为lock返回的指针
void display(void *opaque, void *picture); //该函数用opaque和picture进行显示
另外,还要搭配libvlc_video_set_format或者libvlc_video_set_format_callbacks使用
void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
unsigned width, unsigned height,
unsigned pitch );
注:chroma是形如“RV32”、“YUYV”的字符串。pitch一般是height的4倍
void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
libvlc_video_format_cb setup,
libvlc_video_cleanup_cb cleanup );
setup:
typedef unsigned (*libvlc_video_format_cb)(void **opaque, char *chroma,
unsigned *width, unsigned *height,
unsigned *pitches,
unsigned *lines);
注: **opaque指向opaque的指针的指针,用于传入libvlc_video_set_callbacks的参数。chroma如上,用形如strcpy(chroma,”RV32”)即可。此处width和height均可重新定义。pitches一般height的4倍,lines一般等于width。
cleanup:
typedef void (*libvlc_video_cleanup_cb)(void *opaque);
注:用于释放已分配的内存。可以是NULL。
该扯的扯的差不多了,现在说一下他的延迟问题,本渣渣查了很多资料,不知道延迟问题如何解决,始终存在1s左右的延迟,查资料解决如下: libvlc_media_add_option(m_vlcMedia,":network-caching=300");
//网络延迟时间也可以根据需要修改,这个值越小,实时性越好,当然太小了播放会很卡,或者设置的值失效;一般建议在100-300之间,如果网络环境较好,300ms以内效果很好,实时性较好;
最终效果保证在1s内,但是仍有延迟。
文章太长了,下篇介绍opencv访问网络摄像头