summaryrefslogtreecommitdiffstats
path: root/skia/images/SkImageDecoder_libpvjpeg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'skia/images/SkImageDecoder_libpvjpeg.cpp')
-rw-r--r--skia/images/SkImageDecoder_libpvjpeg.cpp206
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;
+}
+