summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
3c45923)
- Open file in the first call to request frame.
- In case of WebP, load one more frame in the first loop to compute exact time interval.
Change-Id: I03a3b79af278c64d7911d4c65ad300bd09d76bfd
Signed-off-by: seungho <sbsh.baek@samsung.com>
*
* @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
* @param[out] prop A ImageProperties structure for storing information about GIF data.
*
* @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
* @param[out] prop A ImageProperties structure for storing information about GIF data.
- * @param[out] error Error code
* @return The true or false whether reading was successful or not.
*/
bool ReadHeader(LoaderInfo& loaderInfo,
* @return The true or false whether reading was successful or not.
*/
bool ReadHeader(LoaderInfo& loaderInfo,
- ImageProperties& prop, //output struct
- int* error)
{
GifAnimationData& animated = loaderInfo.animated;
GifCachedColorData& cachedColor = loaderInfo.cachedColor;
{
GifAnimationData& animated = loaderInfo.animated;
GifCachedColorData& cachedColor = loaderInfo.cachedColor;
cachedColor.globalCachedColor[i] = PixelLookup(colorMap, i);
}
}
cachedColor.globalCachedColor[i] = PixelLookup(colorMap, i);
}
}
-
- // no errors in header scan etc. so set err and return value
- *error = 0;
public:
Impl(const std::string& url, bool isLocalResource)
: mUrl(url),
public:
Impl(const std::string& url, bool isLocalResource)
: mUrl(url),
mMutex()
{
loaderInfo.gifAccessor = nullptr;
mMutex()
{
loaderInfo.gifAccessor = nullptr;
loaderInfo.fileData.fileName = mUrl.c_str();
loaderInfo.fileData.isLocalResource = isLocalResource;
loaderInfo.fileData.fileName = mUrl.c_str();
loaderInfo.fileData.isLocalResource = isLocalResource;
+ }
+
+ bool LoadGifInformation()
+ {
+ // Block to do not load this file again.
+ Mutex::ScopedLock lock(mMutex);
+ if(DALI_LIKELY(mLoadSucceeded))
+ {
+ return mLoadSucceeded;
+ }
- mLoadSucceeded = ReadHeader(loaderInfo, imageProperties, &error);
+ mLoadSucceeded = ReadHeader(loaderInfo, imageProperties);
+ return mLoadSucceeded;
}
// Moveable but not copyable
}
// Moveable but not copyable
int error;
bool ret = false;
int error;
bool ret = false;
- Mutex::ScopedLock lock(mImpl->mMutex);
- if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ if(DALI_UNLIKELY(!mImpl->LoadGifInformation()))
+ 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);
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);
{
int error;
Dali::Devel::PixelBuffer pixelBuffer;
{
int error;
Dali::Devel::PixelBuffer pixelBuffer;
- if(!mImpl->mLoadSucceeded)
+
+ DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+
+ // If Gif file is still not loaded, Load the information.
+ if(DALI_UNLIKELY(!mImpl->LoadGifInformation()))
{
return pixelBuffer;
}
Mutex::ScopedLock lock(mImpl->mMutex);
{
return pixelBuffer;
}
Mutex::ScopedLock lock(mImpl->mMutex);
- DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
-
pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888);
mImpl->loaderInfo.animated.currentFrame = 1 + (frameIndex % mImpl->loaderInfo.animated.frameCount);
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
{
ImageDimensions GifLoading::GetImageSize() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadGifInformation();
+ }
return ImageDimensions(mImpl->imageProperties.w, mImpl->imageProperties.h);
}
uint32_t GifLoading::GetImageCount() const
{
return ImageDimensions(mImpl->imageProperties.w, mImpl->imageProperties.h);
}
uint32_t GifLoading::GetImageCount() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadGifInformation();
+ }
return mImpl->loaderInfo.animated.frameCount;
}
uint32_t GifLoading::GetFrameInterval(uint32_t frameIndex) const
{
return mImpl->loaderInfo.animated.frameCount;
}
uint32_t GifLoading::GetFrameInterval(uint32_t frameIndex) const
{
- return mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadGifInformation();
+ }
+
+ uint32_t interval = 0u;
+ if(DALI_LIKELY(mImpl->mLoadSucceeded))
+ {
+ interval = mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+ }
+ return interval;
}
std::string GifLoading::GetUrl() const
}
std::string GifLoading::GetUrl() const
Debug::Filter* gWebPLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GIF_LOADING");
#endif
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;
mBuffer(nullptr),
mBufferSize(0u),
mImageSize(),
mBuffer(nullptr),
mBufferSize(0u),
mImageSize(),
+ mLoadSucceeded(false),
+ mIsLocalResource(isLocalResource)
+ }
+
+ bool LoadWebPInformation()
+ {
+ // Block to do not load this file again.
+ Mutex::ScopedLock lock(mMutex);
+ if(DALI_UNLIKELY(mLoadSucceeded))
+ {
+ return mLoadSucceeded;
+ }
+
+#ifndef DALI_WEBP_AVAILABLE
+ // If the system doesn't support webp, loading will be failed.
+ mFrameCount = 0u;
+ mLoadSucceeded = false;
+ return mLoadSucceeded;
+#endif
+
// mFrameCount will be 1 if the input image is non-animated image or animated image with single frame.
// mFrameCount will be 1 if the input image is non-animated image or animated image with single frame.
- if(DALI_LIKELY(ReadWebPInformation(isLocalResource)))
+ if(DALI_LIKELY(ReadWebPInformation()))
{
#ifdef DALI_ANIMATED_WEBP_ENABLED
WebPDataInit(&mWebPData);
{
#ifdef DALI_ANIMATED_WEBP_ENABLED
WebPDataInit(&mWebPData);
mImageSize = ImageDimensions(imageWidth, imageHeight);
}
#endif
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
mLoadSucceeded = false;
DALI_LOG_ERROR("Image loading failed for: \"%s\".\n", mUrl.c_str());
}
mLoadSucceeded = false;
DALI_LOG_ERROR("Image loading failed for: \"%s\".\n", mUrl.c_str());
}
+
+ return mLoadSucceeded;
- bool ReadWebPInformation(bool isLocalResource)
+ bool ReadWebPInformation()
{
Internal::Platform::FileReader fileReader(mUrl);
fp = fileReader.GetFile();
{
Internal::Platform::FileReader fileReader(mUrl);
fp = fileReader.GetFile();
std::string mUrl;
std::vector<uint32_t> mTimeStamp;
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 mFrameCount;
Mutex mMutex;
// For the case the system doesn't support DALI_ANIMATED_WEBP_ENABLED
uint32_t mBufferSize;
ImageDimensions mImageSize;
bool mLoadSucceeded;
uint32_t mBufferSize;
ImageDimensions mImageSize;
bool mLoadSucceeded;
#ifdef DALI_ANIMATED_WEBP_ENABLED
#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{};
for(int i = 0; i < count; ++i)
{
Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
for(int i = 0; i < count; ++i)
{
Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
- Dali::PixelData imageData = Devel::PixelBuffer::Convert(pixelBuffer);
+ 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)))
pixelData.push_back(imageData);
}
if(DALI_UNLIKELY(pixelData.size() != static_cast<uint32_t>(count)))
{
Dali::Devel::PixelBuffer pixelBuffer;
{
Dali::Devel::PixelBuffer pixelBuffer;
+ // If WebP file is still not loaded, Load the information.
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ if(DALI_UNLIKELY(!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
// 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);
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->mLoadingFrame = 0;
+ 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->mLatestLoadedFrame = INITIAL_INDEX;
WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
}
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);
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);
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);
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
{
#endif
return pixelBuffer;
}
ImageDimensions WebPLoading::GetImageSize() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadWebPInformation();
+ }
return mImpl->mImageSize;
}
uint32_t WebPLoading::GetImageCount() const
{
return mImpl->mImageSize;
}
uint32_t WebPLoading::GetImageCount() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadWebPInformation();
+ }
return mImpl->mFrameCount;
}
uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
{
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(DALI_UNLIKELY(!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.");
+ 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(DALI_UNLIKELY(interval < 0))
- return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+ DALI_LOG_ERROR("This interval value is not correct, because the frame still hasn't ever been decoded.");
+ return 0u;
- return mImpl->mTimeStamp[frameIndex];
+ return static_cast<uint32_t>(interval);
* @param[in] frameIndex The frame counter to load. Will usually be the next frame.
* @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
*/
* @param[in] frameIndex The frame counter to load. Will usually be the next frame.
* @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
*/
Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) override;
/**
Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) override;
/**
*
* @note The frame is needed to be loaded before this function is called.
*
*
* @note The frame is needed to be loaded before this function is called.
*
- * @return The time interval of the frame(microsecond).
+ * @return The time interval between frameIndex and frameIndex + 1(microsecond).
*/
uint32_t GetFrameInterval(uint32_t frameIndex) const override;
*/
uint32_t GetFrameInterval(uint32_t frameIndex) const override;
bool HasLoadingSucceeded() const override;
private:
bool HasLoadingSucceeded() const override;
private:
+ /**
+ * @brief Decode Frame of the animated image.
+ *
+ * @param[in] frameIndex The frame counter to load. Will usually be the next frame.
+ * @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
+ */
+ Dali::Devel::PixelBuffer DecodeFrame(uint32_t frameIndex);
+
+private:
struct Impl;
Impl* mImpl;
};
struct Impl;
Impl* mImpl;
};