Make non-animated webp file can be loaded. 53/257853/14
authorseungho <sbsh.baek@samsung.com>
Tue, 4 May 2021 09:02:29 +0000 (18:02 +0900)
committerseungho <sbsh.baek@samsung.com>
Mon, 24 May 2021 06:36:25 +0000 (15:36 +0900)
 - Make webp file that has wrong file extension can be loaded as a single image with image-visual.
 - Make webp file that hasn't animated option can be loaded with animated-image-visual without duplicated loading.

Change-Id: Idab5ed59d3bb06e87dd6028a39b41b8ea0986371
Signed-off-by: seungho <sbsh.baek@samsung.com>
dali/internal/imaging/common/image-loader.cpp
dali/internal/imaging/common/loader-webp.cpp [new file with mode: 0644]
dali/internal/imaging/common/loader-webp.h [new file with mode: 0644]
dali/internal/imaging/common/webp-loading.cpp
dali/internal/imaging/file.list

index f0ace20..dbf492c 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/internal/imaging/common/loader-astc.h>
 #include <dali/internal/imaging/common/loader-bmp.h>
 #include <dali/internal/imaging/common/loader-gif.h>
+#include <dali/internal/imaging/common/loader-webp.h>
 #include <dali/internal/imaging/common/loader-ico.h>
 #include <dali/internal/imaging/common/loader-jpeg.h>
 #include <dali/internal/imaging/common/loader-ktx.h>
@@ -61,6 +62,7 @@ enum FileFormats
   FORMAT_JPEG,
   FORMAT_BMP,
   FORMAT_GIF,
+  FORMAT_WEBP,
   FORMAT_KTX,
   FORMAT_ASTC,
   FORMAT_ICO,
