本篇是JPEG解码系列的第二篇——读数据的底层依赖库。

  本人所开发的MiniJpegDecoder项目,主要分为两层,一层是底层依赖库,另外一层是包含jpeg解码逻辑的应用层。

其实,分三层的话结构更为合理:底层库+解码库+应用层。但由于目前没时间维护这个库,等什么时候空闲了再优化一下结构吧。

  今天介绍的主要是两层结构的底层库——libcodec_utils.so。

1. 源码组成

  源码树结构如下:

utils$ tree
.
|-- ABitReader.cpp
|-- AString.cpp
|-- DataSource.cpp
|-- FileSource.cpp
|-- Makefile
`-- types_def.cpp

  需要说明的是,这几个cpp文件都是来源于Android SDK,位于framesworks/av/media目录下。

2. 各模块说明

  ABitReader——一个按二进制位读写/查询数据的工具,例如读取2bit二进制位,或者跳过3bit,或者查询当前读的bit位置的offset。

  AString——一个用于字符操作的工具,例如追加/插入字符串,或查找某个子字符串。

  DataSource——FileSource的父类,用于抽象读取数据的接口。

  FileSource——读本地文件的工具,是对open/read系统调用的一层抽象,未使用fopen/fread的标准C库函数。

  types_def——64位整形数据转换为网络字节序。

3. 为什么增加加这个底层库?

  JpegDecoder模块作为高层模块,期望从本地文件中,按位读取数据再去解码,重点是处理解码逻辑,而不希望看到底层细节处理操作,例如

从文件中如何读若干Bytes数据,再一个个bit位的逻辑操作。因此使用了这些底层子模块,去实现按bit位读取、跳若干bit位、查询当前位在文件中

的offset等底层细节问题。

  即高层模块只处理高层的业务逻辑,底层只处理底层的业务逻辑,避免眉毛鼻子一把抓。

  底层只负责读文件数据,按bit位方式拿数据。

4. 有无替代方案?

  在做这个h264_tools工具时,找到了x264实现的按bit位读取数据的模块——bs_read,这个应该是更简洁和高效一些吧。

5. bit位操作的常用接口

  由于解码过程中,常常是对bit位的操作运算,如果用fread从文件中读取一个个字节再拆解和组合为需要的bit位,那是相当低效的。从模块解耦

角度上看,需要一个工具,把jpeg数据读取到一块内存中,按需要从这块内存拿取或跳过一定bit位。这个工具就是ABitReader,移植自Android。

  下面是几个常用api及其介绍:

  uint32_t getBits(size_t n);        //从当前offset出取n bits,返回这n bits的值,之后内部的offset会后移n bits

  void skipBits(size_t n);          //从当前offset处跳过n bits,之后内部的offset会后移n bits

  void putBits(uint32_t x, size_t n);    //将n bits的值x,再返回给在读取的一块内存,那么offset会前移n bits

  int32_t getOffset() const;         //当前offset,其实是当前欲读bit位所在Byte值位置,距内存块首地址的偏移

  const uint8_t *data() const;        //当前读取bit位置所在的Byte的指针