Refactoring webp-loading and loader-webp 56/273656/13
authorseungho <sbsh.baek@samsung.com>
Mon, 11 Apr 2022 13:38:00 +0000 (22:38 +0900)
committerseungho <sbsh.baek@samsung.com>
Wed, 13 Apr 2022 12:30:19 +0000 (21:30 +0900)
 - Remove duplicate code(To use WebPLoading from LoaderWebP)
 - Use header flag to define the webp is animated or not.

Change-Id: I9118bd77aa6c1d3430b4d90ca62069f24331d82e
Signed-off-by: seungho <sbsh.baek@samsung.com>
automated-tests/src/dali-adaptor/utc-Dali-GifLoading.cpp
dali/devel-api/adaptor-framework/animated-image-loading.cpp
dali/devel-api/adaptor-framework/animated-image-loading.h
dali/internal/imaging/common/animated-image-loading-impl.h
dali/internal/imaging/common/gif-loading.cpp
dali/internal/imaging/common/gif-loading.h
dali/internal/imaging/common/loader-webp.cpp
dali/internal/imaging/common/webp-loading.cpp
dali/internal/imaging/common/webp-loading.h

index 669b729..b71cedd 100644 (file)
@@ -26,27 +26,10 @@ namespace
 {
 // test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none
 static const char* gGif_100_None = TEST_RESOURCE_DIR "/canvas-none.gif";
-// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none for first frame and previous for the rest
-static const char* gGif_100_Prev = TEST_RESOURCE_DIR "/canvas-prev.gif";
-// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: background
-static const char* gGif_100_Bgnd = TEST_RESOURCE_DIR "/canvas-bgnd.gif";
 
 // this image if not exist, for negative test
 static const char* gGifNonExist = "non-exist.gif";
 
-void VerifyLoad(std::vector<Dali::PixelData>& pixelDataList, Dali::Vector<uint32_t>& frameDelayList, uint32_t frameCount, uint32_t width, uint32_t height, uint32_t delay)
-{
-  DALI_TEST_EQUALS(pixelDataList.size(), frameCount, TEST_LOCATION);
-  DALI_TEST_EQUALS(frameDelayList.Size(), frameCount, TEST_LOCATION);
-
-  for(uint32_t idx = 0; idx < frameCount; idx++)
-  {
-    // Check the image size and delay of each frame
-    DALI_TEST_EQUALS(pixelDataList[idx].GetWidth(), width, TEST_LOCATION);
-    DALI_TEST_EQUALS(pixelDataList[idx].GetHeight(), height, TEST_LOCATION);
-    DALI_TEST_EQUALS(frameDelayList[idx], delay, TEST_LOCATION);
-  }
-}
 } // namespace
 
 void utc_dali_animated_image_loader_startup(void)
@@ -59,72 +42,6 @@ void utc_dali_animated_image_loader_cleanup(void)
   test_return_value = TET_PASS;
 }
 
-int UtcDaliAnimatedImageLoadingP(void)
-{
-  std::vector<Dali::PixelData> pixelDataList;
-  Dali::Vector<uint32_t>       frameDelayList;
-
-  Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_None, true);
-  bool                       succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-  frameDelayList.Clear();
-  frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
-  for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
-  {
-    frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
-  }
-
-  // Check that the loading succeed
-  DALI_TEST_CHECK(succeed);
-  VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
-  pixelDataList.clear();
-  animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_Prev, true);
-  succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-  frameDelayList.Clear();
-  frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
-  for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
-  {
-    frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
-  }
-
-  // Check that the loading succeed
-  DALI_TEST_CHECK(succeed);
-  VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
-  pixelDataList.clear();
-  animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_Bgnd, true);
-  succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-  frameDelayList.Clear();
-  frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
-  for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
-  {
-    frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
-  }
-
-  // Check that the loading succeed
-  DALI_TEST_CHECK(succeed);
-  VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
-  END_TEST;
-}
-
-int UtcDaliAnimatedImageLoadingN(void)
-{
-  std::vector<Dali::PixelData> pixelDataList;
-  Dali::Vector<uint32_t>       frameDelayList;
-
-  Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGifNonExist, true);
-  bool                       succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-
-  // Check that the loading failed
-  DALI_TEST_CHECK(!succeed);
-
-  // Check that both pixelDataList and frameDelayList are empty
-  DALI_TEST_EQUALS(pixelDataList.size(), 0u, TEST_LOCATION);
-
-  END_TEST;
-}
-
 int UtcDaliAnimatedImageLoadingGetImageSizeP(void)
 {
   Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_None, true);
