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)
67 #ifdef DALI_WEBP_ENABLED
68 if(ReadWebPInformation(isLocalResource))
70 WebPAnimDecoderOptions webPAnimDecoderOptions;
71 WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
72 webPAnimDecoderOptions.color_mode = MODE_RGBA;
73 mWebPAnimDecoder = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
74 WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
75 mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
79 mLoadSucceeded = false;
84 bool ReadWebPInformation(bool isLocalResource)
86 #ifdef DALI_WEBP_ENABLED
87 WebPDataInit(&mWebPData);
90 Internal::Platform::FileReader fileReader(mUrl);
91 FILE* fp = fileReader.GetFile();
97 if(fseek(fp, 0, SEEK_END) <= -1)
102 mWebPData.size = ftell(fp);
103 if((!fseek(fp, 0, SEEK_SET)))
105 unsigned char* WebPDataBuffer;
106 WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mWebPData.size));
107 mWebPData.size = fread(WebPDataBuffer, sizeof(WebPByteType), mWebPData.size, fp);
108 mWebPData.bytes = WebPDataBuffer;
119 Dali::Vector<uint8_t> dataBuffer;
122 succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
125 size_t blobSize = dataBuffer.Size();
128 // Open a file handle on the memory buffer:
129 Dali::Internal::Platform::FileReader fileReader(dataBuffer, blobSize);
130 FILE* const fp = fileReader.GetFile();
133 if((!fseek(fp, 0, SEEK_SET)))
135 unsigned char* WebPDataBuffer;
136 WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * blobSize));
137 mWebPData.size = fread(WebPDataBuffer, sizeof(WebPByteType), mWebPData.size, fp);
138 mWebPData.bytes = WebPDataBuffer;
142 DALI_LOG_ERROR("Error seeking within file\n");
147 DALI_LOG_ERROR("Error reading file\n");
158 // Moveable but not copyable
160 Impl(const Impl&) = delete;
161 Impl& operator=(const Impl&) = delete;
162 Impl(Impl&&) = default;
163 Impl& operator=(Impl&&) = default;
167 #ifdef DALI_WEBP_ENABLED
168 if(&mWebPData != NULL)
170 free((void*)mWebPData.bytes);
171 mWebPData.bytes = nullptr;
172 WebPDataInit(&mWebPData);
176 WebPAnimDecoderDelete(mWebPAnimDecoder);
182 std::vector<uint32_t> mTimeStamp;
183 uint32_t mLoadingFrame{0};
186 #ifdef DALI_WEBP_ENABLED
187 WebPData mWebPData{0};
188 WebPAnimDecoder* mWebPAnimDecoder{nullptr};
189 WebPAnimInfo mWebPAnimInfo{0};
193 AnimatedImageLoadingPtr WebPLoading::New(const std::string& url, bool isLocalResource)
195 #ifndef DALI_WEBP_ENABLED
196 DALI_LOG_ERROR("The system does not support Animated WebP format.\n");
198 return AnimatedImageLoadingPtr(new WebPLoading(url, isLocalResource));
201 WebPLoading::WebPLoading(const std::string& url, bool isLocalResource)
202 : mImpl(new WebPLoading::Impl(url, isLocalResource))
206 WebPLoading::~WebPLoading()
211 bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
213 #ifdef DALI_WEBP_ENABLED
214 if(frameStartIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded)
219 DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count);
221 if(mImpl->mLoadingFrame > frameStartIndex)
223 mImpl->mLoadingFrame = 0;
224 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
227 for(; mImpl->mLoadingFrame < frameStartIndex; ++mImpl->mLoadingFrame)
229 uint8_t* frameBuffer;
231 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
232 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
235 for(int i = 0; i < count; ++i)
237 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
238 uint8_t* frameBuffer;
240 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
242 auto pixelBuffer = new uint8_t[bufferSize];
243 memcpy(pixelBuffer, frameBuffer, bufferSize);
244 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
248 pixelData.push_back(Dali::PixelData::New(pixelBuffer, bufferSize, mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY));
251 mImpl->mLoadingFrame++;
252 if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
254 mImpl->mLoadingFrame = 0;
255 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
265 Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
267 Dali::Devel::PixelBuffer pixelBuffer;
269 #ifdef DALI_WEBP_ENABLED
270 if(frameIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded)
275 DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
277 if(mImpl->mLoadingFrame > frameIndex)
279 mImpl->mLoadingFrame = 0;
280 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
283 for(; mImpl->mLoadingFrame < frameIndex; ++mImpl->mLoadingFrame)
285 uint8_t* frameBuffer;
287 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
288 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
291 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
292 uint8_t* frameBuffer;
294 WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
296 pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
297 memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
298 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
300 mImpl->mLoadingFrame++;
301 if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
303 mImpl->mLoadingFrame = 0;
304 WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
310 ImageDimensions WebPLoading::GetImageSize() const
312 #ifdef DALI_WEBP_ENABLED
313 return ImageDimensions(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height);
315 return ImageDimensions();
319 uint32_t WebPLoading::GetImageCount() const
321 #ifdef DALI_WEBP_ENABLED
322 return mImpl->mWebPAnimInfo.frame_count;
328 uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
330 // If frameIndex is above the value of ImageCount or current frame is not loading yet, return 0u.
331 if(frameIndex >= GetImageCount() || (frameIndex > 0 && mImpl->mTimeStamp[frameIndex - 1] > mImpl->mTimeStamp[frameIndex]))
339 return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
341 return mImpl->mTimeStamp[frameIndex];
345 std::string WebPLoading::GetUrl() const
350 bool WebPLoading::HasLoadingSucceeded() const
352 return mImpl->mLoadSucceeded;
355 } // namespace Adaptor
357 } // namespace Internal