嵌入式环境下基于onvif协议取得的RTSP视频流以及opencv的交叉编译

Linux版本:ubuntu12.04

Arm平台:Tiny4412

交叉编译工具:arm-none-linux-gnueabi-gcc-4.5.1、arm-none-linux-gnueabi-g++

  • 交叉编译opencv:

1、准备opencv依赖库以及opencv源码包:zlib-1.2.7、jpegsrc.v7、libpng-1.5.8、yasm-1.3.0、x264-snapshot-20120608-2245、xvidcore-1.3.3、ffmpeg-2.8.14、opencv-2.4.9

2、编译libz:

进入zlib源码目录,

执行:

 ./configure --prefix=./configure --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi –shared

(--prefix=可以修改为自己定义的安装目录)

修改makefile

CC=arm-linux-gcc

AR=arm-linux-ar

RANLIB=arm-linux-ranlib

LDSHARED=arm-linux-gcc -shared -wl, -soname,libz.so.1,--version-script,zl

lib.map

make

make install

生成的库文件:

生成的头文件:

3、编译libjpeg:

进入libjpeg源码目录,

执行:

./configure --host=arm-linux --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi --enable-shared --enable-static

make

make install

生成库文件:

生成头文件:

4、编译libpng:

进入libpng源码目录,

执行:

./configure --host=arm-linux --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi --enable-shared --enable-static

make

make install

生成库文件:

生成头文件:

5、编译yasm:

进入yasm目录,

执行:

./configure --host=arm-linux --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi --enable-shared --enable-static

make

make install

生成库文件:

生成头文件:

6、编译libx264:

进入libx264目录,

执行:

CC=arm-linux-gcc-4.5.1 ./configure --enable-shared --host=arm-linux --disable-asm --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi

make

make install

生成库文件:

生成头文件:

7、编译libxvid:

进入libxvid下的build/generic/目录,

执行:

./configure --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi --host=arm-linux --enable-shared --disable-assembly

make

make install

生成库文件:

生成头文件:

8、编译ffmpeg:

进入ffmpeg目录,

执行:

./configure --prefix=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi --enable-shared --disable-static --enable-gpl --enable-cross-compile --arch=arm --disable-stripping --target-os=linux --enable-libx264 --enable-libxvid extra-cflags=-I/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi/include --extra-ldflags=-L/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi/lib --cc=arm-linux-gcc --enable-swscale

make

make install

生成库文件:

生成头文件:

=====================================================================

在生成的库文件的路径有一个pkgconfig文件夹,里面是编译上面各个库时候生成的.pc文件,.pc文件存放的是生成的库文件安装路径以及头文件路径,还有库的版本信息。例如打开zlib.pc:

此时,可以在终端输入ehco $PKG_CONFIG_PATH命令查看系统搜索库文件的路径。系统默认是从/lib以及/usr/lib下搜索。可以通过修改/etc/profile配置文件使在下一步编译opencv时从刚才安装opencv依赖库文件的路径搜索对应的库文件。

9、编译opencv_2.4.9:

进入opencv_2.4.9源码目录,新建编译目录build,进入build目录,新建一个toolchain.cmake文件,加入以下内容:

set( CMAKE_SYSTEM_NAME Linux )

set( CMAKE_SYSTEM_PROCESSOR arm )

set( CMAKE_C_COMPILER arm-linux-gcc )

set( CMAKE_CXX_COMPILER arm-linux-g++ )

set( CMAKE_FIND_ROOT_PATH "/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi" )

set( CMAKE_C_FLAGS "-Wl,-rpath-link=/opt/exynos4412-linux/arm-linux-4.5.1/arm-none-linux-gnueabi")

set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )

set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )

set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )

CMAKE_FIND_ROOT_PATH为前面安装的依赖库的目录。

然后在build目录下执行:

cmake -D CMAKE_TOOLCHAIN_FILE=toolchain.cmake ../

可以看到输出信息有:

支持FFMPEG编解码。

生成CMakeCache.txt文件,里面存放的是配置信息

可以通过cmake-gui载入该文件从而通过可视化界面修改配置信息。还可以在build目录下执行:ccmake .也可以修改配置信息。

 

需要关闭的编译选项有:

WITH_1394、WITH_CUBLAS、WITH_CUDA、WITH_GTK、WITH_LIBV4L、WITH_OPENCL、WITH_OPENEXR、WITH_OPENGL、WITH_TIFF

可以CMAKE_INSTALL_PREFIX选项更修改opencv库的安装目录。

修改完后,按C生成配置文件,按G保存更改。

修改CMakeCache.txt的CMAKE_EXE_LINKER_FLAGS:STRING=

