Android图片编解码实现方案(Skia)
来源:互联网 发布:数据分析预测方法 编辑:程序博客网 时间:2024/05/17 04:45
1. Android图片解码流程
1) APP:BitmapDecode.java
2) API:BitmapFactory.java(static image)、Movie.java(dynamic image)
3) JNI:BitmapFactory.cpp(static image)、Movie.cpp(dynamic image)
4) C Native Service(Skia):SkImageDecoder.cpp(static image)、SkMovie.cpp(dynamic image)
2. Skia功能介绍
Skia 是一个完整的2D图像库,包括图像,动画,文本绘制功能, RGB(8byte – 32byte)编码(jpeg, png) 和解码功能。(在android2.2 中支持 yuv 的编码解码)。.
1) 代码组织
Skia 是一个 c++实现的代码库,在android 中以扩展库的形式存在,目录为external/skia/。其中文件 include/core/SkCavans.h 中定义了可以使用api.
Class SkCanvas:public SkRefnt
{
public:
drawARGB(...)
drawLine(....)
drawBitmap(....)
drawText(....)
}
4个 public函数用于draw 各种数据,这4个函数是 skia 最重要的函数。
Class SkImageDecoder{
static bool DecodeMemory(....)
static bool DecodeFile(....)
static bool DecodeStream(....);
}
decoder 可以使用的3个decoder的函数对数据进行decoder,Decoder 支持 jpeg, png, gif 等。
Class SkImageEncoder
{
public:
static bool EncodeFile(....)
static bool EncodeStream(....)
}
encoder 可以使用上面2个函数 对数据进行 encoder, 目前 encoder 只支持输出为jpeg 和 png. 输入只支持rawdata RGB(8byte – 32byte)编码 。
如果有硬件的编码和解码器可以通过继承SkImageDecoder和SkImageEncoder来实现硬件编码解码器。在 android 平台里面 类skImageDecoder_libjpeg.cpp 就是通过继承SkImageDecoder 使用类库libjpeg 实现 jpeg 的解码。
2) android 中如何支持skia
Skia 本身是一个 open source 的 project, 集成于android系统中。所以skia不是android 框架的一部分,不需要实现框架的api来支持skia。不过skia 同样可以挂接其他的第3方编码解码库或者硬件编解码库。
3. 分析Skia编解码实现方案
3.1 注册编解码器
Skia 定义了类template <typename T, typename P> class SkTRegistry : SkNoncopyable
SkTRegistry 内部实现为一个链表。代码如下:
/** Template class that registers itself (in the constructor) into a linked-list and provides a function-pointer. This can be used to auto-register a set of services, e.g. a set of image codecs. */template <typename T, typename P> class SkTRegistry : SkNoncopyable {public: typedef T (*Factory)(P); SkTRegistry(Factory fact) {#ifdef ANDROID // work-around for double-initialization bug { SkTRegistry* reg = gHead; while (reg) { if (reg == this) { return; } reg = reg->fChain; } }#endif fFact = fact; fChain = gHead; gHead = this; } static const SkTRegistry* Head() { return gHead; } const SkTRegistry* next() const { return fChain; } Factory factory() const { return fFact; }private: Factory fFact; SkTRegistry* fChain; static SkTRegistry* gHead;};// The caller still needs to declare an instance of this somewheretemplate <typename T, typename P> SkTRegistry<T, P>* SkTRegistry<T, P>::gHead;
• SkTRegistry(Factory fact) 构造函数,用于注册一个 fact 函数,在使用链表的时候,可以通过节点的fact 获得需要的class, 如encoder 或 decoder codec.
• Ghead 成员变量,永远指向最后一个节点。
• Fchain 指向前一个节点。
如果是encoder或decoder codec,就可以将自己的factory 函数注册到这个链表里面,然后当需要创建 encoder 或decoder codec 实例的时候,loop 这个list 找到对应的node, 然后调用factory函数。
3.2 Encoder 和Decoder的Factory
目录 external/skia/src/images中有两个文件:
• SkImageDecoder_Factory.cpp
• SkImageEncoder_Factory.cpp
以上两个文件中定义了以下两个重要函数:
SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) { SkImageDecoder* codec = NULL; const DecodeReg* curr = DecodeReg::Head(); while (curr) { codec = curr->factory()(stream); // we rewind here, because we promise later when we call "decode", that // the stream will be at its beginning. stream->rewind(); if (codec) { return codec; } curr = curr->next(); }#ifdef SK_ENABLE_LIBPNG codec = sk_libpng_dfactory(stream); stream->rewind(); if (codec) { return codec; }#endif return NULL;}
SkImageEncoder* SkImageEncoder::Create(Type t) { SkImageEncoder* codec = NULL; const EncodeReg* curr = EncodeReg::Head(); while (curr) { if ((codec = curr->factory()(t)) != NULL) { return codec; } curr = curr->next(); }#ifdef SK_ENABLE_LIBPNG if ((codec = sk_libpng_efactory(t)) != NULL) { return codec; }#endif return NULL;}
这两个函数就是用来遍历之前的list, 创建Encoder或Decoder 实例。由于通过template,class SkTRegistry 只要是不同的类型,就会有不同的gHeader, 所以不同类型都可以使用 SkTRegistry 而不发生冲突。
3.3 注册 encoder 和 decoder 到 SkTRegistry
目录external/skia/src/images 中有很多类似SkImageDecoder_lib<*>.cpp的文件,这些文件就是使用第3方的lib 来实现编码和解码的。在这些文件中都有类似的代码:(在文件的末尾,并且没有在文件头做声明且是static)
static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
定义在文件的末尾且没有在文件头做声明且是static,目的只有一个通过SkTRegistry的构造函数注册factory 到 list, 这样就告诉android 我有编码解码某某格式的能力了。
如SkImageDecoder_libjpeg.cpp中的相关代码如下:
#include "SkTRegistry.h"static SkImageDecoder* DFactory(SkStream* stream) { static const char gHeader[] = { 0xFF, 0xD8, 0xFF }; static const size_t HEADER_SIZE = sizeof(gHeader); char buffer[HEADER_SIZE]; size_t len = stream->read(buffer, HEADER_SIZE); if (len != HEADER_SIZE) { return NULL; // can't read enough } if (memcmp(buffer, gHeader, HEADER_SIZE)) { return NULL; } return SkNEW(SkJPEGImageDecoder);}static SkImageEncoder* EFactory(SkImageEncoder::Type t) { return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;}static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
3.4 通过第三方lib或硬件解决实现Encoder 或Decoder
通过继承class SkImageEncoder 和 SkImageDecoder 并实现 onEncode 和 onDecode来通过第3方的lib实现Encoder或Decoder。
- Android图片编解码实现方案(Skia)
- Android图片编解码实现方案(Skia)
- SKIA中的JPEG编解码
- android图片编解码architecture
- Android平台上使用skia库进行jpeg图片解码
- Skia 的图像编解码部分
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- 图片数据Base64编解码(java实现)
- Android学习 - android上实现编解码
- Java中native方法
- jQuery实现当拉动滚动条到底部加载数据
- ASP.NET实战-控件及日常功能开发
- 访问者模式
- Java servlet 之过滤器Filter详解
- Android图片编解码实现方案(Skia)
- 深入分析AsyncTask
- ASP.NET正式总结三
- Win7(64位)下安装Oracle 11g (图文解说版)
- AIDL笔记
- Mac OS X 背后的故事(一)力挽狂澜的Ellen Hancock
- 使用xib自定义Cell
- Jeally Bean中MonekyRunner 帮助文件
- 由in_array()函数引发的对PHP比较运算中自动转型的思考