index 8f6a118..6f8b3b9 100644 (file)
@@ -60,12 +60,6 @@ AnimatedImageLoading AnimatedImageLoading::DownCast(BaseHandle handle)
 AnimatedImageLoading::~AnimatedImageLoading()
 {
 }
-
-bool AnimatedImageLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
-{
-  return GetImplementation(*this).LoadNextNFrames(frameStartIndex, count, pixelData);
-}
-
 Dali::Devel::PixelBuffer AnimatedImageLoading::LoadFrame(uint32_t frameIndex)
 {
   return GetImplementation(*this).LoadFrame(frameIndex);
index 92d825c..da72e3f 100644 (file)
@@ -100,18 +100,6 @@ public:
   ~AnimatedImageLoading();
 
   /**
-   * @brief Load the next N Frames of the animated image.
-   *
-   * @note This function will load the entire animated image into memory if not already loaded.
-   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
-   * after the previous invocation of this method, or 0 to start.
-   * @param[in] count The number of frames to load
-   * @param[out] pixelData The vector in which to return the frame data
-   * @return True if the frame data was successfully loaded
-   */
-  bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData);
-
-  /**
    * @brief Load a frame of the animated image.
    *
    * @note This function will load the entire animated image into memory if not already loaded.
index d2a624c..5517fc9 100644 (file)
@@ -66,11 +66,6 @@ public:
   ~AnimatedImageLoading() override = default;
 
   /**
-   * @copydoc Dali::AnimatedImageLoading::LoadNextNFrames()
-   */
-  virtual bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) = 0;
-
-  /**
    * @copydoc Dali::AnimatedImageLoading::LoadFrame()
    */
   virtual Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) = 0;
index e72e600..4ca7dd4 100644 (file)
@@ -1442,40 +1442,6 @@ GifLoading::~GifLoading()
   delete mImpl;
 }
 
-bool GifLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
-{
-  int  error;
-  bool ret = false;
-
-  if(DALI_UNLIKELY(!mImpl->LoadGifInformation()))
-  {
-    return false;
-  }
-
-  Mutex::ScopedLock lock(mImpl->mMutex);
-  const int bufferSize = mImpl->imageProperties.w * mImpl->imageProperties.h * sizeof(uint32_t);
-
-  DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count);
-
-  for(int i = 0; i < count; ++i)
-  {
-    auto pixelBuffer = new unsigned char[bufferSize];
-
-    mImpl->loaderInfo.animated.currentFrame = 1 + ((frameStartIndex + i) % mImpl->loaderInfo.animated.frameCount);
-
-    if(ReadNextFrame(mImpl->loaderInfo, mImpl->imageProperties, pixelBuffer, &error))
-    {
-      if(pixelBuffer)
-      {
-        pixelData.push_back(Dali::PixelData::New(pixelBuffer, bufferSize, mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY));
-        ret = true;
-      }
-    }
-  }
-
-  return ret;
-}
-
 Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex)
 {
   int                      error;
index 6797938..2de8ead 100644 (file)
@@ -68,18 +68,6 @@ public:
   ~GifLoading() override;
 
   /**
-   * @brief Load the next N Frames of the gif.
-   *
-   * @note This function will load the entire gif into memory if not already loaded.
-   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
-   * after the previous invocation of this method, or 0 to start.
-   * @param[in] count The number of frames to load
-   * @param[out] pixelData The vector in which to return the frame data
-   * @return True if the frame data was successfully loaded
-   */
-  bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) override;
-
-  /**
    * @brief Load the next Frame of the animated image.
    *
    * @note This function will load the entire animated image into memory if not already loaded.
index 00abbe5..3749127 100644 (file)
  *
  */
 
+// HEADER
 #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
+// INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <dali/integration-api/debug.h>
-#include <cstring>
-#include <memory>
-
-typedef unsigned char WebPByteType;
+#include <dali/internal/imaging/common/webp-loading.h>
 
 namespace Dali
 {
 namespace TizenPlatform
 {
-#ifdef DALI_ANIMATED_WEBP_ENABLED
-bool ReadWebPInformation(FILE* const fp, WebPData& webPData)
-{
-  if(DALI_UNLIKELY(fp == NULL))
-  {
-    return false;
-  }
-
-  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
-  {
-    return false;
-  }
-  WebPDataInit(&webPData);
-  webPData.size = ftell(fp);
-
-  if(DALI_LIKELY(!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)
+namespace
 {
-  free((void*)webPData.bytes);
-  webPData.bytes = nullptr;
-  WebPDataInit(&webPData);
-  if(webPAnimDecoder)
-  {
-    WebPAnimDecoderDelete(webPAnimDecoder);
-  }
+constexpr uint32_t FIRST_FRAME_INDEX = 0u;
 }
 
-#endif
-
 bool LoadWebpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
 {
-  FILE* const fp = input.file;
-  if(DALI_UNLIKELY(fp == NULL))
-  {
-    return false;
-  }
-
-  if(DALI_UNLIKELY(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(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
-  {
-    std::vector<uint8_t> encodedImage;
-    encodedImage.resize(webPSize);
-    size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
-    if(DALI_UNLIKELY(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 = nullptr;
-  WebPAnimInfo     webPAnimInfo;
-  if(ReadWebPInformation(fp, webPData))
+  FILE* const                fp          = input.file;
+  Dali::AnimatedImageLoading webPLoading = Dali::AnimatedImageLoading(Dali::Internal::Adaptor::WebPLoading::New(fp).Get());
+  if(webPLoading)
   {
-    WebPAnimDecoderOptions webPAnimDecoderOptions;
-    WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
-    webPAnimDecoderOptions.color_mode = MODE_RGBA;
-    webPAnimDecoder                   = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
-    if(webPAnimDecoder != nullptr)
+    ImageDimensions imageSize = webPLoading.GetImageSize();
+    if(webPLoading.HasLoadingSucceeded())
     {
-      WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
-      width  = webPAnimInfo.canvas_width;
-      height = webPAnimInfo.canvas_height;
-      ReleaseResource(webPData, webPAnimDecoder);
+      width  = imageSize.GetWidth();
+      height = imageSize.GetHeight();
       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(DALI_UNLIKELY(fp == NULL))
-  {
-    return false;
-  }
-
-  if(DALI_UNLIKELY(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(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
-  {
-    std::vector<uint8_t> encodedImage;
-    encodedImage.resize(webPSize);
-    size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
-    if(DALI_UNLIKELY(readCount != encodedImage.size()))
-    {
-      DALI_LOG_ERROR("WebP image loading failed.\n");
-      return false;
-    }
-
-    int32_t width, height;
-    if(DALI_UNLIKELY(!WebPGetInfo(&encodedImage[0], encodedImage.size(), &width, &height)))
-    {
-      DALI_LOG_ERROR("Cannot retrieve WebP image size information.\n");
-      return false;
-    }
-
-    WebPBitstreamFeatures features;
-    if(DALI_UNLIKELY(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 = nullptr;
-  WebPAnimInfo     webPAnimInfo;
-  if(ReadWebPInformation(fp, webPData))
+  FILE* const                fp          = input.file;
+  Dali::AnimatedImageLoading webPLoading = Dali::AnimatedImageLoading(Dali::Internal::Adaptor::WebPLoading::New(fp).Get());
+  if(webPLoading)
   {
-    WebPAnimDecoderOptions webPAnimDecoderOptions;
-    WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
-    webPAnimDecoderOptions.color_mode = MODE_RGBA;
-    webPAnimDecoder                   = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
-    if(webPAnimDecoder != nullptr)
+    Dali::Devel::PixelBuffer pixelBuffer = webPLoading.LoadFrame(FIRST_FRAME_INDEX);
+    if(pixelBuffer && webPLoading.HasLoadingSucceeded())
     {
-      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);
-      ReleaseResource(webPData, webPAnimDecoder);
+      bitmap = pixelBuffer;
       return true;
     }
   }
-  ReleaseResource(webPData, webPAnimDecoder);
-#endif
-
-  DALI_LOG_ERROR("WebP image loading failed.\n");
   return false;
 }
 
index 23048ce..0cb8932 100644 (file)
@@ -42,8 +42,9 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
 
-typedef unsigned char WebPByteType;
+typedef uint8_t WebPByteType;
 
 namespace Dali
 {
@@ -66,17 +67,33 @@ struct WebPLoading::Impl
 {
 public:
   Impl(const std::string& url, bool isLocalResource)
-  : mUrl(url),
+  : mFile(nullptr),
+    mUrl(url),
     mFrameCount(1u),
     mMutex(),
     mBuffer(nullptr),
     mBufferSize(0u),
     mImageSize(),
     mLoadSucceeded(false),
+    mIsAnimatedImage(false),
     mIsLocalResource(isLocalResource)
   {
   }
 
+  Impl(FILE* const fp)
+  : mFile(fp),
+    mUrl(),
+    mFrameCount(1u),
+    mMutex(),
+    mBuffer(nullptr),
+    mBufferSize(0u),
+    mImageSize(),
+    mLoadSucceeded(false),
+    mIsAnimatedImage(false),
+    mIsLocalResource(true)
+  {
+  }
+
   bool LoadWebPInformation()
   {
     // Block to do not load this file again.
@@ -97,22 +114,29 @@ public:
     if(DALI_LIKELY(ReadWebPInformation()))
     {
 #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))
+      if(mIsAnimatedImage)
       {
-        mImageSize = ImageDimensions(imageWidth, imageHeight);
+        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);
+      }
+#endif
+#ifdef DALI_WEBP_AVAILABLE
+      if(!mIsAnimatedImage)
+      {
+        int32_t imageWidth, imageHeight;
+        if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+        {
+          mImageSize = ImageDimensions(imageWidth, imageHeight);
+        }
       }
 #endif
       mLoadSucceeded = true;
@@ -129,55 +153,71 @@ public:
 
   bool ReadWebPInformation()
   {
-    FILE* fp = nullptr;
-    if(mIsLocalResource)
+    mBufferSize = 0;
+
+    FILE*                                           fp = mFile;
+    std::unique_ptr<Internal::Platform::FileReader> fileReader;
+    Dali::Vector<uint8_t>                           dataBuffer;
+    if(fp == nullptr)
     {
-      Internal::Platform::FileReader fileReader(mUrl);
-      fp = fileReader.GetFile();
-      if(DALI_UNLIKELY(fp == nullptr))
+      if(mIsLocalResource)
       {
-        return false;
+        fileReader = std::make_unique<Internal::Platform::FileReader>(mUrl);
       }
-
-      if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
+      else
       {
-        return false;
+        size_t dataSize;
+        if(DALI_LIKELY(TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE)))
+        {
+          mBufferSize = dataBuffer.Size();
+          if(DALI_LIKELY(mBufferSize > 0U))
+          {
+            // Open a file handle on the memory buffer:
+            fileReader = std::make_unique<Internal::Platform::FileReader>(dataBuffer, mBufferSize);
+          }
+        }
       }
 
-      mBufferSize = ftell(fp);
-      if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
-      {
-        mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
-        mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
-        return true;
-      }
+      fp = fileReader->GetFile();
     }
-    else
-    {
-      // remote file
-      bool                  succeeded;
-      Dali::Vector<uint8_t> dataBuffer;
-      size_t                dataSize;
 
-      succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
-      if(DALI_LIKELY(succeeded))
+    if(DALI_LIKELY(fp != nullptr))
+    {
+      if(DALI_LIKELY(!fseek(fp, 12, SEEK_SET)))
       {
-        mBufferSize = dataBuffer.Size();
-        if(DALI_LIKELY(mBufferSize > 0U))
+        uint8_t mHeaderBuffer[5];
+        fread(mHeaderBuffer, sizeof(WebPByteType), 5, fp);
+        unsigned char VP8X[4]    = {'V', 'P', '8', 'X'};
+        bool          isExtended = true;
+        for(uint32_t i = 0; i < 4; ++i)
         {
-          // Open a file handle on the memory buffer:
-          Internal::Platform::FileReader fileReader(dataBuffer, mBufferSize);
-          fp = fileReader.GetFile();
-          if(DALI_LIKELY(fp != nullptr))
+          if(mHeaderBuffer[i] != VP8X[i])
           {
-            if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
-            {
-              mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
-              mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
-              return true;
-            }
+            isExtended = false;
+            break;
           }
         }
+        if(isExtended)
+        {
+          unsigned char extension = mHeaderBuffer[4];
+          mIsAnimatedImage        = ((extension >> 1) & 1) ? true : false;
+        }
+      }
+
+      if(mBufferSize == 0)
+      {
+        if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
+        {
+          return false;
+        }
+        mBufferSize = ftell(fp);
+      }
+
+      if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
+      {
+        mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
+        mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
+        return true;
       }
     }
     return false;
@@ -186,15 +226,18 @@ public:
   void ReleaseResource()
   {
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-    if(&mWebPData != nullptr)
-    {
-      mWebPData.bytes = nullptr;
-      WebPDataInit(&mWebPData);
-    }
-    if(mWebPAnimDecoder != nullptr)
+    if(mIsAnimatedImage)
     {
-      WebPAnimDecoderDelete(mWebPAnimDecoder);
-      mWebPAnimDecoder = nullptr;
+      if(&mWebPData != nullptr)
+      {
+        mWebPData.bytes = nullptr;
+        WebPDataInit(&mWebPData);
+      }
+      if(mWebPAnimDecoder != nullptr)
+      {
+        WebPAnimDecoderDelete(mWebPAnimDecoder);
+        mWebPAnimDecoder = nullptr;
+      }
     }
 #endif
     if(mBuffer != nullptr)
@@ -216,6 +259,7 @@ public:
     ReleaseResource();
   }
 
+  FILE*                 mFile;
   std::string           mUrl;
   std::vector<uint32_t> mTimeStamp;
   int32_t               mLatestLoadedFrame{INITIAL_INDEX};
@@ -226,6 +270,7 @@ public:
   uint32_t        mBufferSize;
   ImageDimensions mImageSize;
   bool            mLoadSucceeded;
+  bool            mIsAnimatedImage;
   bool            mIsLocalResource;
 
 #ifdef DALI_ANIMATED_WEBP_ENABLED
@@ -244,34 +289,27 @@ AnimatedImageLoadingPtr WebPLoading::New(const std::string& url, bool isLocalRes
   return AnimatedImageLoadingPtr(new WebPLoading(url, isLocalResource));
 }
 
+AnimatedImageLoadingPtr WebPLoading::New(FILE* const fp)
+{
+#ifndef DALI_ANIMATED_WEBP_ENABLED
+  DALI_LOG_ERROR("The system does not support Animated WebP format.\n");
+#endif
+  return AnimatedImageLoadingPtr(new WebPLoading(fp));
+}
+
 WebPLoading::WebPLoading(const std::string& url, bool isLocalResource)
 : mImpl(new WebPLoading::Impl(url, isLocalResource))
 {
 }
 
-WebPLoading::~WebPLoading()
+WebPLoading::WebPLoading(FILE* const fp)
+: mImpl(new WebPLoading::Impl(fp))
 {
-  delete mImpl;
 }
 
-bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
+WebPLoading::~WebPLoading()
 {
-  for(int i = 0; i < count; ++i)
-  {
-    Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
-    if(DALI_UNLIKELY(!pixelBuffer))
-    {
-      return false;
-    }
-
-    Dali::PixelData imageData = Devel::PixelBuffer::Convert(pixelBuffer);
-    pixelData.push_back(imageData);
-  }
-  if(DALI_UNLIKELY(pixelData.size() != static_cast<uint32_t>(count)))
-  {
-    return false;
-  }
-  return true;
+  delete mImpl;
 }
 
 Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
@@ -283,6 +321,7 @@ Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
   {
     if(DALI_UNLIKELY(!mImpl->LoadWebPInformation()))
     {
+      mImpl->ReleaseResource();
       return pixelBuffer;
     }
   }
@@ -290,69 +329,69 @@ Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
   // 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)
+  if(!mImpl->mIsAnimatedImage)
   {
     int32_t width, height;
-    if(DALI_UNLIKELY(!WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height)))
-    {
-      return pixelBuffer;
-    }
-
-    WebPBitstreamFeatures features;
-    if(DALI_UNLIKELY(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features)))
-    {
-      return 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)
+    if(DALI_LIKELY(WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height)))
     {
-      frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
-    }
-    else
-    {
-      frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
-    }
+      WebPBitstreamFeatures features;
+      if(DALI_LIKELY(VP8_STATUS_NOT_ENOUGH_DATA != WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features)))
+      {
+        uint32_t channelNumber = (features.has_alpha) ? 4 : 3;
+        uint8_t* frameBuffer   = nullptr;
+        if(channelNumber == 4)
+        {
+          frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+        }
+        else
+        {
+          frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+        }
 
-    if(frameBuffer != nullptr)
-    {
-      const int32_t imageBufferSize = width * height * sizeof(uint8_t) * channelNumber;
-      memcpy(pixelBuffer.GetBuffer(), frameBuffer, imageBufferSize);
-      free((void*)frameBuffer);
+        if(frameBuffer != nullptr)
+        {
+          Pixel::Format                     pixelFormat = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
+          int32_t                           bufferSize  = width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat);
+          Internal::Adaptor::PixelBufferPtr internal =
+            Internal::Adaptor::PixelBuffer::New(frameBuffer, bufferSize, width, height, width, pixelFormat);
+          pixelBuffer = Devel::PixelBuffer(internal.Get());
+        }
+      }
     }
+    // The single frame resource should be released after loading.
     mImpl->ReleaseResource();
-    return pixelBuffer;
   }
 #endif
 
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-  Mutex::ScopedLock lock(mImpl->mMutex);
-  if(DALI_UNLIKELY(frameIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded))
+  if(mImpl->mIsAnimatedImage && mImpl->mBuffer != nullptr)
   {
-    return pixelBuffer;
-  }
-
-  DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+    Mutex::ScopedLock lock(mImpl->mMutex);
+    if(DALI_LIKELY(frameIndex < mImpl->mWebPAnimInfo.frame_count && mImpl->mLoadSucceeded))
+    {
+      DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
 
-  if(mImpl->mPreLoadedFrame && mImpl->mLatestLoadedFrame == static_cast<int32_t>(frameIndex))
-  {
-    pixelBuffer = mImpl->mPreLoadedFrame;
-  }
-  else
-  {
-    pixelBuffer = DecodeFrame(frameIndex);
-  }
-  mImpl->mPreLoadedFrame.Reset();
+      if(mImpl->mPreLoadedFrame && mImpl->mLatestLoadedFrame == static_cast<int32_t>(frameIndex))
+      {
+        pixelBuffer = mImpl->mPreLoadedFrame;
+      }
+      else
+      {
+        pixelBuffer = DecodeFrame(frameIndex);
+      }
+      mImpl->mPreLoadedFrame.Reset();
 
-  // If time stamp of next frame is unknown, load a frame more to know it.
-  if(frameIndex + 1 < mImpl->mWebPAnimInfo.frame_count && mImpl->mTimeStamp[frameIndex + 1] == 0u)
-  {
-    mImpl->mPreLoadedFrame = DecodeFrame(frameIndex + 1);
+      // If time stamp of next frame is unknown, load a frame more to know it.
+      if(frameIndex + 1 < mImpl->mWebPAnimInfo.frame_count && mImpl->mTimeStamp[frameIndex + 1] == 0u)
+      {
+        mImpl->mPreLoadedFrame = DecodeFrame(frameIndex + 1);
+      }
+    }
+    else
+    {
+      mImpl->ReleaseResource();
+    }
   }
-
 #endif
   return pixelBuffer;
 }
@@ -368,12 +407,13 @@ Dali::Devel::PixelBuffer WebPLoading::DecodeFrame(uint32_t frameIndex)
   }
 
   uint8_t* frameBuffer = nullptr;
-  int32_t timestamp = 0u;
+  int32_t  timestamp   = 0u;
   for(; mImpl->mLatestLoadedFrame < static_cast<int32_t>(frameIndex);)
   {
     WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
     mImpl->mTimeStamp[++mImpl->mLatestLoadedFrame] = timestamp;
   }
+
   if(frameBuffer != nullptr)
   {
     const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
index f3428e6..5a232fb 100644 (file)
@@ -57,6 +57,13 @@ public:
   static AnimatedImageLoadingPtr New(const std::string& url, bool isLocalResource);
 
   /**
+   * Create a WebPLoading with the given url and resourceType.
+   * @param[in] fp The file pointer to be load.
+   * @return A newly created WebPLoading.
+   */
+  static AnimatedImageLoadingPtr New(FILE* const fp);
+
+  /**
    * @brief Constructor
    *
    * Construct a Loader with the given URL
@@ -66,21 +73,17 @@ public:
   WebPLoading(const std::string& url, bool isLocalResource);
 
   /**
-   * @brief Destructor
+   * @brief Constructor
+   *
+   * Construct a Loader with the given URL
+   * @param[in] fp The file pointer to be load.
    */
-  ~WebPLoading() override;
+  WebPLoading(FILE* const fp);
 
   /**
-   * @brief Load the next N Frames of the webp.
-   *
-   * @note This function will load the entire webp into memory if not already loaded.
-   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
-   * after the previous invocation of this method, or 0 to start.
-   * @param[in] count The number of frames to load
-   * @param[out] pixelData The vector in which to return the frame data
-   * @return True if the frame data was successfully loaded
+   * @brief Destructor
    */
-  bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) override;
+  ~WebPLoading() override;
 
   /**
    * @brief Load the next Frame of the animated image.