加上-lpthread -lrt

执行:

make

make install

生成库文件:

生成头文件:

 

二、gsoap生成onvif框架代码:

本人开发环境为:

  1. 虚拟机:Ubuntu12.04
  2. 必备网址:

 Onvif官网:http://www.onvif.org/

 gsoap官网:http://www.cs.fsu.edu/~engelen/soap.html

3. 下载gsoap

根据以上提供的地址,登陆gsoap官网下载最新的安装包和相关文档;截止今天(2013年8月5日),官网发布的最新版本的gsoap工具为2.8.15版本;最新版本的使用,可以参考文档:《gSOAP 2.8.15 User Guide .pdf》,该文档有非常详细的说明,现在网络上的大部分的demo都是copy这里的;该文档值得研究;该文档在其官网上可以下载,下载地址为:http://www.cs.fsu.edu/~engelen/soap.html;也可以在官网在线查看;或者,可以在gsoap安装包里面找到该文档,路径为:gsoap_2.8.15/gsoap-2.8/gsoap/doc, 名字为soapdoc2.pdf的文件。

4. 安装

将下载的安装包解压,并拷贝到linux的操作目录,本人操作目录为:

$: /gsoap-2.8

以上面的目录为例:(注意以下操作均在root用户权限下进行)

首先进入目录cd /gsoap-2.8/

然后,配置编译环境:

命令:$:./configure --host=arm-linux CC=arm-linux-gcc --prefix=/usr/local/x86-gsoap-2.8

然后,编译连接

命令:$:make

 

编译gsoap时如果报错:/gsoap-2.8/missing: line 81: aclocal-1.15: command not found

解决方法为:

安装新版本的automake

wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz

最后,安装gSOAP

命令:$:make install

 

5. onvif头文件生成

 

命令wsdl2h用于生成头文件,命令soapcpp2用于生成源文件;这两个命令在/usr/local/x86-gsoap-2.8/bin中可以找到。

工具安装完成之后可以在linux下重新建立一个自己的目录,用来生成代码:

这里建立目录:onvif-source

完整路径为:/usr/local/onvif-source/

将gsoap 目录下的typemap.dat文件拷贝到目录onvif-source

(1)在线生成头文件:

在onvif-source目录下执行命令(加上-c可以只生成客户端代码):

./wsdl2h -o onvif.h -s -t ./typemap.dat

http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl

http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl

http://www.onvif.org/onvif/ver10/display.wsdl

http://www.onvif.org/onvif/ver10/deviceio.wsdl

http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl

http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl

http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl

http://www.onvif.org/onvif/ver10/receiver.wsdl

http://www.onvif.org/onvif/ver10/recording.wsdl

http://www.onvif.org/onvif/ver10/search.wsdl

http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl

http://www.onvif.org/onvif/ver10/replay.wsdl

http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl

http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl

http://www.onvif.org/onvif/ver10/schema/onvif.xsd

http://www.onvif.org/ver10/actionengine.wsdl

每个网址之间用空格分开,执行完命令即可生成头文件onvif.h。

 (2)离线生成头文件

如果当前电脑无法联网,则可以通过离线的方式来生成,命令为:

~onvif_new$: wsdl2h -o onvif.h -c -s -t ./typemap.dat devicemgmt.wsdl media.wsdl event.wsdl display.wsdl

deviceio.wsdl imaging.wsdl ptz.wsdl receiver.wsdl recording.wsdl search.wsdl remotediscovery.wsdl

replay.wsdl analytics.wsdl analyticsdevice.wsdl actionengine.wsdl accesscontrol.wsdl doorcontrol.wsdl

注意不同的wsdl以空格分开。

目前Onvif官网提供的最新的WSDL文件一共有17个,可以将其下载下来。不过这些文件直接都是相互关联的,下载的话,除了这17个文件之外,还要下载所有相关联的文件。另外,下载之后,还需要更改文件中的路径,将wsdl文件中的schemaLocation以及location所指的路径进行修改,修改为本地的地址。将所有需要下载的文件下载到onvif_new目录,并修改相关地址。当然如果网速够快,提倡直接在线生成头文件和源文件。另外为了避免后续开发过程中出现某些功能的缺省,最好一次性生成包含所有功能的代码。

6. 源文件的生成

生成onvif.h头文件之后,即可根据soapcpp2命令生成C源文件或者CPP源文件(加上-c可以生成.c源文件)。

命令为:

./soapcpp2 onvif.h -x -I /gsoap-2.8/gsoap/import/ -I /gsoap-2.8/gsoap/

生成过程中有错误:

wsa5.h(288): **ERROR**: remote method name clash: struct/class 'SOAP_ENV__Fault' already declared at line 274

 

