Android圖片編解碼實現方案(Skia)

來源:互聯網
上載者:User
文章目錄
  • 3.1 註冊轉碼器
  • 3.2 Encoder 和Decoder的Factory
  • 3.3 註冊 encoder 和 decoder 到 SkTRegistry
  • 3.4  通過第三方lib或硬體解決實現Encoder 或Decoder
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。

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.