Android5.0录屏方案

导语 本文主要是围绕android直播助手的功能做了一些研究,因为之前对Android多媒体相关的内容知之甚少,只有概念,于是查阅了相关资料并做以总结。

由于我对音视频相关知识零基础所以补充了一些相关知识

视音频编解码技术零基础学习方法

视音频数据处理入门:RGB、YUV像素数据处理

采集音频原始数据---->压缩编码----> 封装

采集视频原始数据---->压缩编码----> 封装

音视频编码

压缩编码就是对数据进行压缩以节省空间便于存储和传输。

视频压缩编码就是将视频帧的像素数据RGB或YUV等压缩成视频码流,编码一般对YUV格式进行,视频编码方案H.264,MPEG2,MPEG4等。

音频压缩编码就是将采样的音频采样数据PCM等压缩成音频码流。音频编码方案:AAC,WMA,MP3等。

编码是音视频技术中最重要的技术之一,也是难点,所幸的是,Android提供了MediaCodec用来方便开发者进行视音频的编解码,并且对于某种编码器还可以指定帧格式,尽管如此,我们也不能指定任意格式,因为这需要硬件的支持,可以通过API查询支持的帧格式。

通过createEncoderByType方法只需要传入mime即可创建对应的解码器,mime可以时下面的形式。

MediaCodec类的使用逻辑大致如下图所示,简单来说,一个编码器用于处理输入数据并对其进行编码处理后输出,它内部有一系列的输入和输出缓冲区,使用时,从编码器申请空的输入缓冲区,然后填充数据后发送给编码器处理,编码完成后编码器会将编码后的数据放入输出缓冲区,只需要从输出缓冲区取出编码后的数据后用于处理,最后将空间返还给编码器。

使用MediaCodec可以有三种方式

1. 使用Buffer数组的同步方式(API20以后deprecated)

2. 使用Buffer同步方式

3.异步方式

前两种方式基本类似,只是使用Buffer的同步方式性能更好。以第一种方式为例:

当要中指编码时只需要在最后一个有效数据Buffer中或者额外发送一个空的Buffer指定其Flag标志位为BUFFER_FLAG_END_OF_STREAM,然后调用queueInputBuffer发送给编码器即可。

除了直接使用ByteBuffer作为MediaCodec的输入输出还可以通过Surface作为数据的载体,具体的有两种:使用Input Surface和使用Output Surface。

以使用Input Surface为例,使用createInputSurface()方法创建一个Input Surface。

Requests a Surface to use as the input to an encoder, in place of input buffers.表明使用这个Surface来代替Buffer作为编码器的输入。

编码器将会自动的从Input Surface读取帧数据送往编码器。此时访问不到输入Buffer缓冲区,使用getInputBuffers等方法抛出异常。编码流结束时调用signalEndOfInputStream函数,该函数调用后,Surface就会停止向编码器提供数据流。

显然,这种方式在不需要获取音视频流的原始数据时是非常方便的。

音视频混合

封装一般指的是将进行过压缩编码的音频流和视频流进行合并,封装格式种类很多,例如MP4,MKV等等,它的作用就是将压缩编码的视频和音频按照一定的格式封装在一起。例如,将H.264编码的视频码流和AAC编码的音频码流合并成MP4格式的数据,

Android也提供了MediaMuxer支持将编码后的音视频码流合并成MP4格式的文件。

使用MediaMuxer的关键代码如下

Android5.0录制视频的方案

通过MediaProjectionManager进行录制屏幕。关键代码如下

在onActivityResult中判断是否获得录屏权限。然后执行下面操作。

createVirtualDisplay:Creates a VirtualDisplay to capture the contents of the screen

这个参数表示了录制的手机屏幕的内容要显示到哪个SurfaceView上,实际上表示了屏幕帧数据的走向,这个参数非常关键。

相关的几个类

ImageReader :The ImageReader class allows direct application access to image data rendered into a Surface

ImageReader类允许应用直接访问渲染到Surface上的image数据。使用MediaProjectionManager录制的屏幕内容可以直接渲染到一个Surface上,这个参数在createVirtualDisplay时传入,但是我们无法访问到渲染的内容。所以ImageReader类主要是用于使用Surface时访问不到原始视频数据流的情形。要想访问到每一帧的内容可以使用ImageReader类。

该类有一个函数getSurface获取一个Surface,通过这个函数获取一个Surface用来为ImageReader产生Images即视频流帧数据。

将这个Surface指定到录制屏幕时的Surface参数,就可以通过ImageReader读取到Surface上面渲染的每一帧的数据,通过acquireLatestImage()等方法可以获取一个Image对象。

Image:A single complete image buffer to use with a media source such as a MediaCodec or a CameraDevice.

也就是说Image类表示一个图片缓冲区,用来和MediaCodec一起使用。通过Image对象可以得到这一帧画面的像素数据,应该是RGB数据,转化为YUV格式的数据house,然后通过MediaCodec对其进行编码。

本地录屏方案

有了上面的准备知识,再来看直播助手的两个主要功能本地录屏和推流功能的实现逻辑容易多了。

本地录屏的逻辑:本地录屏不需要操作视频原始数据,因此使用Input Surface作为编码器的输入。

视频:MediaProjection通过createVirtualDisplay创建的VirtualDisplay传入的Surface是通过MediaCodec的createInputSurface方法返回的,表明编码器的输入其实来自于录制到的屏幕数据,于是只需要在MediaCodec的输出缓冲区中拿到编码后的ByteBuffer即可。

音频:录制程序获得音频原始数据PCM,传给MediaCodec编码,然后从MediaCodec的输出缓冲区拿到编码后的ByteBuffer即可。

最终通过合并模块将音视频混合。

