肥客泉

肥客联邦
自由无止境.自由的引领.自由的联盟.自由让你我腾飞!为了同一目标而奋斗,为了同一信念而聚一堂,为了网络事业的明天而烈火青春.
肥客因您的支持而成长,因您的关注而精彩闪亮!

肥客是专业的网络应用服务商。我们的团队凭借扎实的技术与优质的服务为企业、公司、政府等部门量身定制软件与网站的网络应用和用户体验。有非凡志向,才有非凡成就。

直播技术(从服务端到客户端)

环境部署

2015年开始直播变得越来越流行,很多的直播平台也应运而生,直播是一个很有技术的项目,从服务端到客户端到web等等。我们将写一序列的博客来阐述直播中的技术,这包括服务端技术和客户端技术。包括最简单的服务端环境部署、客户端编译、采集、推流、拉流、美化特效、水印、延时优化、音视频同步、p2p等等。当然还可能包括一些信号处理的知识,比如滤波,傅里叶变换(FFT)。从本文开始我们将从环境部署开始,这包括两方面的环境部署即服务端和客户端。

1、服务端

在部署服务端环境其实包含很多东西的,最常用的web服务nginx,数据库Mysql、Nosql,api开发最多的三种选择:

  • java环境,需要jdk,tomcat/jboss

  • php环境,需要安装php,odp

  • lua环境,需要安装lua、luajit

考虑使用缓存技术,则主要包含redis和memcached。如果还要其他的日志统计(kafka什么的)需求则还需要更多的环境,我们这里不讨论,只是简单叙述 
对于直播而言,我们需要部署两个东西,nginx(含nginx-rtmp-module)、ffmpeg,这两个是直播服务端的关键,下面我们简单讲述如何安装nginx(含nginx-rtmp-module)和ffmpeg以及如何配置nginx.conf。 
首选我们来安装nginx和ffmpeg。 
nginx下载地址:

ffmpeg下载地址:

nginx-rtmp-module下载地址:https://github.com/arut/nginx-rtmp-module

其中nginx-rtmp-module是Google工程师开发的,在gitHub上有很多分支,根据自己的需求选择分支,我们这里选择master分支。 
首选安装nginx和nginx-rtmp-module,在安装nginx的时候,会需要openssl、pcre、zlib这几个库。cd 进入nginx解压目录

./configure --prefix=/usr/local/nginx --with-pcre=/path/to/your/pcre/--with-zlib=/path/to/your/zlib/--with-openssl=/path/to/your/openssl/--add-module=/path/to/your/nginx-rtmp-module
  • 1

其中–prefix是指安装后nginx的目录,–with-pcre需要pcre库,/path/to/your/pcre/是指的pcre源代码路径,其他的同理。–add-module=/path/to/your/nginx-rtmp-module 这个是添加nginx-rtmp-module,将nginx-rtmp-module嵌入到nginx中,这样是nginx的强大之处-插件功能。 
安装完成之后,在浏览器中输入localhost:8080则会出现如下画面: 
 
那么接下安装ffmpeg,解压ffmpeg并cd进去目录,执以下语句

./configure--enable-shared--prefix=/usr/local/ffmpeg
  • 1

网上有很多安装ffmpeg的教程,这里不详细介绍。 
如果安装成功后会,在终端中输入 ffmpeg -version会显示相关的信息。如果没有则可能没有安装成功。 
安装完成之后我们来看看nginx.conf的配置信息。

