public:
Impl(const std::string& url, bool isLocalResource)
: mUrl(url),
- mLoadSucceeded(true),
+ mLoadSucceeded(false),
mMutex()
{
loaderInfo.gifAccessor = nullptr;
- int error;
loaderInfo.fileData.fileName = mUrl.c_str();
loaderInfo.fileData.isLocalResource = isLocalResource;
+ }
+ bool LoadGifInformation()
+ {
+ int error;
mLoadSucceeded = ReadHeader(loaderInfo, imageProperties, &error);
+ return mLoadSucceeded;
}
// Moveable but not copyable
Mutex::ScopedLock lock(mImpl->mMutex);
if(!mImpl->mLoadSucceeded)
{
- return false;
+ if(!mImpl->LoadGifInformation())
+ {
+ return false;
+ }
}
const int bufferSize = mImpl->imageProperties.w * mImpl->imageProperties.h * sizeof(uint32_t);
{
int error;
Dali::Devel::PixelBuffer pixelBuffer;
- if(!mImpl->mLoadSucceeded)
- {
- return pixelBuffer;
- }
Mutex::ScopedLock lock(mImpl->mMutex);
DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+ // If Gif file is still not loaded, Load the information.
+ if(!mImpl->mLoadSucceeded)
+ {
+ if(!mImpl->LoadGifInformation())
+ {
+ return pixelBuffer;
+ }
+ }
+
pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888);
mImpl->loaderInfo.animated.currentFrame = 1 + (frameIndex % mImpl->loaderInfo.animated.frameCount);
ImageDimensions GifLoading::GetImageSize() const
{
+ if(!mImpl->mLoadSucceeded)
+ {
+ DALI_LOG_ERROR("Gif file is still not loaded, this image size could not be correct value.\n");
+ }
return ImageDimensions(mImpl->imageProperties.w, mImpl->imageProperties.h);
}
uint32_t GifLoading::GetImageCount() const
{
+ if(!mImpl->mLoadSucceeded)
+ {
+ DALI_LOG_ERROR("Gif file is still not loaded, this image count could not be correct value.\n");
+ }
return mImpl->loaderInfo.animated.frameCount;
}
uint32_t GifLoading::GetFrameInterval(uint32_t frameIndex) const
{
+ if(!mImpl->mLoadSucceeded)
+ {
+ DALI_LOG_ERROR("Gif file is still not loaded, this frame interval could not be correct value.\n");
+ }
return mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
}
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
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;
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();
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
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
};
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))
{
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
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))
+ {
+ 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);
+ }
+
+#endif
+ return pixelBuffer;
+}
+
+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);
}
- for(; mImpl->mLoadingFrame < frameIndex; ++mImpl->mLoadingFrame)
+ uint8_t* frameBuffer;
+ int32_t timestamp;
+ for(; mImpl->mLatestLoadedFrame < static_cast<int32_t>(frameIndex);)
{
- uint8_t* frameBuffer;
- int timestamp;
WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
- mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+ mImpl->mTimeStamp[++mImpl->mLatestLoadedFrame] = timestamp;
}
-
const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
- uint8_t* frameBuffer;
- int timestamp;
- WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
-
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;
- mImpl->mLoadingFrame++;
- if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
- {
- mImpl->mLoadingFrame = 0;
- WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
- }
#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);
}
}