可以发现这是由于重复定义导致,可以修改该文件。

打开文件/gsoap-2.8/gsoap/import/wsa5.h,将277行int SOAP_ENV__Fault修改为int SOAP_ENV__Fault_alex

再执行命令:./soapcpp2 onvif.h -x -I /gsoap-2.8/gsoap/import/ -I /gsoap-2.8/gsoap/

生成成功会有Compilation successful字样。

生成的源文件:

开发onvif客户端所需要的源文件有:

需要的头文件有:

duration.cpp、duration.h存放在gsoap的源码目录下:

 

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例代码,用于从 ONVIF 设备读取视频流并提取每一帧图像: ```java import javax.xml.soap.SOAPException; import javax.xml.ws.soap.SOAPFaultException; import org.onvif.ver10.schema.VideoEncoderConfiguration; import org.onvif.ver10.schema.VideoResolution; import org.onvif.ver10.schema.VideoSource; import org.onvif.ver10.schema.VideoSourceConfiguration; import com.sun.xml.ws.client.ClientTransportException; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.*; import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; public class ONVIFExample extends JPanel { private static final long serialVersionUID = 1L; private static final String MEDIA_PROFILE_TOKEN = "MediaProfile000"; private static final String SERVICE_URI = "http://192.168.1.1/onvif/device_service"; private static final String USER = "admin"; private static final String PASSWORD = "admin"; private BufferedImage currentImage = null; public ONVIFExample() { super(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (currentImage != null) { g.drawImage(currentImage, 0, 0, this); } } public void readStream() throws Exception { String videoUrl = getVideoUrl(SERVICE_URI, USER, PASSWORD); if (videoUrl == null) { throw new Exception("Failed to get video URL"); } String[] urlParts = videoUrl.split(":"); String host = urlParts[0]; int port = Integer.parseInt(urlParts[1]); InputStream inputStream = null; ByteArrayOutputStream byteArrayOutputStream = null; try { URL url = new URL(videoUrl); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestProperty("Authorization", "Basic " + getEncodedAuth(USER, PASSWORD)); inputStream = httpConn.getInputStream(); byteArrayOutputStream = new ByteArrayOutputStream(); byte[] chunk = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(chunk)) > 0) { byteArrayOutputStream.write(chunk, 0, bytesRead); if (byteArrayOutputStream.size() > 1024 * 1024) { currentImage = getBufferedImage(byteArrayOutputStream.toByteArray()); byteArrayOutputStream.reset(); repaint(); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (byteArrayOutputStream != null) { try { byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } private static String getVideoUrl(String serviceUrl, String user, String pass) { String mediaUrl = null; try { DeviceService deviceService = new DeviceService(serviceUrl, user, pass); VideoEncoderConfiguration encoderConfiguration = deviceService.getVideoEncoderConfiguration(MEDIA_PROFILE_TOKEN); VideoSourceConfiguration sourceConfiguration = deviceService.getVideoSourceConfiguration(encoderConfiguration.getSourceToken()); VideoSource videoSource = deviceService.getVideoSource(sourceConfiguration.getSourceToken()); VideoResolution resolution = encoderConfiguration.getResolution(); Dimension dimension = new Dimension(resolution.getWidth(), resolution.getHeight()); mediaUrl = deviceService.getSnapshotUri(dimension.width, dimension.height); } catch (SOAPFaultException e) { e.printStackTrace(); } catch (ConnectException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (SOAPException e) { e.printStackTrace(); } return mediaUrl; } private static String getEncodedAuth(String user, String pass) { String authStr = user + ":" + pass; String authEncoded = javax.xml.bind.DatatypeConverter.printBase64Binary(authStr.getBytes()); return authEncoded; } private static BufferedImage getBufferedImage(byte[] imageData) { BufferedImage bufferedImage = null; try { InputStream inputStream = new ByteArrayInputStream(imageData); bufferedImage = ImageIO.read(inputStream); } catch (IOException e) { e.printStackTrace(); } return bufferedImage; } public static void main(String[] args) { JFrame frame = new JFrame("ONVIF Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ONVIFExample onvifExample = new ONVIFExample(); frame.add(onvifExample); frame.setSize(640, 480); frame.setVisible(true); try { onvifExample.readStream(); } catch (Exception e) { e.printStackTrace(); } } } ``` 这个示例代码使用了 ONVIF 的 Java 实现,它可以帮助你通过 ONVIF 协议从相应的设备获取视频流。在获得视频流之后,代码会将每一帧图像转换为 BufferedImage,并在 JPanel 上绘制出来。你可以根据你的需求修改代码以实现更多功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值