2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/imaging/common/webp-loading.h>
22 #ifdef DALI_WEBP_AVAILABLE
23 #include <webp/decode.h>
24 #include <webp/demux.h>
26 #if WEBP_DEMUX_ABI_VERSION > 0x0101
27 #define DALI_WEBP_ENABLED 1
31 #include <dali/integration-api/debug.h>
32 #include <dali/public-api/images/pixel-data.h>
34 #include <dali/internal/imaging/common/file-download.h>
35 #include <dali/internal/system/common/file-reader.h>
38 #include <sys/types.h>
42 typedef unsigned char WebPByteType;
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gWebPLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GIF_LOADING");
56 constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
60 struct WebPLoading::Impl
63 Impl(const std::string& url, bool isLocalResource)
66 #ifdef DALI_WEBP_ENABLED
67 if(ReadWebPInformation(isLocalResource))
69 WebPAnimDecoderOptions webPAnimDecoderOptions;
70 WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
71 webPAnimDecoderOptions.color_mode = MODE_RGBA;
72 mWebPAnimDecoder = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
73 WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
74 mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
79 bool ReadWebPInformation(bool isLocalResource)
81 #ifdef DALI_WEBP_ENABLED
82 WebPDataInit(&mWebPData);
85 Internal::Platform::FileReader fileReader(mUrl);
86 FILE* fp = fileReader.GetFile();
92 if(fseek(fp, 0, SEEK_END) <= -1)
97 mWebPData.size = ftell(fp);
98 if((!fseek(fp, 0, SEEK_SET)))
100 unsigned char* WebPDataBuffer;
101 WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mWebPData.size));
102 mWebPData.size = fread(WebPDataBuffer, sizeof(WebPByteType), mWebPData.size, fp);
103 mWebPData.bytes = WebPDataBuffer;
114 Dali::Vector<uint8_t> dataBuffer;
117 succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
120 size_t blobSize = dataBuffer.Size();
123 // Open a file handle on the memory buffer:
124 Dali::Internal::Platform::FileReader fileReader(dataBuffer, blobSize);
125 FILE* const fp = fileReader.GetFile();
128 if((!fseek(fp, 0, SEEK_SET)))
130 unsigned char* WebPDataBuffer;
131 WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * blobSize));
132 mWebPData.size = fread(WebPDataBuffer, sizeof(WebPByteType), mWebPData.size, fp);
133 mWebPData.bytes = WebPDataBuffer;
137 DALI_LOG_ERROR("Error seeking within file\n");
142 DALI_LOG_ERROR("Error reading file\n");
153 // Moveable but not copyable
155 Impl(const Impl&) = delete;
156 Impl& operator=(const Impl&) = delete;
157 Impl(Impl&&) = default;
158 Impl& operator=(Impl&&) = default;
162 #ifdef DALI_WEBP_ENABLED
163 if(&mWebPData != NULL)
165 free((void*)mWebPData.bytes);
166 mWebPData.bytes = nullptr;
167 WebPDataInit(&mWebPData);
171 WebPAnimDecoderDelete(mWebPAnimDecoder);
177 std::vector<uint32_t> mTimeStamp;
178 uint32_t mLoadingFrame{0};
180 #ifdef DALI_WEBP_ENABLED
181 WebPData mWebPData{0};
182 WebPAnimDecoder* mWebPAnimDecoder{nullptr};
183 WebPAnimInfo mWebPAnimInfo{0};
187 AnimatedImageLoadingPtr WebPLoading::New(const std::string& url, bool isLocalResource)
189 #ifndef DALI_WEBP_ENABLED
190 DALI_LOG_ERROR("The system does not support Animated WebP format.\n");
192 return AnimatedImageLoadingPtr(new WebPLoading(url, isLocalResource));
195 WebPLoading::WebPLoading(const std::string& url, bool isLocalResource)
196 : mImpl(new WebPLoading::Impl(url, isLocalResource))
200 WebPLoading::~WebPLoading()
205 bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
207 #ifdef DALI_WEBP_ENABLED
208 if(frameStartIndex >= mImpl->mWebPAnimInfo.frame_count)
213 DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count);
215 if(mImpl->mLoadingFrame > frameStartIndex)
217 mImpl->mLoadingFrame = 0;
218 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
221 for(; mImpl->mLoadingFrame < frameStartIndex; ++mImpl->mLoadingFrame)
223 uint8_t* frameBuffer;
225 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
226 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
229 for(int i = 0; i < count; ++i)
231 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
232 uint8_t* frameBuffer;
234 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
236 auto pixelBuffer = new uint8_t[bufferSize];
237 memcpy(pixelBuffer, frameBuffer, bufferSize);
238 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
242 pixelData.push_back(Dali::PixelData::New(pixelBuffer, bufferSize, mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY));
245 mImpl->mLoadingFrame++;
246 if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
248 mImpl->mLoadingFrame = 0;
249 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
259 Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
261 Dali::Devel::PixelBuffer pixelBuffer;
262 #ifdef DALI_WEBP_ENABLED
263 if(frameIndex >= mImpl->mWebPAnimInfo.frame_count)
268 DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameIndex:%d )\n", frameIndex);
270 if(mImpl->mLoadingFrame > frameIndex)
272 mImpl->mLoadingFrame = 0;
273 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
276 for(; mImpl->mLoadingFrame < frameIndex; ++mImpl->mLoadingFrame)
278 uint8_t* frameBuffer;
280 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
281 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
284 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
285 uint8_t* frameBuffer;
287 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
289 pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
290 memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
291 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
293 mImpl->mLoadingFrame++;
294 if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
296 mImpl->mLoadingFrame = 0;
297 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
303 ImageDimensions WebPLoading::GetImageSize() const
305 #ifdef DALI_WEBP_ENABLED
306 return ImageDimensions(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height);
308 return ImageDimensions();
312 uint32_t WebPLoading::GetImageCount() const
314 #ifdef DALI_WEBP_ENABLED
315 return mImpl->mWebPAnimInfo.frame_count;
321 uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
323 // If frameIndex is above the value of ImageCount or current frame is not loading yet, return 0u.
324 if(frameIndex >= GetImageCount() || (frameIndex > 0 && mImpl->mTimeStamp[frameIndex - 1] > mImpl->mTimeStamp[frameIndex]))
332 return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
334 return mImpl->mTimeStamp[frameIndex];
338 std::string WebPLoading::GetUrl() const
343 } // namespace Adaptor
345 } // namespace Internal