加载中 ...
首页 > 常见问题 正文

ShareREC for Android全系统手机录屏软件原理解析

2019-03-24 10:32:20 来源:沈阳软件公司 作者:沈阳软件开发

format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);

format.setInteger(MediaFormat.KEY_COLOR_FORMAT, pixelFormat);

format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);

format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 0);

encoder = MediaCodec.createEncoderByType("video/avc");

encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

encoder.start();

bufferInfo = new BufferInfo();

}

上面的代码演示了怎样初始化一个MediaCodec实例。需要注重的一点是,虽然我们设置了MediaCodec的帧率,但由于抓图时,图片数据不是匀速输入的,因此这个字段在此处形同虚设,可是又不能不填。上面的例子并不演示怎样获取硬件编码器支持的颜色花样类型,详细的实现方式可以搜索一下,不难找。

然后我们来实现上面抓图模块中遗留的offerFrame要领:

public void offerFrame(ByteBuffer frame, int rowStride) throws Throwable {

long framePreTimeUs = System.nanoTime() / 1000;

ByteBuffer[] inputBuffers = encoder.getInputBuffers();

int inputBufferIndex = encoder.dequeueInputBuffer(-1);

if (inputBufferIndex >= 0) {

ByteBuffer ibb = inputBuffers[inputBufferIndex];

ibb.position沈阳软件定制

<a href=http://www.hvihi.com target=_blank class=infotextkey>沈阳<a href=http://www.hvihi.com target=_blank class=infotextkey>软件开发</a></a>,<a href=http://www.hvihi.com target=_blank class=infotextkey>沈阳<a href=http://www.hvihi.com target=_blank class=infotextkey>软件公司</a></a>

(0);

YUVConverter.rgbaToI420(frame, ibb, 1280, 720, rowStride);

encoder.queueInputBuffer(inputBufferIndex, 0, ibb.limit(), framePreTimeUs, 0);

}

ByteBuffer[] outputBuffers = encoder.getOutputBuffers();

int outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, 0);

while (outputBufferIndex >= 0) {

ByteBuffer obb = outputBuffers[outputBufferIndex];

if (obb != null) {

int frameType = 0;

if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 1) {

frameType = 1;

} else if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 2) {

frameType = 2;

}

// 将编码好的H264帧输出给mp4合并模块

offerVideoTrack(obb, bufferInfo.size, bufferInfo.presentationTimeUs, frameType);

}

encoder.releaseOutputBuffer(outputBufferIndex, false);

outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, 0);

}

}

MediaCodec的输入输出都有缓存行列,我们要给它输入数据,需要先获取其输入缓存行列,然后在空闲的位置复制像素数据。由于我们抓取到的数据是RGBA花样,必须转为YUV花样才气别准确编码,这里ShareREC使用了libYUV,将RGBA转为I420。此外,并不是一输入图片就连忙会有输出h264帧,MediaCodec一样平常会缓存3-7张图片。

最后是视频合并模块,ShareREC使用了mp4v2来实现。实在在安卓平台同样自4.3以后系统自带了视频合并工具MediaMuxer。但这个工具似乎必须与MediaCodec一同使用,由于的用户要求ShareREC至少支持4.0以上的系统,故除了MediaCodec,实在我们还具备优化过的软件编码器。为了同时兼容两种编码器,我们放弃了MediaMuxer而接纳兼容性更好的mp4v2。

本文不先容mp4v2的使用,由于这凌驾java代码的领域(libYUV也是)。但它的事情原理很简朴,无非就是打开文件;在内存中生存视频轨道和音频轨道的信息;接着一帧帧写入视频或者音频数据,不用在意写入顺序,可以混在一起;在完成合并时,将内存内里的音视频信息组合为mp4形貌信息,追加到文件尾部,之后关闭文件。这个流程网上的文档许多,随便搜索就有了。但使用时有一些可能需要注重的,包罗多线程同步和图片出现时间的问题。

关于多线程同步,是指由于我们在现实录屏时,音频和视频是离开两条线程来编码的,但最后往mp4v2写入时,是写入统一个文件的,但由于mp4v2没有做好同步,因此若是写入音视频帧的时间,差池mp4v2自己做好同步锁,会泛起音视频写乱了的问题,导致最后视频无法播放。

至于图片出现的问题,请回首一下上面代码例子中的framePreTimeUs,这个是这一张图片被送入编码器的时间,合并视频时,需要将这个字段带给mp4v2。由于mp4v2默认是以为图片匀速输入的,以是它不剖析我们这个字段,只在意一最先设置的帧率。但由于抓图不是匀速的,因此若是只遵照牢固的帧率来显示,未来视频就会时快时慢,甚至声音图片差别步。因此在添加视频帧时,务须要设置出现的时间偏移。ShareREC以TimeScale为基准,会将framePreTimeUs凭据TimeScale做一次转换,然后在MP4WriteSample的时间,renderingOffset参数通报进去。

“沈阳软件公司”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与

我们联系删除或处理,客服QQ:55506560,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同

其观点或证实其内容的真实性。