Document directory
- 3.1 register the decoder
- 3.2 factory of encoder and decoder
- 3.3 register encoder and decoder to sktregistry
- 3.4 encoder or decoder through third-party lib or hardware solutions
1. Android image decoding process
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 features
Skia is a complete 2D image library that includes image, animation, text rendering, RGB (8 byte-32 byte) encoding (JPEG, PNG) and decoding functions. (YUV encoding and decoding is supported in android2.2 )..
1) Code Organization
Skia is a C ++-implemented code base. It exists in the form of an extension library in Android. The directory is external/skia /. The include/CORE/skcavans. h file defines the available APIs.
Class skcanvas: Public skrefnt
{
Public:
Drawargb (...)
Drawline (....)
Drawbitmap (....)
Drawtext (....)
}
Four public functions are used for various draw data. These four functions are the most important functions of skia.
Class skimagedecoder {
Static bool decodememory (....)
Static bool decodefile (....)
Static bool decodestream (....);
}
The three decoder functions that decoder can use to decoder data. decoder supports JPEG, PNG, and GIF data.
Class skimageencoder
{
Public:
Static bool encodefile (....)
Static bool encodestream (....)
}
Encoder can use the preceding two functions to encoder data. Currently, encoder only supports JPEG and PNG data output. The input only supports rawdata RGB (8 byte-32 byte) encoding.
If you have a hardware encoding and decoder, You can inherit skimagedecoder and skimageencoder to implement the hardware encoding and decoder. On the Android platform, the class skimagedecoder_libdemo.cpp uses the class library libjpeg to Implement JPEG decoding by inheriting skimagedecoder.
2) how to support skia in Android
Skia is an open source project, which is integrated into the Android system. Therefore, skia is not part of the android framework and does not need to implement the Framework API to support skia. However, skia can also be attached to other 3rd-party decoding libraries or hardware decoding libraries.
3. Analyze the skia codec Implementation Scheme 3.1 register the Codec
Skia defines the class template <typename T, typename P> class sktregistry: sknoncopyable
The sktregistry is implemented as a linked list. The Code is as follows:
/** 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) constructor is used to register a fact function. When using a linked list, you can obtain the required class through the node fact, such as encoder or decoder codec.
• Ghead member variables always point to the last node.
• Fchain refers to the forward node.
If it is encoder or decoder codec, you can register your factory function into this linked list. Then, when you need to create an encoder or decoder codec instance, find the corresponding node in the list of loop, then, call the factory function.
3.2 factory of encoder and decoder
The external/skia/src/images directory contains two files:
• Skimagedecoder_factory.cpp
• Skimageencoder_factory.cpp
The preceding two files define the following two important functions:
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;}
These two functions are used to traverse the previous list and create an encoder or decoder instance. Because template and class sktregistry have different gheaders as long as they are of different types, sktregistry can be used for different types without conflict.
3.3 register encoder and decoder to sktregistry
The external/skia/src/images directory contains many files similar to skimagedecoder_lib <*>. cpp. These files are encoded and decoded using the Lib of the 3rd party. There is similar code in these files: (at the end of the file, there is no declaration in the file header and it is static)
Static sktregistry <skimageencoder *, skimageencoder: type> gereg (efactory );
Static sktregistry <skimagedecoder *, skstream *> gdreg (dfactory );
It is defined at the end of the file and is not declared in the file header and is static. Only one constructor using sktregistry registers factory to list, this tells android that I have the ability to encode and decode a specific format.
For example, the Code in skimagedecoder_libdemo.cpp is as follows:
#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 encoder or decoder through third-party lib or hardware solutions
By inheriting class skimageencoder and skimagedecoder and implementing onencode and ondecode, encoder or decoder can be implemented through the Lib of the 3rd party.