[Tizen] Set the LoadSuccessflag to false after ReleaseResource() is called
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / webp-loading.cpp
index dc758fa..8efdc5b 100644 (file)
@@ -57,7 +57,8 @@ namespace
 Debug::Filter* gWebPLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GIF_LOADING");
 #endif
 
-constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
+static constexpr int32_t INITIAL_INDEX               = -1;
+static constexpr size_t  MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
 
 } // namespace
 
@@ -71,11 +72,17 @@ public:
     mBuffer(nullptr),
     mBufferSize(0u),
     mImageSize(),
-    mLoadSucceeded(true)
+    mLoadSucceeded(false),
+    mIsLocalResource(isLocalResource)
+  {
+  }
+
+  bool LoadWebPInformation()
   {
     // mFrameCount will be 1 if the input image is non-animated image or animated image with single frame.
-    if(ReadWebPInformation(isLocalResource))
+    if(ReadWebPInformation())
     {
+      mLoadSucceeded = true;
 #ifdef DALI_ANIMATED_WEBP_ENABLED
       WebPDataInit(&mWebPData);
       mWebPData.size  = mBufferSize;
@@ -107,16 +114,18 @@ public:
       mLoadSucceeded = false;
       DALI_LOG_ERROR("Image loading failed for: \"%s\".\n", mUrl.c_str());
     }
+
+    return mLoadSucceeded;
   }
 
-  bool ReadWebPInformation(bool isLocalResource)
+  bool ReadWebPInformation()
   {
     FILE* fp = nullptr;
-    if(isLocalResource)
+    if(mIsLocalResource)
     {
       Internal::Platform::FileReader fileReader(mUrl);
       fp = fileReader.GetFile();
-      if(fp == NULL)
+      if(fp == nullptr)
       {
         return false;
       }
@@ -165,33 +174,45 @@ public:
     return false;
   }
 
-  // Moveable but not copyable
-
-  Impl(const Impl&) = delete;
-  Impl& operator=(const Impl&) = delete;
-  Impl(Impl&&)                 = default;
-  Impl& operator=(Impl&&) = default;
-
-  ~Impl()
+  void ReleaseResource()
   {
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-    if(&mWebPData != NULL)
+    if(&mWebPData != nullptr)
     {
       mWebPData.bytes = nullptr;
       WebPDataInit(&mWebPData);
     }
-    if(mWebPAnimDecoder)
+    if(mWebPAnimDecoder != nullptr)
     {
       WebPAnimDecoderDelete(mWebPAnimDecoder);
+      mWebPAnimDecoder = nullptr;
     }
 #endif
-    free((void*)mBuffer);
-    mBuffer = nullptr;
+    if(mBuffer != nullptr)
+    {
+      free((void*)mBuffer);
+      mBuffer = nullptr;
+    }
+
+    // Set the flag so that webp information can be reloaded when visual is re-attached to scene.
+    mLoadSucceeded = false;
+  }
+
+  // Moveable but not copyable
+
+  Impl(const Impl&) = delete;
+  Impl& operator=(const Impl&) = delete;
+  Impl(Impl&&)                 = default;
+  Impl& operator=(Impl&&) = default;
+
+  ~Impl()
+  {
+    ReleaseResource();
   }
 
   std::string           mUrl;
   std::vector<uint32_t> mTimeStamp;
-  uint32_t              mLoadingFrame{0};
+  int32_t               mLatestLoadedFrame{INITIAL_INDEX};
   uint32_t              mFrameCount;
   Mutex                 mMutex;
   // For the case the system doesn't support DALI_ANIMATED_WEBP_ENABLED
@@ -199,11 +220,13 @@ public:
   uint32_t        mBufferSize;
   ImageDimensions mImageSize;
   bool            mLoadSucceeded;
+  bool            mIsLocalResource;
 
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-  WebPData         mWebPData{0};
-  WebPAnimDecoder* mWebPAnimDecoder{nullptr};
-  WebPAnimInfo     mWebPAnimInfo{0};
+  WebPData                 mWebPData{0};
+  WebPAnimDecoder*         mWebPAnimDecoder{nullptr};
+  WebPAnimInfo             mWebPAnimInfo{0};
+  Dali::Devel::PixelBuffer mPreLoadedFrame{};
 #endif
 };
 
@@ -230,7 +253,12 @@ bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vect
   for(int i = 0; i < count; ++i)
   {
     Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
-    Dali::PixelData          imageData   = Devel::PixelBuffer::Convert(pixelBuffer);
+    if(!pixelBuffer)
+    {
+      return false;
+    }
+
+    Dali::PixelData imageData = Devel::PixelBuffer::Convert(pixelBuffer);
     pixelData.push_back(imageData);
   }
   if(pixelData.size() != static_cast<uint32_t>(count))