推流的逻辑:推流SDK提供了一个编码器TVLiveSdk_LiveEncoder,它接受YUV420的视频数据格式和PCM编码的原始音频流。因此要获得视频的原始帧数据才行,可以通过ImageReader实现该功能。

视频:MediaProjection通过createVirtualDisplay创建的VirtualDisplay传入的Surface是通过ImageReader的getSurface方法返回的,表明录制的屏幕帧数据传递到ImageReader,于是通过ImageReader的相关API可以读取到录制的屏幕每一帧的数据,但这个数据时RGB格式的,转化为YUV格式后传到推流SDK即可。

音频:由于推流SDK需要的就是原始PCM编码的音频数据,因此录制到音频数据后直接调用推流SDK即可。

简单说就是重定向了屏幕录制的数据的方向,这个Surface提供的是什么,录制的视频数据就传到哪里。Surface提供的是本地某个SurfaceView控件,那么就会将屏幕内容显示到这个控件上,提供MediaCodec就是作为编码器的输入源最终获得编码后的数据,提供ImageReader就会作为ImageReader的数据源,最终获得了视频的原始数据流。

Android直播助手中录屏和推流具体框架设计

...

查看原文:http://qhyuang1992.com/index.php/2016/08/08/android5_0_lu_ping_fang_an/

时间: 2024-10-09 20:06:37

Android5.0录屏方案的相关文章

iOS 系统级别录屏方式调研

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px ".PingFang SC"; color: #454545 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px ".PingFang SC"; color: #454545; min-height: 21.0px } p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; fon

Android5.0免Root截屏,录屏

http://blog.csdn.net/wds1181977/article/details/52174840 MediaProjection介绍 MediaProjection可以用来捕捉屏幕,具体来说可以截取当前屏幕和录制屏幕视频.MediaProjection由MediaProjectionManager来管理和获取. 使用步骤 首先获取MediaProjectionManager,和其他的Manager一样通过 Context.getSystemService() 传入参数MEDIA_

ffmpeg,rtmpdump和nginx rtmp实现录屏,直播和录制

公司最近在做视频直播的项目,我这里分配到对直播的视频进行录制,录制的方式是通过rtmpdump对rtmp的视频流进行录制 前置的知识 ffmpeg: 用于实现把录屏工具发出的视频和音频流,转换成我们需要的格式,然后发送到rtmp中转服务器上. rtmpdump: 用于实现视频的录制,从rtmp的中转服务器接受到视频流,并把视频流保存成flv文件 nginx-rtmp-module: 用户rtmp中转服务,虽然他可以做很多功能,但是我这里只是使用了这一个 screen capture: windo

Android实现录屏直播(一)ScreenRecorder的简单分析

应项目需求瞄准了Bilibili的录屏直播功能,基本就仿着做一个吧.研究后发现Bilibili是使用的MediaProjection 与 VirtualDisplay结合实现的,需要 Android 5.0 Lollipop API 21以上的系统才能使用. 其实官方提供的android-ScreenCapture这个Sample中已经有了MediaRecorder的实现与使用方式,还有使用MediaRecorder实现的录制屏幕到本地文件的Demo,从中我们都能了解这些API的使用. 而如果需

Android录屏应用开发研究

1截屏接口 在Android5.0之前如果希望截图屏幕,是需要获取系统root权限的.但在Android5.0之后Android开放了新的接口android.media.projection,开发者使用该接口,第三方应用程序无需再获取系统root权限也可以直接进行屏幕截图操作了.查询其官方api可知,该接口主要用来"屏幕截图"操作和"音频录制"操作,这里只讨论用于屏幕截图的功能.由于使用了媒体的映射技术手段,故截取的屏幕并不是真正的设备屏幕,而是截取的通过映射出来的

Android5.0以上系统的移动网络开关

笔者近期遇到一个非常有意思的bug,贴出来和大家分享下. 那是一个温暖的早晨,阳光晒得人非常舒服.一封bug邮件像一片叶子飘到我的邮箱. 一番交流.笔者确认负责的Widget开关在Android5.0以上系统没有作用.相信非常多做过移动网络开关的朋友都知道.传统的方法是在ConnectivityManager中通过反射两个方法setMobileDataEnabled和getMobileDataEnabled来控制移动网络开和关的. /** * Gets the value of the sett

android 调用 screenrecord 实现录屏

首先要说明的是并未实现,本文讲一下自己的思路. adb 使用shell 命令 screenrecord 可录屏. 自己写了个app,通过Process p = Runtime.getRuntime().exec(cmd)的方式调用shell命令,报错: java.lang.SecurityException: Permission Denial: broadcast asks to run as user -2 but is calling from user 0 需要android.permi

Android免Root录屏

首先确保你的Android系统版本是5.0+ 1.安装一个叫"游视秀"的手机应用,你可以直接扫描下方的二维码下载安装 2.打开“游视秀” 3.点击右上角“录屏”的图标 4.选择一个录屏方式,手机推荐“竖屏录制”平板推荐“横屏录制” 5.选择好录屏方式后会出现桌面会出现悬浮框,点击可以开始录屏,再次点击可以结束录屏 6.啊咧,怎么桌面TM的没有悬浮框啊!!!别着急,在“其他应用管理”->“游视秀”->“权限管理”->“显示悬浮窗”->“允许”,然后再次打开“游视秀

4.录屏软件录屏端和接收端程序

 1  录屏端程序案例 T30DeskSend.pro SOURCES += \ main.cpp \ Sender.cpp HEADERS += \ Sender.h QT += network widgets Sender.h #ifndef SENDER_H #define SENDER_H   #include <QObject> #include <QUdpSocket>   class Sender : public QObject {     Q_OBJECT p