@@ -82,6 +84,7 @@ const Dali::ImageLoader::BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[FORMAT_TOTAL_CO
     {Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
     {Bmp::MAGIC_BYTE_1,  Bmp::MAGIC_BYTE_2,  LoadBitmapFromBmp,  LoadBmpHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
     {Gif::MAGIC_BYTE_1,  Gif::MAGIC_BYTE_2,  LoadBitmapFromGif,  LoadGifHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Webp::MAGIC_BYTE_1, Webp::MAGIC_BYTE_2, LoadBitmapFromWebp, LoadWebpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
     {Ktx::MAGIC_BYTE_1,  Ktx::MAGIC_BYTE_2,  LoadBitmapFromKtx,  LoadKtxHeader,  Bitmap::BITMAP_COMPRESSED      },
     {Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED      },
     {Ico::MAGIC_BYTE_1,  Ico::MAGIC_BYTE_2,  LoadBitmapFromIco,  LoadIcoHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
@@ -107,6 +110,7 @@ const FormatExtension FORMAT_EXTENSIONS[] =
     {".jpg",  FORMAT_JPEG},
     {".bmp",  FORMAT_BMP },
     {".gif",  FORMAT_GIF },
+    {".webp", FORMAT_WEBP },
     {".ktx",  FORMAT_KTX },
     {".astc", FORMAT_ASTC},
     {".ico",  FORMAT_ICO },
diff --git a/dali/internal/imaging/common/loader-webp.cpp b/dali/internal/imaging/common/loader-webp.cpp
new file mode 100644 (file)
index 0000000..37404dd
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/internal/imaging/common/loader-webp.h>
+
+// EXTERNAL INCLUDES
+#ifdef DALI_WEBP_AVAILABLE
+#include <webp/decode.h>
+#include <webp/demux.h>
+
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+#define DALI_ANIMATED_WEBP_ENABLED 1
+#endif
+#endif
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/integration-api/debug.h>
+#include <cstring>
+#include <memory>
+
+typedef unsigned char WebPByteType;
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+bool ReadWebPInformation(FILE* const fp, WebPData& webPData)
+{
+  if(fp == NULL)
+  {
+    return false;
+  }
+
+  if(fseek(fp, 0, SEEK_END) <= -1)
+  {
+    return false;
+  }
+  WebPDataInit(&webPData);
+  webPData.size = ftell(fp);
+
+  if((!fseek(fp, 0, SEEK_SET)))
+  {
+    unsigned char* WebPDataBuffer;
+    WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * webPData.size));
+    webPData.size  = fread(WebPDataBuffer, sizeof(WebPByteType), webPData.size, fp);
+    webPData.bytes = WebPDataBuffer;
+  }
+  else
+  {
+    return false;
+  }
+  return true;
+}
+
+void ReleaseResource(WebPData& webPData, WebPAnimDecoder* webPAnimDecoder)
+{
+  free((void*)webPData.bytes);
+  webPData.bytes = nullptr;
+  WebPDataInit(&webPData);
+  if(webPAnimDecoder)
+  {
+    WebPAnimDecoderDelete(webPAnimDecoder);
+  }
+}
+
+#endif
+
+bool LoadWebpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
+{
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    return false;
+  }
+
+  if(fseek(fp, 0, SEEK_END) <= -1)
+  {
+    return false;
+  }
+
+  // If the image is non-animated webp
+#ifdef DALI_WEBP_AVAILABLE
+  size_t webPSize = ftell(fp);
+  if((!fseek(fp, 0, SEEK_SET)))
+  {
+    std::vector<uint8_t> encodedImage;
+    encodedImage.resize(webPSize, 0);
+    size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
+    if(readCount != encodedImage.size())
+    {
+      return false;
+    }
+    int32_t imageWidth, imageHeight;
+    if(WebPGetInfo(&encodedImage[0], encodedImage.size(), &imageWidth, &imageHeight))
+    {
+      width  = static_cast<uint32_t>(imageWidth);
+      height = static_cast<uint32_t>(imageHeight);
+      return true;
+    }
+  }
+#endif
+
+  // If the image is animated webp
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+  WebPData         webPData;
+  WebPAnimDecoder* webPAnimDecoder;
+  WebPAnimInfo     webPAnimInfo;
+  if(ReadWebPInformation(fp, webPData))
+  {
+    WebPAnimDecoderOptions webPAnimDecoderOptions;
+    WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
+    webPAnimDecoderOptions.color_mode = MODE_RGBA;
+    webPAnimDecoder                   = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
+    if(webPAnimDecoder != nullptr)
+    {
+      WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
+      width  = webPAnimInfo.canvas_width;
+      height = webPAnimInfo.canvas_height;
+      return true;
+    }
+  }
+  ReleaseResource(webPData, webPAnimDecoder);
+#endif
+  DALI_LOG_ERROR("WebP file open failed.\n");
+  return false;
+}
+
+bool LoadBitmapFromWebp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
+{
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    return false;
+  }
+
+  if(fseek(fp, 0, SEEK_END) <= -1)
+  {
+    return false;
+  }
+
+  // If the image is non-animated webp
+#ifdef DALI_WEBP_AVAILABLE
+  size_t webPSize = ftell(fp);
+  if((!fseek(fp, 0, SEEK_SET)))
+  {
+    std::vector<uint8_t> encodedImage;
+    encodedImage.resize(webPSize, 0);
+    size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
+    if(readCount != encodedImage.size())
+    {
+      DALI_LOG_ERROR("WebP image loading failed.\n");
+      return false;
+    }
+
+    int32_t width, height;
+    if(!WebPGetInfo(&encodedImage[0], encodedImage.size(), &width, &height))
+    {
+      DALI_LOG_ERROR("Cannot retrieve WebP image size information.\n");
+      return false;
+    }
+
+    WebPBitstreamFeatures features;
+    if(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(&encodedImage[0], encodedImage.size(), &features))
+    {
+      DALI_LOG_ERROR("Cannot retrieve WebP image features.\n");
+      return false;
+    }
+
+    uint32_t      channelNumber = (features.has_alpha) ? 4 : 3;
+    Pixel::Format pixelFormat   = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
+    bitmap                      = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
+    uint8_t* frameBuffer        = nullptr;
+    if(channelNumber == 4)
+    {
+      frameBuffer = WebPDecodeRGBA(&encodedImage[0], encodedImage.size(), &width, &height);
+    }
+    else
+    {
+      frameBuffer = WebPDecodeRGB(&encodedImage[0], encodedImage.size(), &width, &height);
+    }
+
+    if(frameBuffer != nullptr)
+    {
+      const int32_t bufferSize = width * height * sizeof(uint8_t) * channelNumber;
+      memcpy(bitmap.GetBuffer(), frameBuffer, bufferSize);
+      free((void*)frameBuffer);
+      return true;
+    }
+  }
+#endif
+
+  // If the image is animated webp
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+  WebPData         webPData;
+  WebPAnimDecoder* webPAnimDecoder;
+  WebPAnimInfo     webPAnimInfo;
+  if(ReadWebPInformation(fp, webPData))
+  {
+    WebPAnimDecoderOptions webPAnimDecoderOptions;
+    WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
+    webPAnimDecoderOptions.color_mode = MODE_RGBA;
+    webPAnimDecoder                   = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
+    if(webPAnimDecoder != nullptr)
+    {
+      uint8_t* frameBuffer;
+      int      timestamp;
+      WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
+      WebPAnimDecoderReset(webPAnimDecoder);
+      WebPAnimDecoderGetNext(webPAnimDecoder, &frameBuffer, &timestamp);
+
+      bitmap                   = Dali::Devel::PixelBuffer::New(webPAnimInfo.canvas_width, webPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
+      const int32_t bufferSize = webPAnimInfo.canvas_width * webPAnimInfo.canvas_height * sizeof(uint32_t);
+      memcpy(bitmap.GetBuffer(), frameBuffer, bufferSize);
+      return true;
+    }
+  }
+  ReleaseResource(webPData, webPAnimDecoder);
+#endif
+
+  DALI_LOG_ERROR("WebP image loading failed.\n");
+  return false;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-webp.h b/dali/internal/imaging/common/loader-webp.h
new file mode 100644 (file)
index 0000000..55d3278
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_WEBP_H
+#define DALI_TIZEN_PLATFORM_LOADER_WEBP_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+#include <cstdio>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+namespace TizenPlatform
+{
+class ResourceLoadingClient;
+
+namespace Webp
+{
+const unsigned char MAGIC_BYTE_1 = 0x52;
+const unsigned char MAGIC_BYTE_2 = 0x49;
+} // namespace Webp
+
+/**
+ * Loads the header of a Webp file and fills in the width and height appropriately.
+ * @param[in]  input   Information about the input image (including file pointer)
+ * @param[out] width   Is set with the width of the image
+ * @param[out] height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadWebpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height);
+
+/**
+ * Loads the bitmap from a Webp file.  This function checks the header first
+ * and if it is not a Webp file, then it returns straight away.
+ * @note For animated Webps, only the first image is displayed
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromWebp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap);
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_WEBP_H
index 7e4511c..dc758fa 100644 (file)
@@ -24,7 +24,7 @@
 #include <webp/demux.h>
 
 #if WEBP_DEMUX_ABI_VERSION > 0x0101
-#define DALI_WEBP_ENABLED 1
+#define DALI_ANIMATED_WEBP_ENABLED 1
 #endif
 
 #endif
@@ -40,6 +40,9 @@
 #include <unistd.h>
 #include <cstring>
 
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
 typedef unsigned char WebPByteType;
 
 namespace Dali
@@ -63,34 +66,56 @@ struct WebPLoading::Impl
 public:
   Impl(const std::string& url, bool isLocalResource)
   : mUrl(url),
-    mLoadSucceeded(true),
-    mMutex()
+    mFrameCount(1u),
+    mMutex(),
+    mBuffer(nullptr),
+    mBufferSize(0u),
+    mImageSize(),
+    mLoadSucceeded(true)
   {
-#ifdef DALI_WEBP_ENABLED
+    // mFrameCount will be 1 if the input image is non-animated image or animated image with single frame.
     if(ReadWebPInformation(isLocalResource))
     {
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+      WebPDataInit(&mWebPData);
+      mWebPData.size  = mBufferSize;
+      mWebPData.bytes = mBuffer;
       WebPAnimDecoderOptions webPAnimDecoderOptions;
       WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
       webPAnimDecoderOptions.color_mode = MODE_RGBA;
       mWebPAnimDecoder                  = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
       WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
       mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
+      mFrameCount = mWebPAnimInfo.frame_count;
+      mImageSize  = ImageDimensions(mWebPAnimInfo.canvas_width, mWebPAnimInfo.canvas_height);
+#elif DALI_WEBP_AVAILABLE
+      int32_t imageWidth, imageHeight;
+      if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+      {
+        mImageSize = ImageDimensions(imageWidth, imageHeight);
+      }
+#endif
+#ifndef DALI_WEBP_AVAILABLE
+      // If the system doesn't support webp, loading will be failed.
+      mFrameCount    = 0u;
+      mLoadSucceeded = false;
+#endif
     }
     else
     {
+      mFrameCount    = 0u;
       mLoadSucceeded = false;
+      DALI_LOG_ERROR("Image loading failed for: \"%s\".\n", mUrl.c_str());
     }
-#endif
   }
 
   bool ReadWebPInformation(bool isLocalResource)
   {
-#ifdef DALI_WEBP_ENABLED
-    WebPDataInit(&mWebPData);
+    FILE* fp = nullptr;
     if(isLocalResource)
     {
       Internal::Platform::FileReader fileReader(mUrl);
-      FILE*                          fp = fileReader.GetFile();
+      fp = fileReader.GetFile();
       if(fp == NULL)
       {
         return false;
@@ -101,17 +126,12 @@ public:
         return false;
       }
 
-      mWebPData.size = ftell(fp);
-      if((!fseek(fp, 0, SEEK_SET)))
-      {
-        unsigned char* WebPDataBuffer;
-        WebPDataBuffer  = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mWebPData.size));
-        mWebPData.size  = fread(WebPDataBuffer, sizeof(WebPByteType), mWebPData.size, fp);
-        mWebPData.bytes = WebPDataBuffer;
-      }
-      else
+      mBufferSize = ftell(fp);
+      if(!fseek(fp, 0, SEEK_SET))
       {
-        return false;
+        mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
+        mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
+        return true;
       }
     }
     else
@@ -124,37 +144,25 @@ public:
       succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
       if(succeeded)
       {
-        size_t blobSize = dataBuffer.Size();
-        if(blobSize > 0U)
+        mBufferSize = dataBuffer.Size();
+        if(mBufferSize > 0U)
         {
           // Open a file handle on the memory buffer:
-          Dali::Internal::Platform::FileReader fileReader(dataBuffer, blobSize);
-          FILE* const                          fp = fileReader.GetFile();
-          if(NULL != fp)
+          Internal::Platform::FileReader fileReader(dataBuffer, mBufferSize);
+          fp = fileReader.GetFile();
+          if(fp != nullptr)
           {
-            if((!fseek(fp, 0, SEEK_SET)))
+            if(!fseek(fp, 0, SEEK_SET))
             {
-              unsigned char* WebPDataBuffer;
-              WebPDataBuffer  = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * blobSize));
-              mWebPData.size  = fread(WebPDataBuffer, sizeof(WebPByteType), mWebPData.size, fp);
-              mWebPData.bytes = WebPDataBuffer;
+              mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
+              mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
+              return true;
             }
-            else
-            {
-              DALI_LOG_ERROR("Error seeking within file\n");
-            }
-          }
-          else
-          {
-            DALI_LOG_ERROR("Error reading file\n");
           }
         }
       }
     }
-    return true;
-#else
     return false;
-#endif
   }
 
   // Moveable but not copyable
@@ -166,10 +174,9 @@ public:
 
   ~Impl()
   {
-#ifdef DALI_WEBP_ENABLED
+#ifdef DALI_ANIMATED_WEBP_ENABLED
     if(&mWebPData != NULL)
     {
-      free((void*)mWebPData.bytes);
       mWebPData.bytes = nullptr;
       WebPDataInit(&mWebPData);
     }
@@ -178,15 +185,22 @@ public:
       WebPAnimDecoderDelete(mWebPAnimDecoder);
     }
 #endif
+    free((void*)mBuffer);
+    mBuffer = nullptr;
   }
 
   std::string           mUrl;
   std::vector<uint32_t> mTimeStamp;
   uint32_t              mLoadingFrame{0};
-  bool                  mLoadSucceeded;
+  uint32_t              mFrameCount;
   Mutex                 mMutex;
+  // For the case the system doesn't support DALI_ANIMATED_WEBP_ENABLED
+  unsigned char*  mBuffer;
+  uint32_t        mBufferSize;
+  ImageDimensions mImageSize;
+  bool            mLoadSucceeded;
 
-#ifdef DALI_WEBP_ENABLED
+#ifdef DALI_ANIMATED_WEBP_ENABLED
   WebPData         mWebPData{0};
   WebPAnimDecoder* mWebPAnimDecoder{nullptr};
   WebPAnimInfo     mWebPAnimInfo{0};
@@ -195,7 +209,7 @@ public:
 
 AnimatedImageLoadingPtr WebPLoading::New(const std::string& url, bool isLocalResource)
 {
-#ifndef DALI_WEBP_ENABLED
+#ifndef DALI_ANIMATED_WEBP_ENABLED
   DALI_LOG_ERROR("The system does not support Animated WebP format.\n");
 #endif
   return AnimatedImageLoadingPtr(new WebPLoading(url, isLocalResource));
@@ -213,64 +227,64 @@ WebPLoading::~WebPLoading()
 
 bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
 {
-#ifdef DALI_WEBP_ENABLED
-  Mutex::ScopedLock lock(mImpl->mMutex);
-  if(frameStartIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded)
+  for(int i = 0; i < count; ++i)
   {
-    return false;
+    Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
+    Dali::PixelData          imageData   = Devel::PixelBuffer::Convert(pixelBuffer);
+    pixelData.push_back(imageData);
   }
-
-  DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count);
-
-  if(mImpl->mLoadingFrame > frameStartIndex)
+  if(pixelData.size() != static_cast<uint32_t>(count))
   {
-    mImpl->mLoadingFrame = 0;
-    WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
+    return false;
   }
+  return true;
+}
 
-  for(; mImpl->mLoadingFrame < frameStartIndex; ++mImpl->mLoadingFrame)
-  {
-    uint8_t* frameBuffer;
-    int      timestamp;
-    WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
-    mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
-  }
+Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
+{
+  Dali::Devel::PixelBuffer pixelBuffer;
 
-  for(int i = 0; i < count; ++i)
+  // WebPDecodeRGBA is faster than to use demux API for loading non-animated image.
+  // If frame count is 1, use WebPDecodeRGBA api.
+#ifdef DALI_WEBP_AVAILABLE
+  if(mImpl->mFrameCount == 1)
   {
-    const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
-    uint8_t*  frameBuffer;
-    int       timestamp;
-    WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
+    int32_t width, height;
+    if(!WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height))
+    {
+      return pixelBuffer;
+    }
 
-    auto pixelBuffer = new uint8_t[bufferSize];
-    memcpy(pixelBuffer, frameBuffer, bufferSize);
-    mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+    WebPBitstreamFeatures features;
+    if(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features))
+    {
+      return pixelBuffer;
+    }
 
-    if(pixelBuffer)
+    uint32_t      channelNumber = (features.has_alpha) ? 4 : 3;
+    Pixel::Format pixelFormat   = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
+    pixelBuffer                 = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
+    uint8_t* frameBuffer        = nullptr;
+    if(channelNumber == 4)
+    {
+      frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+    }
+    else
     {
-      pixelData.push_back(Dali::PixelData::New(pixelBuffer, bufferSize, mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY));
+      frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
     }
 
-    mImpl->mLoadingFrame++;
-    if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
+    if(frameBuffer != nullptr)
     {
-      mImpl->mLoadingFrame = 0;
-      WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
+      const int32_t imageBufferSize = width * height * sizeof(uint8_t) * channelNumber;
+      memcpy(pixelBuffer.GetBuffer(), frameBuffer, imageBufferSize);
+      free((void*)frameBuffer);
+      return pixelBuffer;
     }
   }
-
-  return true;
-#else
-  return false;
 #endif
-}
 
-Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
-{
-  Dali::Devel::PixelBuffer pixelBuffer;
-
-#ifdef DALI_WEBP_ENABLED
+#ifdef DALI_ANIMATED_WEBP_ENABLED
   Mutex::ScopedLock lock(mImpl->mMutex);
   if(frameIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded)
   {
@@ -314,20 +328,12 @@ Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
 
 ImageDimensions WebPLoading::GetImageSize() const
 {
-#ifdef DALI_WEBP_ENABLED
-  return ImageDimensions(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height);
-#else
-  return ImageDimensions();
-#endif
+  return mImpl->mImageSize;
 }
 
 uint32_t WebPLoading::GetImageCount() const
 {
-#ifdef DALI_WEBP_ENABLED
-  return mImpl->mWebPAnimInfo.frame_count;
-#else
-  return 0u;
-#endif
+  return mImpl->mFrameCount;
 }
 
 uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
index b5f0894..4dcda76 100644 (file)
@@ -17,6 +17,7 @@ SET( adaptor_imaging_common_src_files
     ${adaptor_imaging_dir}/common/loader-ktx.cpp
     ${adaptor_imaging_dir}/common/loader-png.cpp
     ${adaptor_imaging_dir}/common/loader-wbmp.cpp
+    ${adaptor_imaging_dir}/common/loader-webp.cpp
     ${adaptor_imaging_dir}/common/pixel-manipulation.cpp
     ${adaptor_imaging_dir}/common/gif-loading.cpp
     ${adaptor_imaging_dir}/common/webp-loading.cpp