#include "SkImageDecoder.h" #include "SkColor.h" #include "SkColorPriv.h" #include "SkDither.h" #include "SkMath.h" #include "SkStream.h" #include "SkTemplates.h" #include "SkUtils.h" extern void ValidateHeap(); class SkPVJPEGImageDecoder : public SkImageDecoder { protected: virtual bool onDecode(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref, Mode); private: enum { STORAGE_SIZE = 8 * 1024 }; char fStorage[STORAGE_SIZE]; }; SkImageDecoder* SkImageDecoder_PVJPEG_Factory(SkStream* stream) { return SkNEW(SkPVJPEGImageDecoder); } #include "pvjpgdecoderinterface.h" #include "pvjpgdecoder_factory.h" class AutoPVDelete { public: AutoPVDelete(PVJpgDecoderInterface* codec) : fCodec(codec) {} ~AutoPVDelete() { fCodec->Reset(); PVJpgDecoderFactory::DeletePVJpgDecoder(fCodec); } private: PVJpgDecoderInterface* fCodec; }; class MyObserver : public MPVJpegDecObserver { public: MyObserver() : fCount(0) {} ~MyObserver() { if (fCount != 0) { SkDebugf("--- pvjpeg left %d allocations\n", fCount); } } virtual void allocateBuffer(uint8* &buffer, int32 buffersize) { ++fCount; // we double the allocation to work around bug when height is odd buffer = (uint8*)sk_malloc_throw(buffersize << 1); SkDebugf("--- pvjpeg alloc [%d] %d addr=%p\n", fCount, buffersize, buffer); } virtual void deallocateBuffer(uint8 *buffer) { SkDebugf("--- pvjpeg free [%d] addr=%p\n", fCount, buffer); --fCount; sk_free(buffer); } private: int fCount; }; static void check_status(TPvJpgDecStatus status) { if (TPVJPGDEC_SUCCESS != status) { SkDEBUGF(("--- pvjpeg status %d\n", status)); } } static bool getFrame(PVJpgDecoderInterface* codec, SkBitmap* bitmap, SkBitmap::Config prefConfig, SkImageDecoder::Mode mode) { TPvJpgDecInfo info; TPvJpgDecStatus status = codec->GetInfo(&info); if (status != TPVJPGDEC_SUCCESS) return false; int width = info.iWidth[0]; int height = info.iHeight[0]; bitmap->setConfig(SkBitmap::kRGB_565_Config, width, height); bitmap->setIsOpaque(true); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } SkASSERT(info.iNumComponent == 3); TPvJpgDecOutputFmt format; format.iColorFormat = TPV_COLORFMT_RGB16; format.iCropped.topLeftX = 0; format.iCropped.topLeftY = 0; format.iCropped.bottomRightX = width - 1; format.iCropped.bottomRightY = height - 1; format.iOutputPitch = bitmap->rowBytes() >> 1; status = codec->SetOutput(&format); if (status != TPVJPGDEC_SUCCESS) { SkDebugf("--- PV SetOutput failed %d\n", status); return false; } TPvJpgDecFrame frame; uint8* ptrs[3]; int32 widths[3], heights[3]; sk_bzero(ptrs, sizeof(ptrs)); frame.ptr = ptrs; frame.iWidth = widths; frame.iHeight = heights; status = codec->GetFrame(&frame); if (status != TPVJPGDEC_SUCCESS) { SkDebugf("--- PV GetFrame failed %d\n", status); return false; } bitmap->allocPixels(); memcpy(bitmap->getPixels(), ptrs[0], bitmap->getSize()); return true; } class OsclCleanupper { public: OsclCleanupper() { OsclBase::Init(); OsclErrorTrap::Init(); OsclMem::Init(); } ~OsclCleanupper() { OsclMem::Cleanup(); OsclErrorTrap::Cleanup(); OsclBase::Cleanup(); } }; bool SkPVJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap, SkBitmap::Config prefConfig, Mode mode) { // do I need this guy? OsclCleanupper oc; PVJpgDecoderInterface* codec = PVJpgDecoderFactory::CreatePVJpgDecoder(); TPvJpgDecStatus status = codec->Init(); check_status(status); MyObserver observer; // must create before autopvdelete AutoPVDelete ad(codec); status = codec->SetObserver(&observer); check_status(status); char* storage = fStorage; int32 bytesInStorage = 0; for (;;) { int32 bytesRead = stream->read(storage + bytesInStorage, STORAGE_SIZE - bytesInStorage); if (bytesRead <= 0) { SkDEBUGF(("SkPVJPEGImageDecoder: stream read returned %d\n", bytesRead)); return false; } // update bytesInStorage to account for the read() bytesInStorage += bytesRead; SkASSERT(bytesInStorage <= STORAGE_SIZE); // now call Decode to eat some of the bytes int32 consumed = bytesInStorage; status = codec->Decode((uint8*)storage, &consumed); SkASSERT(bytesInStorage >= consumed); bytesInStorage -= consumed; // now bytesInStorage is the remaining unread bytes if (bytesInStorage > 0) { // slide the leftovers to the beginning SkASSERT(storage == fStorage); SkASSERT(consumed >= 0 && bytesInStorage >= 0); SkASSERT((size_t)(consumed + bytesInStorage) <= sizeof(fStorage)); SkASSERT(sizeof(fStorage) == STORAGE_SIZE); // SkDebugf("-- memmov srcOffset=%d, numBytes=%d\n", consumed, bytesInStorage); memmove(storage, storage + consumed, bytesInStorage); } switch (status) { case TPVJPGDEC_SUCCESS: SkDEBUGF(("SkPVJPEGImageDecoder::Decode returned success?\n");) return false; case TPVJPGDEC_FRAME_READY: case TPVJPGDEC_DONE: return getFrame(codec, decodedBitmap, prefConfig, mode); case TPVJPGDEC_FAIL: case TPVJPGDEC_INVALID_MEMORY: case TPVJPGDEC_INVALID_PARAMS: case TPVJPGDEC_NO_IMAGE_DATA: SkDEBUGF(("SkPVJPEGImageDecoder: failed to decode err=%d\n", status);) return false; case TPVJPGDEC_WAITING_FOR_INPUT: break; // loop around and eat more from the stream } } return false; }