Ragnarok Note

谈谈关于Android视频编码的那些坑

Android的视频相关的开发,大概一直是整个Android生态,以及Android API中,最为分裂以及兼容性问题最为突出的一部分。摄像头,以及视频编码相关的API,Google一直对这方面的控制力非常差,导致不同厂商对这两个API的实现有不少差异,而且从API的设计来看,一直以来优化也相当有限,甚至有人认为这是“Android上最难用的API之一”

以微信为例,我们录制一个540p的mp4文件,对于Android来说,大体上是遵循这么一个流程:



大体上就是从摄像头输出的YUV帧经过预处理之后,送入编码器,获得编码好的h264视频流。

上面只是针对视频流的编码,另外还需要对音频流单独录制,最后再将视频流和音频流进行合成出最终视频。

这篇文章主要将会对视频流的编码中两个常见问题进行分析:

  1. 视频编码器的选择(硬编 or 软编)?
  2. 如何对摄像头输出的YUV帧进行快速预处理(镜像,缩放,旋转)?

视频编码器的选择

对于录制视频的需求,不少app都需要对每一帧数据进行单独处理,因此很少会直接用到MediaRecorder来直接录取视频,一般来说,会有这么两个选择

  • MediaCodec
  • FFMpeg+x264/openh264

我们来逐个解析一下


MediaCodec

MediaCodec是API 16之后Google推出的用于音视频编解码的一套偏底层的API,可以直接利用硬件加速进行视频的编解码。调用的时候需要先初始化MediaCodec作为视频的编码器 ...

如何获取Android系统中申请对象的信息

最近一直在做有关内存方面的优化工作,在做优化的过程,除了关注内存的申请量以及GC的情况之外,我们经常需要想方法找出是那些对象占用了大量内存,以及他们是如何导致GC的,这意味着我们需要获取对象申请的信息(大小,类型,堆栈等),我们这篇文章来介绍下几种获取对象申请信息的方法

Allocation Tracker

Allocation Tracker是android studio自带的一个功能,我们可以在MemoryMonitor中打开使用:

如上图,点击红框按钮,然后操作app,开始allocation tracking,当认为需要结束的时候,再次点击按钮,稍等片刻,即可以在android studio中dump出在 这段时间新申请 对象的信息:

这种使用方式相当直观,可以看到申请对象大小,数量,还有堆栈等,通过这些信息,我们可以作为我们接下来进行内存优化的参考

但是,对于这种获取申请对象信息的方法,会存在几个问题:

  1. 获取的信息过于分散,中间夹杂着不少其他的信息,不完全是app申请的,可能需要进行不少查找才能定位到具体的问题
  2. 跟TraceView一样,无法做到自动化分析,每次都需要开发者手工开始/结束,对于某些问题的分析可能会造成不便,而且对于批量分析来说也比较困难
  3. 虽然在allocation ...

Tricking Android MemoryFile

之前在做一个内存优化的时候,使用到了MemoryFile,由此发现了MemoryFile的一些特性以及一个非常trickly的使用方法,因此在这里记录一下

What is it

MemoryFile是android在最开始就引入的一套框架,其内部实际上是封装了android特有的内存共享机制Ashmem匿名共享内存,简单来说,Ashmem在Android内核中是被注册成一个特殊的字符设备,Ashmem驱动通过在内核的一个自定义slab缓冲区中初始化一段内存区域,然后通过mmap把申请的内存映射到用户的进程空间中(通过tmpfs),这样子就可以在用户进程中使用这里申请的内存了,另外,Ashmem的一个特性就是可以在系统内存不足的时候,回收掉被标记为"unpin"的内存,这个后面会讲到,另外,MemoryFile也可以通过Binder跨进程调用来让两个进程共享一段内存区域。由于整个申请内存的过程并不再Java层上,可以很明显的看出使用MemoryFile申请的内存实际上是并不会占用Java堆内存的。

MemoryFile暴露出来的用户接口可以说跟他的名字一样,基本上跟我们平时的文件的读写基本一致,也可以使用InputStream和OutputStream来对其进行读写等操作:

MemoryFile memoryFile = new MemoryFile(null, inputStream.available());
memoryFile.allowPurging(false);
OutputStream outputStream = memoryFile.getOutputStream();
outputStream ...

RxCamera, 一个RxJava风格的android camera封装

事实上这个库写了已经有一段时间了,由于最近工作上比较忙,所以现在才写一篇文章来总结

What's this

正如标题所说,RxCamera是一个基于RxJava而构建的一套android.hardware.camera封装的库。最初写这个库的目的是为了熟悉RxJava,并且而且也看到虽然在android开发已经有不少基于RxJava的库,但是关于音视频相关却少之又少,于是就动手实现了一下。目前这个库还处于非常早期的状态,API比较简陋,并且关于camera的设置还有很多没有做

How to use

RxCamera的README中已经有关于这个库使用的比较详细介绍了,我在这里再说明一下:

加入依赖

首先你需要在项目中加入对RxCamera项目的依赖:

repositories {
        jcenter()
}
dependencies {
    compile 'com.ragnarok.rxcamera:lib:0.0.1'
}

基本的使用

  • 配置camera的参数

android的原生camera api提供了不少的选项来配置打开摄像头时候的参数,例如预览的帧率,预览的分辨率,自动对焦等,在RxCamera中主要是通过一个RxCameraConfig对象来管理这些对象 ...

Project Lacie Initiate

Motivation

我记得去年在组内介绍Annotation和Annotation Process Tool的时候,当时不少小伙伴都认为这个是一个非常棒的工具,用来做代码生成非常合适,但是也存在不少问题,主要的争论点在于,对于大型的项目,其代码量非常大,无论是在IDE内或者在命令行中进行编译,即使只是普通的增量编译,打包,也需要耗上非常长的时间。而普通的APT则需要每次都先拉起一次编译过程,因为实际上整个Annotation Processing是Java编译中的一个步骤,另外如果在Annotation Processing的过程中另外产生了新的代码的话,还需要重新编译生成的代码,这会导致整个编译过程变得更加漫长,如下图,为Java源码编译的过程,摘自OpenJDK官网。

于是,后续我就逐渐开始想方法实现有一个类似Annotation Processor的API的工具,但并不需要拉起Javac进行编译,只需要输入源码即可,然后由开发者自行定义生成代码的规则,即可完成APT的功能。

Research

要实现这样的一个工具,最先迫切的就是需要一个语法解析器,这样子才能从源码中提取出所需要的信息。当时候的想法是自己来实现Tokenizer和Parser(真庆幸大学的时候教编译原理的灭绝大法师的训练,我还记得怎么写哈哈哈哈),但很快我就找到了JavaCC这个工具,这玩意可以说是Java编译器的生成工具,实际上Javac的前端也是这个东西来生成的。但是JavaCC生成的代码非常乱并且其API并不是很好用。当时候我想当JDK中一定是有单独Javac前端独立出来的,于是我又找到了JDK中的tools ...