jpg_loader: support multi-thread and header reading in prior to decoding.
authorHermet Park <chuneon.park@samsung.com>
Wed, 27 Oct 2021 04:47:52 +0000 (13:47 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Thu, 28 Oct 2021 06:19:31 +0000 (15:19 +0900)
revise the code to support async loading of the static jpeg_loader,
also support header reading in prior to decoding.

src/loaders/jpg/tvgJpgLoader.cpp
src/loaders/jpg/tvgJpgLoader.h
src/loaders/jpg/tvgJpgd.cpp
src/loaders/jpg/tvgJpgd.h
src/loaders/png/tvgPngLoader.cpp
src/loaders/png/tvgPngLoader.h

index 7e6c375..599d2fe 100644 (file)
@@ -20,7 +20,7 @@
  * SOFTWARE.
  */
 
-#include "tvgJpgd.h"
+#include <memory.h>
 #include "tvgLoader.h"
 #include "tvgJpgLoader.h"
 
 /* Internal Class Implementation                                        */
 /************************************************************************/
 
+void JpgLoader::clear()
+{
+    jpgdDelete(decoder);
+    if (freeData) free(data);
+    decoder = nullptr;
+    data = nullptr;
+    freeData = false;
+}
+
 
 /************************************************************************/
 /* External Class Implementation                                        */
 
 JpgLoader::~JpgLoader()
 {
-    free(image);
-    image = NULL;
+    jpgdDelete(decoder);
+    if (freeData) free(data);
 }
 
+
 bool JpgLoader::open(const string& path)
 {
-    int width, height, actual_comps;
-    image = decompress_jpeg_image_from_file(path.c_str(), &width, &height, &actual_comps, 4);
-    if (!image) return false;
+    clear();
 
-    vw = w = static_cast<float>(width);
-    vh = h = static_cast<float>(height);
+    int width, height;
+    decoder = jpgdHeader(path.c_str(), &width, &height);
+    if (!decoder) return false;
+
+    w = static_cast<float>(width);
+    h = static_cast<float>(height);
 
     return true;
 }
 
+
 bool JpgLoader::open(const char* data, uint32_t size, bool copy)
 {
-    int width, height, actual_comps;
-    image = decompress_jpeg_image_from_memory((const unsigned char *)data, size, &width, &height, &actual_comps, 4);
-    if (!image) return false;
+    clear();
+
+    if (copy) {
+        this->data = (char *) malloc(size);
+        if (!this->data) return false;
+        memcpy((char *)this->data, data, size);
+        freeData = true;
+    } else {
+        this->data = (char *) data;
+        freeData = false;
+    }
+
+    int width, height;
+    decoder = jpgdHeader(this->data, size, &width, &height);
+    if (!decoder) return false;
 
-    vw = w = static_cast<float>(width);
-    vh = h = static_cast<float>(height);
+    w = static_cast<float>(width);
+    h = static_cast<float>(height);
 
     return true;
 }
 
 
+
 bool JpgLoader::read()
 {
+    if (!decoder || w <= 0 || h <= 0) return false;
+
+    TaskScheduler::request(this);
+
     return true;
 }
 
 
 bool JpgLoader::close()
 {
+    this->done();
+    clear();
     return true;
 }
 
 
 const uint32_t* JpgLoader::pixels()
 {
+    this->done();
+
     return (const uint32_t*)image;
 }
+
+
+void JpgLoader::run(unsigned tid)
+{
+    image = jpgdDecompress(decoder);
+}
\ No newline at end of file
index e12a907..e7ec3ab 100644 (file)
 #ifndef _TVG_JPG_LOADER_H_
 #define _TVG_JPG_LOADER_H_
 
-//TODO: Use Task?
-class JpgLoader : public LoadModule
+#include "tvgTaskScheduler.h"
+#include "tvgJpgd.h"
+
+class JpgLoader : public LoadModule, public Task
 {
+private:
+    jpeg_decoder* decoder = nullptr;
+    char* data = nullptr;
+    unsigned char *image = nullptr;
+    bool freeData = false;
+
+    void clear();
+
 public:
     ~JpgLoader();
 
@@ -35,9 +45,7 @@ public:
     bool close() override;
 
     const uint32_t* pixels() override;
-
-private:
-    unsigned char *image = nullptr;
+    void run(unsigned tid) override;
 };
 
 #endif //_TVG_JPG_LOADER_H_
index 7a59829..1bf5e6f 100644 (file)
@@ -110,11 +110,12 @@ class jpeg_decoder_file_stream : public jpeg_decoder_stream
     jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
     jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
 
-    FILE *m_pFile;
-    bool m_eof_flag, m_error_flag;
+    FILE *m_pFile = nullptr;
+    bool m_eof_flag = false;
+    bool m_error_flag = false;
 
 public:
-    jpeg_decoder_file_stream();
+    jpeg_decoder_file_stream() {}
     virtual ~jpeg_decoder_file_stream();
     bool open(const char *Pfilename);
     void close();
@@ -2814,14 +2815,7 @@ int jpeg_decoder::begin_decoding()
 jpeg_decoder::~jpeg_decoder()
 {
     free_all_blocks();
-}
-
-
-jpeg_decoder_file_stream::jpeg_decoder_file_stream()
-{
-    m_pFile = nullptr;
-    m_eof_flag = false;
-    m_error_flag = false;
+    delete(m_pStream);
 }
 
 
@@ -2910,23 +2904,62 @@ int jpeg_decoder_mem_stream::read(uint8_t *pBuf, int max_bytes_to_read, bool *pE
 }
 
 
-unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps)
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+
+jpeg_decoder* jpgdHeader(const char* data, int size, int* width, int* height)
 {
-    if (!actual_comps) return nullptr;
-    *actual_comps = 0;
+    auto decoder = new jpeg_decoder(new jpeg_decoder_mem_stream((const uint8_t*)data, size));
+    if (decoder->get_error_code() != JPGD_SUCCESS) {
+        delete(decoder);
+        return nullptr;
+    }
+
+    if (width) *width = decoder->get_width();
+    if (height) *height = decoder->get_height();
+
+    return decoder;
+}
+
+
+jpeg_decoder* jpgdHeader(const char* filename, int* width, int* height)
+{
+    auto fileStream = new jpeg_decoder_file_stream();
+    if (!fileStream->open(filename)) return nullptr;
+
+    auto decoder = new jpeg_decoder(fileStream);
+    if (decoder->get_error_code() != JPGD_SUCCESS) {
+        delete(decoder);
+        return nullptr;
+    }
+
+    if (width) *width = decoder->get_width();
+    if (height) *height = decoder->get_height();
+
+    return decoder;
+}
+
+
+void jpgdDelete(jpeg_decoder* decoder)
+{
+    delete(decoder);
+}
 
