2 * Copyright (c) 2020 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 <sys/types.h>
39 #include <dali/internal/imaging/common/file-download.h>
40 #include <dali/internal/system/common/file-reader.h>
42 typedef unsigned char WebPByteType;
56 #if defined(DEBUG_ENABLED)
57 Debug::Filter *gWebPLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
60 constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
64 struct WebPLoading::Impl
67 Impl( const std::string& url, bool isLocalResource )
70 #ifdef DALI_WEBP_ENABLED
71 if( ReadWebPInformation( isLocalResource ) )
73 WebPAnimDecoderOptions webPAnimDecoderOptions;
74 WebPAnimDecoderOptionsInit( &webPAnimDecoderOptions );
75 webPAnimDecoderOptions.color_mode = MODE_RGBA;
76 mWebPAnimDecoder = WebPAnimDecoderNew( &mWebPData, &webPAnimDecoderOptions );
77 WebPAnimDecoderGetInfo( mWebPAnimDecoder, &mWebPAnimInfo );
78 mTimeStamp.assign( mWebPAnimInfo.frame_count, 0 );
83 bool ReadWebPInformation( bool isLocalResource )
85 #ifdef DALI_WEBP_ENABLED
86 WebPDataInit( &mWebPData );
89 Internal::Platform::FileReader fileReader( mUrl );
90 FILE *fp = fileReader.GetFile();
96 if( fseek( fp, 0, SEEK_END ) <= -1 )
101 mWebPData.size = ftell( fp );
102 if( ( ! fseek( fp, 0, SEEK_SET ) ) )
104 unsigned char *WebPDataBuffer;
105 WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * mWebPData.size ) );
106 mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
107 mWebPData.bytes = WebPDataBuffer;
118 Dali::Vector<uint8_t> dataBuffer;
121 succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE );
124 size_t blobSize = dataBuffer.Size();
127 // Open a file handle on the memory buffer:
128 Dali::Internal::Platform::FileReader fileReader( dataBuffer, blobSize );
129 FILE * const fp = fileReader.GetFile();
132 if( ( ! fseek( fp, 0, SEEK_SET ) ) )
134 unsigned char *WebPDataBuffer;
135 WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * blobSize ) );
136 mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
137 mWebPData.bytes = WebPDataBuffer;
141 DALI_LOG_ERROR( "Error seeking within file\n" );
146 DALI_LOG_ERROR( "Error reading file\n" );
157 // Moveable but not copyable
159 Impl( const Impl& ) = delete;
160 Impl& operator=( const Impl& ) = delete;
161 Impl( Impl&& ) = default;
162 Impl& operator=( Impl&& ) = default;
166 #ifdef DALI_WEBP_ENABLED
167 if( &mWebPData != NULL )
169 free( (void*)mWebPData.bytes );
170 mWebPData.bytes = nullptr;
171 WebPDataInit( &mWebPData );
173 if( mWebPAnimDecoder )
175 WebPAnimDecoderDelete(mWebPAnimDecoder);
181 std::vector<uint32_t> mTimeStamp;
182 uint32_t mLoadingFrame{0};
184 #ifdef DALI_WEBP_ENABLED
185 WebPData mWebPData{0};
186 WebPAnimDecoder* mWebPAnimDecoder{nullptr};
187 WebPAnimInfo mWebPAnimInfo{0};
191 AnimatedImageLoadingPtr WebPLoading::New( const std::string &url, bool isLocalResource )
193 #ifndef DALI_WEBP_ENABLED
194 DALI_LOG_ERROR( "The system does not support Animated WebP format.\n" );
196 return AnimatedImageLoadingPtr( new WebPLoading( url, isLocalResource ) );
199 WebPLoading::WebPLoading( const std::string &url, bool isLocalResource )
200 : mImpl( new WebPLoading::Impl( url, isLocalResource ) )
204 WebPLoading::~WebPLoading()
209 bool WebPLoading::LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
211 #ifdef DALI_WEBP_ENABLED
212 if( frameStartIndex >= mImpl->mWebPAnimInfo.frame_count )
217 DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count );
219 if( mImpl->mLoadingFrame > frameStartIndex )
221 mImpl->mLoadingFrame = 0;
222 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
225 for( ; mImpl->mLoadingFrame < frameStartIndex ; ++mImpl->mLoadingFrame )
227 uint8_t* frameBuffer;
229 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
230 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
233 for( int i = 0; i < count; ++i )
235 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
236 uint8_t* frameBuffer;
238 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
240 auto pixelBuffer = new uint8_t[ bufferSize ];
241 memcpy( pixelBuffer, frameBuffer, bufferSize );
242 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
246 pixelData.push_back( Dali::PixelData::New( pixelBuffer, bufferSize,
247 mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height,
248 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;
268 #ifdef DALI_WEBP_ENABLED
269 if( frameIndex >= mImpl->mWebPAnimInfo.frame_count )
274 DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameIndex:%d )\n", frameIndex );
276 if( mImpl->mLoadingFrame > frameIndex )
278 mImpl->mLoadingFrame = 0;
279 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
282 for( ; mImpl->mLoadingFrame < frameIndex ; ++mImpl->mLoadingFrame )
284 uint8_t* frameBuffer;
286 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
287 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
290 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
291 uint8_t* frameBuffer;
293 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
295 pixelBuffer = Dali::Devel::PixelBuffer::New( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888 );
296 memcpy( pixelBuffer.GetBuffer(), frameBuffer, bufferSize );
297 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
299 mImpl->mLoadingFrame++;
300 if( mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count )
302 mImpl->mLoadingFrame = 0;
303 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
309 ImageDimensions WebPLoading::GetImageSize() const
311 #ifdef DALI_WEBP_ENABLED
312 return ImageDimensions( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height );
314 return ImageDimensions();
318 uint32_t WebPLoading::GetImageCount() const
320 #ifdef DALI_WEBP_ENABLED
321 return mImpl->mWebPAnimInfo.frame_count;
327 uint32_t WebPLoading::GetFrameInterval( uint32_t frameIndex ) const
329 if( frameIndex >= GetImageCount() )
337 return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
339 return mImpl->mTimeStamp[frameIndex];
343 std::string WebPLoading::GetUrl() const
348 } // namespace Adaptor
350 } // namespace Internal