HEXA机器人嵌入式 Linux C ARM 我爱编程

HEXA娱乐开发日志技术点003——下位机成功推流

2018-04-14  本文已影响34人  阿棍儿_Leon

HEXA开发日志目录
上一篇 HEXA娱乐开发日志技术点002——下位机成功获取弹幕


成果

目前,我手中的HEXA机器人可以用RTMP协议推流flv文件了,即用flv作为视频源做直播,并且此功能已在奥点云和B站试验成功。如果要推实时视频,还需要一些后续工作,这次只说flv文件推流的事。
源码版本812171d9eb56768c18d525b6e3c61b1ae7c315ee
目前的控制端网页长这样,在推流测试的地址中填入rtmp服务器地址后,点击“推”即可启动demo,并开始推流

控制端网页
这是目前这个skill的目录结构,本次主要添加了一个rtmp.go和deps目录下的一堆依赖文件。
DanmuDriveMe
├── manifest.json
├── remote
│   └── index.html==>控制端网页
├── robot
│   ├── assets
│   │   └── test.flv==>用于测试的flv文件
│   ├── deps
│   │   ├── include==>C文件,包括librtmp库头文件和我对librtmp库的封装
│   │   │   ├── amf.h
│   │   │   ├── log.h
│   │   │   ├── rtmp.h
│   │   │   └── rtmp_sample_api.c==>我对librtmp库的简单封装
│   │   └── lib==>依赖库,包括librtmp所依赖的openssl、zlib库
│   │       ├── libcrypto.so -> libcrypto.so.1.0.0
│   │       ├── libcrypto.so.1.0.0
│   │       ├── librtmp.so -> librtmp.so.1
│   │       ├── librtmp.so.1
│   │       ├── libssl.so -> libssl.so.1.0.0
│   │       ├── libssl.so.1.0.0
│   │       ├── libz.so -> libz.so.1
│   │       ├── libz.so.1 -> libz.so.1.2.11
│   │       └── libz.so.1.2.11
│   └── src==>go代码
│       ├── Danmu.go==>弹幕相关
│       ├── DanmuDriveMe.go
│       └── rtmp.go==>推流相关

从文件角度,目前的依赖或调用关系大概是这样
index.html ==> DanmuDriveMe.go ==> rtmp.go ==> rtmp_sample_api.c ==> librtmp.so ==> libssl.so+libcrypto.so+libz.so

How To

在做之前,先理清一下关于步骤的逻辑。

  1. 要先在电脑上跑通
    推流要使用开源C工程rtmpdump中的librtmp库,在不熟悉它的情况下,最好先在电脑上demo成功,同时在此过程中了解rtmpdump的使用。
  2. 要封装librtmp库
    封装是为了方便给Go程序调用,如果不封装的话,就要在Go程序中使用很多复杂的C数据类型,这会带来很多麻烦,因此要对librtmp库进行简单封装以保持与Go对接的C接口和数据类型都足够简单。
  3. 用Go程序测试这个封装
    这点不必多说,前面的简单封装就是为了方便Go程序调用的。
  4. 本次最终目标——下位机推流
    这里有个大前提,即这是一个嵌入式平台,所以不管搞什么,都要针对平台来做,所有C库,都必须交叉编译才能用。包括librtmp库和它所依赖的库,统统要交叉编译。

前3步的工作体现在我的rtmpdump工程源码的以下文件中

在上位机demo rtmpdump

这项内容在网上资料很多,这里只讲一些值的一说的点。

上位机封装与Go程序

如果熟悉了librtmp库的使用,封装就很简单,这里就不多说了,只说一些稍微值得一提的点吧。

package <包名>
/*
#cgo LDFLAGS: ld参数,比如-L...和-l...之类的,和Makefile常见的写法一样的
#cgo CFLAGS: gcc参数,比如-I...之类的,也合Makefile常见写法一样的
//此处写C代码完全是C语法
void c_fun(){}
*///此处和下一句import "C"之间不可以有空行
import "C"
import(
<其他包>
...
)
func go_func_name() {
    C.c_fun() //调用C函数
}
//buf 是[]byte类型
cc := C.CString(string(buf))
//rtmp_sample_add_data第一个参数要char *类型
C.rtmp_sample_add_data(cc, C.int(datalength)+15)
C.free(unsafe.Pointer(cc))

下位机推流

有了上位机的demo之后,下位机代码就很好写了,所以这个步骤的难点不在于代码,而在于如何交叉编译动态链接库并正确引用他们。

如何建立交叉编译环境?

如果想效仿官方做法,一个方法是读mind SDK的源码,我这么做得到了以下认知:

要交叉编译啥?

当然是rtmpdump啦,先来个make SYS=posix尝尝,立刻发现<openssl/ssl.h>找不到,搞定openssl之后,再来,会发现<zlib.h>找不到。如果先读了README就明白了,rtmpdump依赖openssl和zlib库,所以我得把rtmpdumpopensslzlib都交叉编译成动态库

zlib编译

下载源码,然后执行

CC=arm-linux-gnueabihf-gcc ./configure --prefix=<安装目录的绝对路径>
make
make install

openssl编译

下载源码,下载后要注意两点

  1. 选择版本,很可能由于API变动,最新版不和rtmpdump不能匹配,所以要预先知道版本,切换到那个版本的tag上再编译。一个确定版本的方法是,自己的上位机openssl版本或者Docker容器中的openssl版本,因为在前面的第一个步骤中,已经证明了系统中的openssl是可以和rtmpdump匹配的,用它准没错。
  2. 如果build了错误版本,再build rtmpdump时发现一些奇怪的问题,要换openssl版本的话,一定要先删除.gitignore之后再git clean -fd,因为有些ignore的文件是会影响编译的。

我在这吃了一些亏,最后发现了openssl API变动的修改,原本公开的结构体不再公开了,那么rtmpdump中使用这个结构体的地方就编不过了。
确定好版本后,编译命令如下:

AR="arm-linux-gnueabihf-ar" RANLIB=arm-linux-gnueabihf-ranlib CC=arm-linux-gnueabihf-gcc /usr/bin/perl ./Configure shared linux-armv4 --prefix=<安装目录的绝对路径>
make
make install

rtmpdump编译

下载源码,完整的make命令我先不给出来,因为要引用自己编的openssl和zlib库,makefile和make命令改得有点乱,一是目前处于demo阶段,二是预计很长时间内,我没有必要再交叉编译librtmp库,所以这里偷个懒,只是强调一下,认真读README,都能搞定的!

导入库到skill

这里看一下rtmp.go中开头部分对CGO的配置,再结合库文件和C文件的位置就明白了。
一个特别的地方是#include "../deps/include/rtmp_sample_api.c"这一句,这里直接弃用了.h文件,也只是偷个懒,因为在前面混乱的研究中,只引用头文件的话,好像会找不到.c文件,索性就直接引用.c文件了,也可能只是个误会,不过我最近感冒,暂时懒得研究了。

总结和计划


下一篇 HEXA娱乐开发日志技术点004——一步到位的推流

上一篇下一篇

猜你喜欢

热点阅读