diff options
Diffstat (limited to 'skia/images/SkImageDecoder_libpvjpeg.cpp')
-rw-r--r-- | skia/images/SkImageDecoder_libpvjpeg.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/skia/images/SkImageDecoder_libpvjpeg.cpp b/skia/images/SkImageDecoder_libpvjpeg.cpp new file mode 100644 index 0000000..9177741 --- /dev/null +++ b/skia/images/SkImageDecoder_libpvjpeg.cpp @@ -0,0 +1,206 @@ +#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]; + 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; +} + |