{
// 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)
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);
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);
~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.
~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;
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;
~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.
*
*/
+// 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, ×tamp);
-
- 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;
}
// 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
{
{
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.
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;
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;
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)
ReleaseResource();
}
+ FILE* mFile;
std::string mUrl;
std::vector<uint32_t> mTimeStamp;
int32_t mLatestLoadedFrame{INITIAL_INDEX};
uint32_t mBufferSize;
ImageDimensions mImageSize;
bool mLoadSucceeded;
+ bool mIsAnimatedImage;
bool mIsLocalResource;
#ifdef DALI_ANIMATED_WEBP_ENABLED
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)
{
if(DALI_UNLIKELY(!mImpl->LoadWebPInformation()))
{
+ mImpl->ReleaseResource();
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
- 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;
}
}
uint8_t* frameBuffer = nullptr;
- int32_t timestamp = 0u;
+ int32_t timestamp = 0u;
for(; mImpl->mLatestLoadedFrame < static_cast<int32_t>(frameIndex);)
{
WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
mImpl->mTimeStamp[++mImpl->mLatestLoadedFrame] = timestamp;
}
+
if(frameBuffer != nullptr)
{
const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
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
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.