worker_processes  2;error_log  logs/error.log;error_log  logs/error.log  notice;error_log  logs/error.log  info;pid        logs/nginx.pid;events {    worker_connections  128;}http {    include       mime.types;    default_type  application/octet-stream;    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '                      '$status $body_bytes_sent "$http_referer" '                      '"$http_user_agent""$http_x_forwarded_for"';    access_log  logs/access.log  main;    sendfile        on;    keepalive_timeout  65;    server_names_hash_bucket_size 128;    client_header_buffer_size 32k;    large_client_header_buffers 432k;    client_max_body_size 300m;    tcp_nopush     on;    tcp_nodelay on;    server_tokens off;    gzip  on;    gzip_min_length  1k;    gzip_buffers     416k;    gzip_http_version 1.1;    gzip_comp_level 2;    gzip_types     text/plain application/x-javascript text/css application/xml;    gzip_vary on;    include vhosts/*.conf;}#切换自动推送(多 worker 直播流)模式。默认为 off#rtmp_auto_push on;#当 worker 被干掉时设置自动推送连接超时时间。默认为 100 毫秒#rtmp_auto_push_reconnect 1s;#设置用于流推送的 UNIX 域套接字目录。默认为 /tmp#rtmp_socket_dir /var/sock;rtmp {    server {      listen 1935;      #点播配置#application vod {#    play /opt/media/nginxrtmp/flv;#}#直播流配置application live {          live on;          #allow publish 127.0.0.1;#deny publish all;#allow play all;      }      #access_log logs/rtmp_access.log new;      access_log logs/rtmp_access.log;      access_log on;    #HLS协议支持#application hls {#live on;#hls on;#hls_path /tmp/app;#hls_fragment 5s;#}#application hls{#   live on;#   hls on;#   hls_path /usr/local/Cellar/nginx-full/1.10.1/html/app;#   hls_fragment 1s;#}  }}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

其中http相关的标签我这边不做详细的介绍,这个等一会用到api的时候详细介绍。下面我们看看rtmp标签,rtmp标签的意思是声明一个 RTMP 实例。在rtmp标签下面有server,它的意思是给 NGINX 添加一个监听端口以接收 RTMP 连接 
application标签是创建一个 RTMP 应用。application 名的模式并不类似于 http location。这个以后再详细阐述。在这个配置中,我们只是配置了一个live,同时打开了log,其他的相关的参数我们现在不说明,等以后会专门介绍rtmp的配置文章介绍。 
配置好了这个之后就是通过ffmpeg向server推流。ffmpeg的指令为:

ffmpeg -re-i /Users/jarlene/Downloads/test.flv -c copy -f flv rtmp://localhost:1935/live/steam
  • 1

这里不详细介绍ffmpeg指令,因为接下来我们会有一篇专门的文章接受ffmpeg。 
这个时候就可以用vlc播放器拉流看直播了。 

到这里我们就简单讲述了nginx和ffmpeg安装和nginx.conf配置信息以及推流和观看

2、客户端

相对于服务端环境部署来说客户端环境部署复杂很多,尤其是在android平台,编译导入android studio等等过程都很复杂,ios平台还好,但是由于我个人喜爱,在此也会加上Windows客户端相配置,只不过windows会一段时间后更新。对于客户端主要就是编译ffmpeg。下面这段脚本是编译ffmpeg到android和ios平台的。

#/bin/bashAndroidDest=`pwd`/FFmpeg-Android && rm -rf $AndroidDestIOSDest=`pwd`/FFmpeg-iOS && rm -rf $IOSDestSOURCE="ffmpeg-3.1.1"THIN="$IOSDest/thin"SCRATCH="$IOSDest/scratch"echo$THINecho$SCRATCH# if [ -d ffmpeg ]; then#   cd ffmpeg# else#   git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg#   cd ffmpeg# fiif [ ! -r $SOURCE ]    thenecho'FFmpeg source not found. Trying to download...'        curl http://www.ffmpeg.org/releases/$SOURCE.tar.bz2 | tar xj \            || exit1fifunction android() {    cd$SOURCE# sed -i -e 's|SLIBNAME_WITH_MAJOR='\$(SLIBNAME).\$(LIBMAJOR)'|SLIBNAME_WITH_MAJOR='\$(SLIBPREF)\$(FULLNAME)-\$(LIBMAJOR)\$(SLIBSUF)'|' configure# sed -i -e 's|LIB_INSTALL_EXTRA_CMD='\$\$(RANLIB)"\$(LIBDIR)/\$(LIBNAME)"'|LIB_INSTALL_EXTRA_CMD='\$\$(RANLIB)"\$(LIBDIR)/\$(LIBNAME)"'|' configure# sed -i -e 's|SLIB_INSTALL_LINKS='\$(SLIBNAME_WITH_MAJOR)\$(SLIBNAME)'|SLIB_INSTALL_LINKS='\$(SLIBNAME)'|' configure    NDK=/Users/jarlene/Library/Android/sdk/ndk-bundle    SYSROOT=$NDK/platforms/android-19/arch-arm    WORKING_DIR=`pwd`    # Expand the prebuilt/* path into the correct one    TOOLCHAIN=`echo$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64`    export PATH=$TOOLCHAIN/bin:$PATH# Don't build any neon version for nowfor version in armv5te armv7a; do        DEST=$AndroidDest        FLAGS="--target-os=linux --cross-prefix=arm-linux-androideabi- --arch=arm"        FLAGS="$FLAGS --sysroot=$SYSROOT"#FLAGS="$FLAGS --soname-prefix=/data/data/net.sourceforge.servestream/lib/"        FLAGS="$FLAGS --enable-shared --disable-symver"# FLAGS="$FLAGS --enable-small --optimization-flags=-O2"#FLAGS="$FLAGS --extra-cflags=-I$NDK/platforms/android-23/arch-arm/usr/include/ffmpeg --extra-ldflags=-L$NDK/platforms/android-23/arch-arm/usr/lib"        FLAGS="$FLAGS --disable-doc"# FLAGS="$FLAGS --enable-gpl"        FLAGS="$FLAGS --disable-ffmpeg"        FLAGS="$FLAGS --disable-ffplay"        FLAGS="$FLAGS --disable-ffprobe"        FLAGS="$FLAGS --disable-ffserver"# FLAGS="$FLAGS --enable-avdevice"# FLAGS="$FLAGS --enable-swresample"# FLAGS="$FLAGS --enable-swscale"        FLAGS="$FLAGS --enable-postproc"# FLAGS="$FLAGS --enable-avfilter"# FLAGS="$FLAGS --disable-everything"# FLAGS="$FLAGS --enable-muxer=mov --enable-muxer=ipod --enable-muxer=psp --enable-muxer=mp4 --enable-muxer=avi "# FLAGS="$FLAGS --enable-demuxer=acc,flac,h263,h264,m4v,matroska,mp3,mpegvideo,ogg,pcm_alaw,pcm_f32be,pcm_f32le,pcm_f64be,pcm_f64le,pcm_mulaw,pcm_s16be,pcm_s16le,pcm_s24be"# FLAGS="$FLAGS --enable-demuxer=pcm_s24le,pcm_s32be,pcm_s32le,pcm_s8,pcm_u16be,pcm_u16le,pcm_u24be,pcm_u24le,pcm_u32be,pcm_u32le,pcm_u8,rtp,rtsp,sdp,wav"# FLAGS="$FLAGS --enable-parser=aac,aac_latm,flac,h263,h264,mpeg4video,mpegaudio,mpegvideo,vorbis,vp8"# FLAGS="$FLAGS --enable-decoder=aac,aac_latm,mp3,wmalossless,wmapro,wmav1,wmav2,wmavoice,mpeg4,h264"# FLAGS="$FLAGS --enable-protocol=http,https,mmsh,mmst,rtmp,hls,file,rtsp"        FLAGS="$FLAGS --disable-debug"case"$version"in            neon)                EXTRA_CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=neon"                EXTRA_LDFLAGS="-Wl,--fix-cortex-a8"# Runtime choosing neon vs non-neon requires# renamed files                ABI="armeabi-v7a"                ;;            armv7a)                EXTRA_CFLAGS="-march=armv7-a -mfloat-abi=softfp"                EXTRA_LDFLAGS=""                ABI="armeabi-v7a"                ;;            *)                EXTRA_CFLAGS=""                EXTRA_LDFLAGS=""                ABI="armeabi"                ;;        esac        DEST="$DEST/$ABI"        FLAGS="$FLAGS --prefix=$DEST"        mkdir -p $DESTecho$FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" > $DEST/info.txt        ./configure $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" | tee $DEST/configuration.txt        [ $PIPESTATUS == 0 ] || exit1        make clean        make -j4 || exit1        make install || exit1donecd ..}function ios(){    mkdir -p $IOSDest    CONFIGURE_FLAGS="--enable-cross-compile --disable-debug --disable-programs \    --disable-doc --enable-pic"if [ "$X264" ]        then        CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-gpl --enable-libx264"fiif [ "$FDK_AAC" ]        then        CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-libfdk-aac"fi# avresample#CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-avresample"# arm64 armv7 x86_64 i386    ARCHS="arm64 armv7 x86_64"    COMPILE="y"    LIPO="y"    DEPLOYMENT_TARGET="6.0"if [ "$*" ]        thenif [ "$*" = "lipo" ]            then# skip compile            COMPILE=        else            ARCHS="$*"if [ $#-eq1 ]                then# skip lipo                LIPO=            fififiif [ "$COMPILE" ]        thenif [ ! `which yasm` ]            thenecho'Yasm not found'if [ ! `which brew` ]                thenecho'Homebrew not found. Trying to install...'                ruby -e"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" \                || exit1fiecho'Trying to install Yasm...'            brew install yasm || exit1fiif [ ! `which gas-preprocessor.pl` ]            thenecho'gas-preprocessor.pl not found. Trying to install...'            (curl -L https://github.com/libav/gas-preprocessor/raw/master/gas-preprocessor.pl \                -o /usr/local/bin/gas-preprocessor.pl \                && chmod +x /usr/local/bin/gas-preprocessor.pl) \            || exit1fi# if [ ! -r $SOURCE ]# then#   echo 'FFmpeg source not found. Trying to download...'#   curl http://www.ffmpeg.org/releases/$SOURCE.tar.bz2 | tar xj \#       || exit 1# ficd$SOURCE        configHeaderFile="$SOURCE/config.h"        make clean        if [ ! -f"$configHeaderFile" ]; then# echo $configHeaderFile            rm config.h        ficd ..        CWD=`pwd`        echo$CWDfor ARCH in$ARCHSdoecho"building $ARCH..."            mkdir -p "$SCRATCH/$ARCH"cd"$SCRATCH/$ARCH"            CFLAGS="-arch $ARCH"if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]                then                PLATFORM="iPhoneSimulator"                CFLAGS="$CFLAGS -mios-simulator-version-min=$DEPLOYMENT_TARGET"else                PLATFORM="iPhoneOS"                CFLAGS="$CFLAGS -mios-version-min=$DEPLOYMENT_TARGET -fembed-bitcode"if [ "$ARCH" = "arm64" ]                    then                    EXPORT="GASPP_FIX_XCODE5=1"fifi            XCRUN_SDK=`echo$PLATFORM | tr '[:upper:]''[:lower:]'`            CC="xcrun -sdk $XCRUN_SDK clang"            CXXFLAGS="$CFLAGS"            LDFLAGS="$CFLAGS"if [ "$X264" ]                then                CFLAGS="$CFLAGS -I$X264/include"                LDFLAGS="$LDFLAGS -L$X264/lib"fiif [ "$FDK_AAC" ]                then                CFLAGS="$CFLAGS -I$FDK_AAC/include"                LDFLAGS="$LDFLAGS -L$FDK_AAC/lib"fi            TMPDIR=${TMPDIR/%\/}$CWD/$SOURCE/configure \            --target-os=darwin \            --arch=$ARCH \            --cc="$CC" \            $CONFIGURE_FLAGS \            --extra-cflags="$CFLAGS" \            --extra-ldflags="$LDFLAGS" \            --prefix="$THIN/$ARCH" \            || exit1            make -j3 install $EXPORT || exit1cd$CWDdonefiif [ "$LIPO" ]        thenecho"building fat binaries..."        mkdir -p $IOSDest/lib        set - $ARCHS        CWD=`pwd`        cd$THIN/$1/lib        for LIB in *.a        docd$CWDecho lipo -create `find $THIN -name $LIB` -output $IOSDest/lib/$LIB1>&2            lipo -create `find $THIN -name $LIB` -output $IOSDest/lib/$LIB || exit1donecd$CWD        cp -rf $THIN/$1/include $IOSDestfiecho Done}iosandroid
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 91

  • 92

  • 93

  • 94

  • 95

  • 96

  • 97

  • 98

  • 99

  • 100

  • 101

  • 102

  • 103

  • 104

  • 105

  • 106

  • 107

  • 108

  • 109

  • 110

  • 111

  • 112

  • 113

  • 114

  • 115

  • 116

  • 117

  • 118

  • 119

  • 120

  • 121

  • 122

  • 123

  • 124

  • 125

  • 126

  • 127

  • 128

  • 129

  • 130

  • 131

  • 132

  • 133

  • 134

  • 135

  • 136

  • 137

  • 138

  • 139

  • 140

  • 141

  • 142

  • 143

  • 144

  • 145

  • 146

  • 147

  • 148

  • 149

  • 150

  • 151

  • 152

  • 153

  • 154

  • 155

  • 156

  • 157

  • 158

  • 159

  • 160

  • 161

  • 162

  • 163

  • 164

  • 165

  • 166

  • 167

  • 168

  • 169

  • 170

  • 171

  • 172

  • 173

  • 174

  • 175

  • 176

  • 177

  • 178

  • 179

  • 180

  • 181

  • 182

  • 183

  • 184

  • 185

  • 186

  • 187

  • 188

  • 189

  • 190

  • 191

  • 192

  • 193

  • 194

  • 195

  • 196

  • 197

  • 198

  • 199

  • 200

  • 201

  • 202

  • 203

  • 204

  • 205

  • 206

  • 207

  • 208

  • 209

  • 210

  • 211

  • 212

  • 213

  • 214

  • 215

  • 216

  • 217

  • 218

  • 219

  • 220

  • 221

  • 222

  • 223

  • 224

  • 225

  • 226

  • 227

  • 228

  • 229

  • 230

  • 231

  • 232

  • 233

  • 234

  • 235

  • 236

  • 237

  • 238

  • 239

  • 240

  • 241

  • 242

  • 243

  • 244

  • 245

  • 246

  • 247

  • 248

  • 249

  • 250

  • 251

  • 252

  • 253

  • 254

这段脚本可以编译出android和ios的两个平台的配置,当然根据你的需求在configure中配置需要的东西,否则ffmpeg编译出来之后还是很大。 
顺便解释一下:SOURCE=”ffmpeg-3.1.1”这个是release ffmpeg的版本,通过curl去下载,然后会在脚本的目录出下载并解压生成一个ffmpeg-3.1.1目录。 
这个脚本有两个事情需要说明:

  1. 如果不修改configure文件,android平台编译出来的so文件名有问题,会在.so后面带上版本号,这个在android中识别不了的。

  2. 如果修改了configure文件,在编译ios平台的时候会遇到一个no file or directory的问题。导致完成后install的时候失败。 
    建议: 
    先编译ios平台,然后在修改configure,具体修改如下:

将下面的内容

SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
  • 1

  • 2

  • 3

  • 4

修改为:

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'SLIB_INSTALL_LINKS='$(SLIBNAME)'
  • 1

  • 2

  • 3

  • 4

当然如果你是shell脚本高手,在编译android的时候通过sed命令将上面提到内容进行修改也是可以的。 
编译完成之后将编译出来的lib(so文件或者.a文件)和include(头文件)拷贝到你android studio中和xcode中。android具体如图: 
 
gradle脚本配置:

ndk {            moduleName "FFPlayer"            stl "stlport_static"            cFlags "-std=gnu++11 -DGL_GLEXT_PROTOTYPES"            abiFilters "armeabi", "armeabi-v7a"String basePath = new File("./").canonicalPath + "/ffplaylib/src/main/jniLibs/armeabi/"String libavcodec =  basePath + "libavcodec-54.so"String libavdevice = basePath + "libavdevice-54.so"String libavfilter = basePath + "libavfilter-3.so"String libavformat = basePath + "libavformat-54.so"String libavutil = basePath + "libavutil-51.so"String libswresample = basePath + "libswresample-0.so"String libswscale = basePath + "libswscale-2.so"            ldLibs "log","GLESv2","dl", "GLESv1_CM","GLESv2", "android",libavcodec, libavdevice, libavfilter, libavformat, libavutil,libswresample,libswscale        }    sourceSets {        main {            jni.srcDirs  "src/main/jni", "src/main/jni/include","src/main/jni/include/libavcodec","src/main/jni/include/libavdevice","src/main/jni/include/libavfilter",                    "src/main/jni/include/libavformat","src/main/jni/include/libavutil","src/main/jni/include/libswresample",                    "src/main/jni/include/libswscale", "src/main/jni/SDL", "src/main/jni/SDL/include"            jniLibs.srcDirs "src/main/jinLibs"        }    }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

第一个是ndk配置,配置moduleName等,同时指定本地依赖libavcodec等so库。 
sourceSets主要是制定include头文件路径。 
这样就能移植进入android studio中,而不是在eclipse中。

而对ios想到简单一些。具体如图: 
 
因为这边是用swift写的应用,所以还需要指定Swift compiler和Search path

Search path: 

Swift compiler

Swift compiler的头文件如下: 

做完这些之后就可以在代码中直接引用了。 

在android中是通过jni调用Native代码的,这里我就详细介绍了。

3、总结

本文讲述从服务端到客户基本环境部署,其中包括一些关键的东西点。下一篇直播技术的文章将阐述android和ios如何播放视频代码。再之后将会详细介绍ffmpeg以及其基本架构。之后会叙述服务端nginx.conf基本配置以及客户端采集推流相关的东西。



原文:http://blog.csdn.net/xwl198937/article/details/52371726

评论

© 肥客泉 | Powered by LOFTER