@@ -244,6 +272,15 @@ Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
 {
   Dali::Devel::PixelBuffer pixelBuffer;
 
+  // If WebP file is still not loaded, Load the information.
+  if(!mImpl->mLoadSucceeded)
+  {
+    if(!mImpl->LoadWebPInformation())
+    {
+      return pixelBuffer;
+    }
+  }
+
   // 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
@@ -279,8 +316,10 @@ Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
       const int32_t imageBufferSize = width * height * sizeof(uint8_t) * channelNumber;
       memcpy(pixelBuffer.GetBuffer(), frameBuffer, imageBufferSize);
       free((void*)frameBuffer);
-      return pixelBuffer;
     }
+    mImpl->ReleaseResource();
+
+    return pixelBuffer;
   }
 #endif
 
@@ -293,63 +332,106 @@ Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
 
   DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
 
-  if(mImpl->mLoadingFrame > frameIndex)
+  if(mImpl->mPreLoadedFrame && mImpl->mLatestLoadedFrame == static_cast<int32_t>(frameIndex))
   {
-    mImpl->mLoadingFrame = 0;
-    WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
+    pixelBuffer = mImpl->mPreLoadedFrame;
   }
-
-  for(; mImpl->mLoadingFrame < frameIndex; ++mImpl->mLoadingFrame)
+  else
   {
-    uint8_t* frameBuffer;
-    int      timestamp;
-    WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
-    mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+    pixelBuffer = DecodeFrame(frameIndex);
   }
+  mImpl->mPreLoadedFrame.Reset();
 
-  const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
-  uint8_t*  frameBuffer;
-  int       timestamp;
-  WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
+  // 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);
+  }
 
-  pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
-  memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
-  mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+#endif
+  return pixelBuffer;
+}
 
-  mImpl->mLoadingFrame++;
-  if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
+Dali::Devel::PixelBuffer WebPLoading::DecodeFrame(uint32_t frameIndex)
+{
+  Dali::Devel::PixelBuffer pixelBuffer;
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+  if(mImpl->mLatestLoadedFrame >= static_cast<int32_t>(frameIndex))
   {
-    mImpl->mLoadingFrame = 0;
+    mImpl->mLatestLoadedFrame = INITIAL_INDEX;
     WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
   }
+
+  int32_t timestamp;
+  uint8_t* frameBuffer = nullptr;
+  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);
+    pixelBuffer          = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
+    memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
+  }
+
 #endif
   return pixelBuffer;
 }
 
 ImageDimensions WebPLoading::GetImageSize() const
 {
+  if(!mImpl->mLoadSucceeded)
+  {
+    DALI_LOG_ERROR("WebP file is still not loaded, this image size could not be correct value.\n");
+  }
   return mImpl->mImageSize;
 }
 
 uint32_t WebPLoading::GetImageCount() const
 {
+  if(!mImpl->mLoadSucceeded)
+  {
+    DALI_LOG_ERROR("WebP file is still not loaded, this image count could not be correct value.\n");
+  }
   return mImpl->mFrameCount;
 }
 
 uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
 {
-  // If frameIndex is above the value of ImageCount or current frame is not loading yet, return 0u.
-  if(frameIndex >= GetImageCount() || (frameIndex > 0 && mImpl->mTimeStamp[frameIndex - 1] > mImpl->mTimeStamp[frameIndex]))
+  if(!mImpl->mLoadSucceeded)
+  {
+    DALI_LOG_ERROR("WebP file is still not loaded, this frame interval could not be correct value.\n");
+  }
+  if(frameIndex >= GetImageCount())
   {
+    DALI_LOG_ERROR("Input frameIndex exceeded frame count of the WebP.");
     return 0u;
   }
   else
   {
-    if(frameIndex > 0)
+    int32_t interval = 0u;
+    if(GetImageCount() == 1u)
+    {
+      return 0u;
+    }
+    else if(frameIndex + 1 == GetImageCount())
+    {
+      // For the interval between last frame and first frame, use last interval again.
+      interval = mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+    }
+    else
+    {
+      interval = mImpl->mTimeStamp[frameIndex + 1] - mImpl->mTimeStamp[frameIndex];
+    }
+
+    if(interval < 0)
     {
-      return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+      return 0u;
     }
-    return mImpl->mTimeStamp[frameIndex];
+    return static_cast<uint32_t>(interval);
   }
 }