Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)
一、前言
在之前已经详细介绍了Android中的一种视频数据源:Camera,不了解的同学可以点击进入:Android中Camera使用详解 ,在这篇文章中我们介绍了如何采集摄像头的每一帧数据,然后进行二次处理,例子中主要使用了对每一帧数据进行格式转化:NV21转化成ARGB格式,然后生成一张图片,然后添加水印效果。那么本文就来开始介绍如何将摄像头视频源数据的每一帧进行二次处理,然后推流到服务端。推流现在有很多种方式,但是更多的是基于FFMpeg,而现在各个云服务平台已经推出了直播SDK了,本文就来介绍一下金山云SDK,看看如何使用金山云SDK来进行推流,但是在使用之前,我们肯定得先了解他的原理,不过先来看一张效果图:

看到了吧,这里使用手机后置摄像头采集数据,然后推流到服务端,然后本地使用VLC进行观看,因为制作gif的关系,所以画面会有点模糊和卡顿。并不是是本生视频数据采集和推流造成的。
二、分析金山云SDK的功能
上面也看到效果,下面就来分析他的实现原理,因为他只有demo,和几个jar包,而文档写的也是很简单:
那么本文就采用反编译的方法来解读他的jar文件,他有三个jar包:
本文只看直播推流工具包ksylive3.0.jar,这里还可以看到了,他有一些so文件,有两个文件比较起眼,一个是libksystreamer.so他是底层的推流核心功能,我们使用IDA打开查看其native方法:
看到了,这里和Java层的FFmpegWrapper类交互,推流编码等核心功能就在这里实现了,而这里会看到他底层使用了现阶段开源的视频编解码工具类FFmpeg,以及添加水印等视频二次处理效果。
还有一个就是libksyyuv.so,这个主要是用于YUV数据格式转化,在之前的一篇文章中介绍了,获取到视频的每一帧数据之后是需要做格式转化的,但是这些转化工作放在Java层效率是个问题,一般都会放到native层做处理的。
三、金山云SDK的核心类
在讲解他的原理实现之前,先来看一下SDK的简单用法吧,用法很简单,
1、KSYStreamer类,进行编码推流。
2、KSYBgmPlayer类,是播放背景音乐流,可以在推流的过程中给视频添加背景音乐。
3、KSYMediaPlayer类,播放流类,这个类主要适用于画中画效果的。
4、KSYStreamerConfig.Builder类,设置推流的配置信息类。
第一个:KSYStreamerConfig.Builder类
KSYStreamerConfig.Builder builder = new KSYStreamerConfig.Builder();
1、setmUrl方法:设置推流地址
2、setFrameRate方法:设置推流帧率
3、setMaxAverageVideoBitrate方法:设置最高码率,即目标码率
4、setMinAverageVideoBitrate方法:设置最低码率
5、setInitAverageVideoBitrate方法:设置初始码率
6、setAudioBitrate方法:设置音频码率
7、setVideoResolution方法:设置推流视频的尺寸:360P/480P/540P/720P
8、setEncodeMethod方法:设置视频编码方式:硬编码/软编码
9、setSampleAudioRateInHz方法:设置音频的频率
10、setDefaultLandscape方法:设置推流视频方向:横屏/竖屏
11、setFrontCameraMirror方法:设置摄像头方向:前置/后置
第二个:KSYStreamer类
KSYStreamer mStreamer = new KSYStreamer(Context context);
mStreamer.setConfig(builder.build());
1、setDisplayPreview方法:设置预览界面,参数是GLSurfaceView
2、setOnStatusListener方法:设置推流状态回调,
3、setOnLogListener方法:设置日志回调
4、setOnAudioRawDataListener方法:设置音频原始数据回调
5、setOnPreviewFrameListener方法:设置每一帧数据回调
6、enableDebugLog方法:是否开启日志信息
7、setMuteAudio方法:设置静音
8、setEnableEarMirror方法:设置清耳模式
9、setBeautyFilter方法:设置滤镜
10、showWaterMarkLogo方法::设置水印logo图片效果
11、showWaterMarkTime方法:设置时间戳水印效果
12、hideWaterMarkLogo方法:隐藏水印logo图片
13、hideWaterMarkTime方法:隐藏水印时间戳
14、startStream方法:开始推流
15、stopStream方法:停止推流
16、setBgmPlayer方法:设置背景音乐
17、startMixMusic方法:设置背景音乐路径
18、stopMixMusic方法:停止背景音乐
19、getRtmpHostIP方法:获取推流ip地址
20、getUploadedKBytes方法:获取已经推流的字节
21、getEncodedFrames方法:获取编码帧率
22、getCurrentBitrate方法:获取当前的码率
23、setPipPlayer方法:设置画中画视频播放功能
23、setPipLocation方法:设置画中画视频位置
第三、KSYBgmPlayer类
KSYBgmPlayer mKsyBgmPlayer = KSYBgmPlayer.getInstance();
1、setOnBgmPlayerListener方法:设置推流背景音乐播放回调
2、setVolume方法:设置音乐音量
3、setMute方法:静音
第四、KSYMediaPlayer类
KSYMediaPlayermKsyMediaPlayer = new KSYMediaPlayer.Builder(Context context).build();
1、setOnCompletionListener方法:设置视频播放回调
2、setOnInfoListener方法:设置视频播放信息回调
3、setOnSeekCompleteListener方法:设置视频播放拖动回调
4、setScreenOnWhilePlaying方法:设置全屏播放
5、setLooping方法:设置循环播放
6、setVolume方法:设置播放音量
7、setPlayerMute方法:设置播放静音
四、分析金山云SDK中的核心方法
上面分析完了推流SDK中重要的四个类,下面就来详细分析几个重要的常用功能方法:
1、第一个方法:添加水印效果
看到了,这里添加了水印效果,水印效果有两种:一种是时间戳,一种是一张静态图片
我们在推流的过程中有时候为了推广自己或者其他效果,会在视频中添加水印功能,这个也是在推流的过程中比较重要的功能,下面来通过源码分析他是如何进行添加水印的:showWaterMarkLogo方法和showWaterMarkTime方法:
1》添加时间戳水印效果:showWaterMarkTime
这个方法有五个参数:
第一个参数:水印展示的X坐标
第二个参数:水印展示的Y坐标
第三个参数:时间戳其实是一张图片,水印图片缩放大小(L长度*参数)
第四个参数:时间戳水印颜色
第五个参数:水印透明度
接着看wmiShowTime方法:
这里正好是一个定时器,每隔1s执行一次:
这里看到了,原来是把时间戳文案变成一张图片,在之前的一篇文章中我们添加水印也是这么做的。然后在调用KSYStreamer中的setWaterMarkTime方法:
这个方法看到了,干了两件事,其实想想也是合理的,添加水印需要两个地方都需要添加:
第一个是预览界面GLSurfaceView中,这个是给主播看到的
第二个是视频编码推流中,这个是给用户拉流看到的
再看看w变量:
调用了a方法:
然后调用z方法:
到这里,核心方法就有了,这里开始计算坐标,图片尺寸等信息了,这里看到paramFloat3是按照指定的宽度乘以比例系数,然后在根据高宽比算出图片的高度,这些比例在初始化的使用设置的:
这里有这些比例的,也是我们之前看到KSYStreamerConfig.Builder类的方法setVideoResolution提供的设置360P/480P/540P/720P
计算好比例之后,开始调用e对象的setWmiTime方法了,再来看看e对象:
原来e对象是FFStreamer类型的,而我们在上面分析SDK功能包的时候,知道这个类是和底层ffmepg功能交互的:
而底层,也可以看到是直接使用ffmpeg进行编码,加水印效果的。
到这里就分析完了,SDK中添加时间戳水印的原理,他内部定义一个定时器每隔1s执行任务,然后把当前时间戳文案使用Canvas变成一张图片,接着通过传递进来的参数,这些参数都是比例系数,所以肯定是小于1的,计算坐标,图片大小,最后在调用FFStreamer类的setWmiTime方法,在底层使用ffmpeg进行添加水印效果。
上面分析完了,编码中的水印效果,下面再来看看预览画面中添加水印效果:
看看y类型:
看看这个类:
这个类中没有找到t方法,去父类a中也没有找到,a继承x,在x类中找到了t()方法:
看看y类型:
继承了KSYImageFilter类,这个类是用来做图片滤镜效果的基本类:
看到了,这里计算数据之后,再次调用a方法开始绘制:
果然到这里,开始调用OpenGL绘制图形了,也就是水印效果,以及图片滤镜效果等都是调用OpenGL技术来绘制的,然后在回显到界面中的,所以这里肯定得用GLSurfaceView预览界面了,支持OpenGL功能,还能进行图片二次处理再次回显到界面上,再来看看上面的最开始的a类,继承了Render类了,我们知道这个类是和GLSurfaceView息息相关的,渲染器类:
还记得在第一篇文章中,介绍基础知识大纲的时候,不了解的同学可以点击这里:基础知识大纲概要 有一张图片(图片不清晰,可以下载查看):
这里看到了Render类有几个回调方法:
1》onSurfaceCreated(GL10 gl, EGLConfig config)
2》onSurfaceChanged(GL10 gl, int width, int height)
3》onDrawFrame(GL10 gl)
GLSurfaceView->setRender->onSurfaceCreated回调方法中构造一个SurfaceTexture对象,然后设置到Camera预览中->SurfaceTexture中的回调方法onFrameAvailable来得知一帧的数据准备好了->requestRender通知Render来绘制数据->在Render的回调方法onDrawFrame中调用SurfaceTexture的updateTexImage方法获取一帧数据,然后开始使用GL来进行绘制。
GLSurfaceView和SurfaceView还有一个区别是,onDrawFrame在自己的单独线程中操作绘制的,而SurfaceView如果要绘制的话就在主线程中操作了。
好了到这里,我们分析完了预览中添加水印的效果,结合GLSurfaceView和Render使用OpenGL来进行图片的叠加绘制,以及后面涉及到的滤镜效果都是在这里进行处理的,当然还需要结合GPUImage类发挥效果,这个后悔会单独介绍OpenGL知识,如何处理图片技巧的,本文就不介绍了。
2》添加Logo图片水印效果:showWaterMarkLogo
这个方法的参数为:
第一个参数:图片路径
第二个参数:展示的X坐标
第三个参数:展示Y坐标
第四个参数:图片长度比
第五个参数:图片高度比
第六个参数:透明度
通过这些参数来看,和上面添加水印只多了一个图片高度比的比例系数,其他和水印效果一样。而且在分析上面添加水印的方法差不多,添加时间戳水印效果也是先把时间戳文案转化成一张图片,那么后续的流程就是添加一张图片水印效果了:
所以这里就在太多的介绍了。
2、第二个方法:摄像头每一帧数据处理
这里还有一个摄像头每一帧数据的回调,因为我们从SDK可以看到,摄像头Camera是在内部定义的,所以为了特定需求,需要把这个接口放出来,看看源码:
这里的ksyStreamer是h类型:
这里的w是d类型:
设置回调方法,d类实现了Camera.PreviewCallback接口
然后在回调方法中做处理,首先调用外部回调接口,把数据抛出去,然后在处理原始数据进行推流。
所以,SDK内部定义了一个Camera,自己实现了每一帧获取数据的回调接口,然后在回调方法中把数据抛出去给外面,同时在对每一帧数据进行二次处理,使用FFStreamer进行编码,加水印推流。
五、金山云SDK用法
到这里,我们就介绍完了金山云SDK推流的原理,因为底层涉及到的ffmpeg进行视频编码,加水印效果,后续一篇文章在介绍如何操作。下面就来简单看一个完整的例子:
1、构造KSYStreamerConfig.Builder类
2、构造KSYStreamer类
3、构造KSYMediaPlayer类
4、构造KSYBgmPlayer类
5、添加水印
6、处理Camear每一帧数据回调方法
六、技术概要
到这里我们就介绍了金山云SDK,如何进行推流操作,本文重要介绍了两种方法:
第一个是添加水印效果
添加水印有两个地方,一个是在推流之后的视频添加水印效果,这个是为了能够让用户拉流看到,起到宣传作用,这个主要是借助底层的ffmepg功能库,进行添加水印效果。还一个就是在预览中添加水印效果,这个是给主播看到的,主要利用GLSurfaceView的OpenGL技术进行添加水印,然后再把画面回显出来即可。
第二个是Camera每一帧数据回调
SDK内部定义了一个Camera摄像头,而这个没有暴露出来,但是有些需求我们想得到摄像头的每一帧数据,那么这时候可以通过KSYStreamer的回调方法来处理每一帧数据。
在用一张图来看看SDK的大体功能结构图:
项目下载地址:http://download.csdn.net/detail/jiangwei0910410003/9590380
七、总结
本文介绍完之后,可以进行正常的推流工作了,但是还有一些知识点没有介绍到,比如ffmpeg如何编码加水印效果,这个是后续的一篇文章中详细介绍的。但是到这里我们整个推流的流程就可以走通了,从服务器搭建到摄像头原理解析再到现在的推流实现,至少对于一个推流app来说,大体的原理是了解了。后面还会继续介绍编码推流的相关知识。
Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)的更多相关文章
- Android中直播视频技术探究之---桌面屏幕视频数据源采集功能分析
一.前言 之前介绍了Android直播视频中一种视频源数据采集:摄像头Camera视频数据采集分析 中介绍了利用Camera的回调机制,获取摄像头的每一帧数据,然后进行二次处理进行推流.现在我们在介绍 ...
- Android中直播视频技术探究之---摄像头Camera视频源数据采集解析
一.前言 在视频直播中一般都是两种视频数据源,一个是摄像头数据,一个是录制桌面数据,而一般来说美女妹子直播都是来自于摄像头数据,游戏直播都是录制桌面数据的,那么今天就来看看第一个数据源数据采集分析,A ...
- Android中Java反射技术的使用示例
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Metho ...
- Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)
原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...
- Android菜鸟的成长笔记(15)—— Android中的状态保存探究(下)
原文:Android菜鸟的成长笔记(15)-- Android中的状态保存探究(下) 在上一篇中我们简单了解关于Android中状态保存的过程和原理,这一篇中我们来看一下在系统配置改变的情况下保存数据 ...
- javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG、javaCV-openCV)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- Android中直播视频技术探究之---视频直播服务端环境搭建(Nginx+RTMP)
一.前言 前面介绍了Android中视频直播中的一个重要类ByteBuffer,不了解的同学可以 点击查看 到这里开始,我们开始动手开发了,因为我们后续肯定是需要直播视频功能,然后把视频推流到服务端, ...
- Android中直播视频技术探究之---基础知识大纲介绍
一.前言 最近各种视频直播app到处都是,各种霸屏,当然我们也是需要体验的,关于视频直播的软件这里就不介绍了,在不是技术的人来看,直播是一种潮流,是一种娱乐方式,但是作为一个高技术的,我们除了看看,更 ...
- 6、Android中的NFC技术
Android对NFC技术的支持 Android2.3.1(API Level = 9)开始支持NFC技术,但Android2.x和Android3.x对NFC的支持非常有限.而从Android4.0 ...
随机推荐
- Where does beauty come from?
One more question, rational beauty should come from a dedicated brain and mind. Should there be more ...
- Python高频技巧总结[基础篇]
0. 概要说明 python应用最多的场景还是web快速开发.爬虫.自动化运维:简单网站.自动Fuzz脚本.收发邮件脚本.简单验证码识别脚本. 爬虫在开发过程中也有很多复用的过程,这里总结一下,以后也 ...
- C#:IO
1. File和Directory类 这两个类属于静态类,经常用到的比如File.Exists(string path), Directory.Exists(string path), Directo ...
- paper 27 :图像/视觉显著性检测技术发展情况梳理(Saliency Detection、Visual Attention)
1. 早期C. Koch与S. Ullman的研究工作. 他们提出了非常有影响力的生物启发模型. C. Koch and S. Ullman . Shifts in selective visual ...
- 注意!你的Thread.Abort方法真的让线程停止了吗?
大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...
- 集成Spring事物管理
什么是事物 事物是访问数据库的一个操作序列,数据库应用系统通过事物集来完成对数据库的存取.事物的正确执行使得数据库从一种状态转换为另一种状态. 事物必须服从ISO/IEC所制定的ACID原则.ACID ...
- c#中 ==与equals有什么区别【转】
转至http://www.zybang.com/question/2263895f201ffec6c68b6c304ac4cd61.html 对于值类型.引用类型来说比较过程怎样的?using Sys ...
- Spark实战1:shell+独立App使用总结
Spark改进了Hadoop执行非流式算法的需要多次IO的缺陷,Spark的所有操作都是基于RDD弹性分布式数据集这种数据结构的,对RDD的操作主要的操作包括transform和action两种操作. ...
- 使用javascript判断浏览器对css3的支持情况【译】
Quick Tip: Detect CSS3 Support in Browsers with JavaScript Jeffrey Way on Nov 15th 2010 步骤 1 首先我们要确 ...
- iOS 学习笔记 一 (2015.02.05)
一:Xcode6输入框设置为 keyboard type设置为Number Pad弹不出键盘的解决办法 问题:Can't find keyplane that supports type 4 fo ...