-    if ((!pStream) || (!width) || (!height) || (!req_comps))  return nullptr;
-    if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) return nullptr;
 
-    jpeg_decoder decoder(pStream);
-    if (decoder.get_error_code() != JPGD_SUCCESS) return nullptr;
+unsigned char* jpgdDecompress(jpeg_decoder* decoder)
+{
+    if (!decoder) return nullptr;
+
+    int req_comps = 4;  //TODO: fixed 4 channel components now?
+    if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) return nullptr;
 
-    const int image_width = decoder.get_width(), image_height = decoder.get_height();
-    *width = image_width;
-    *height = image_height;
-    *actual_comps = decoder.get_num_components();
+    auto image_width = decoder->get_width();
+    auto image_height = decoder->get_height();
+    //auto actual_comps = decoder->get_num_components();
 
-    if (decoder.begin_decoding() != JPGD_SUCCESS) return nullptr;
+    if (decoder->begin_decoding() != JPGD_SUCCESS) return nullptr;
 
     const int dst_bpl = image_width * req_comps;
     uint8_t *pImage_data = (uint8_t*)malloc(dst_bpl * image_height);
@@ -2935,7 +2968,7 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
     for (int y = 0; y < image_height; y++) {
         const uint8_t* pScan_line;
         uint32_t scan_line_len;
-        if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) {
+        if (decoder->decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) {
             free(pImage_data);
             return nullptr;
         }
@@ -2943,17 +2976,17 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
         uint8_t *pDst = pImage_data + y * dst_bpl;
 
         //Return as BGRA
-        if ((req_comps == 4) && (decoder.get_num_components() == 3)) {
+        if ((req_comps == 4) && (decoder->get_num_components() == 3)) {
             for (int x = 0; x < image_width; x++) {
                 pDst[0] = pScan_line[x*4+2];
                 pDst[1] = pScan_line[x*4+1];
                 pDst[2] = pScan_line[x*4+0];
                 pDst[3] = 255;
                 pDst += 4;
-            } 
-        } else if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3))) {
+            }
+        } else if (((req_comps == 1) && (decoder->get_num_components() == 1)) || ((req_comps == 4) && (decoder->get_num_components() == 3))) {
             memcpy(pDst, pScan_line, dst_bpl);
-        } else if (decoder.get_num_components() == 1) {
+        } else if (decoder->get_num_components() == 1) {
             if (req_comps == 3) {
                 for (int x = 0; x < image_width; x++) {
                     uint8_t luma = pScan_line[x];
@@ -2972,7 +3005,7 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
                     pDst += 4;
                 }
             }
-        } else if (decoder.get_num_components() == 3) {
+        } else if (decoder->get_num_components() == 3) {
             if (req_comps == 1) {
                 const int YR = 19595, YG = 38470, YB = 7471;
                 for (int x = 0; x < image_width; x++) {
@@ -2992,23 +3025,4 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
         }
     }
     return pImage_data;
-}
-
-
-/************************************************************************/
-/* External Class Implementation                                        */
-/************************************************************************/
-
-unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps)
-{
-    jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size);
-    return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps);
-}
-
-
-unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps)
-{
-    jpeg_decoder_file_stream file_stream;
-    if (!file_stream.open(pSrc_filename)) return nullptr;
-    return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps);
 }
\ No newline at end of file
index 61c6969..a0e56e6 100644 (file)
 #ifndef _TVG_JPGD_H_\r
 #define _TVG_JPGD_H_\r
 \r
-// Loads a JPEG image from a memory buffer or a file.\r
-// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).\r
-// On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).\r
-// Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.\r
-// Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.\r
-unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps);\r
-unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps);\r
+class jpeg_decoder;\r
+\r
+jpeg_decoder* jpgdHeader(const char* data, int size, int* width, int* height);\r
+jpeg_decoder* jpgdHeader(const char* filename, int* width, int* height);\r
+unsigned char* jpgdDecompress(jpeg_decoder* decoder);\r
+void jpgdDelete(jpeg_decoder* decoder);\r
 \r
 #endif //_TVG_JPGD_H_\r
index 31af358..e50f34e 100644 (file)
@@ -136,7 +136,6 @@ bool PngLoader::read()
 bool PngLoader::close()
 {
     this->done();
-
     clear();
     return true;
 }
index 97c91a4..fa1860c 100644 (file)
@@ -48,7 +48,6 @@ public:
     bool close() override;
 
     const uint32_t* pixels() override;
-
     void run(unsigned tid) override;
 };