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/system/common/capture-impl.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/public-api/render-tasks/render-task-list.h>
26 #include <dali/integration-api/debug.h>
29 #include <dali/integration-api/adaptor-framework/adaptor.h>
30 #include <dali/devel-api/adaptor-framework/native-image-source-devel.h>
31 #include <dali/devel-api/adaptor-framework/window-devel.h>
32 #include <dali/devel-api/adaptor-framework/bitmap-saver.h>
33 #include <dali/internal/adaptor/common/adaptor-impl.h>
34 #include <dali/internal/graphics/gles/egl-graphics.h>
47 constexpr int32_t VERSION_NATIVE_IMAGE_SOURCE = 30;
48 constexpr uint32_t TIME_OUT_DURATION = 1000;
52 : mQuality( DEFAULT_QUALITY ),
55 mNativeImageSourcePtr( NULL ),
58 mIsNativeImageSourcePossible(true)
62 Capture::Capture( Dali::CameraActor cameraActor )
63 : mQuality( DEFAULT_QUALITY ),
64 mCameraActor( cameraActor ),
67 mNativeImageSourcePtr( NULL ),
70 mIsNativeImageSourcePossible(true)
76 DeleteNativeImageSource();
80 CapturePtr Capture::New()
82 CapturePtr pWorker = new Capture();
87 CapturePtr Capture::New( Dali::CameraActor cameraActor )
89 CapturePtr pWorker = new Capture( cameraActor );
94 void Capture::Start( Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor, const uint32_t quality )
97 Start( source, position, size, path, clearColor );
100 void Capture::Start( Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor )
102 DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
104 // Increase the reference count focely to avoid application mistake.
108 if( mPath.size() > 0 )
113 DALI_ASSERT_ALWAYS(source && "Source is NULL.");
116 SetupResources( position, size, clearColor, source );
119 void Capture::SetImageQuality( uint32_t quality )
124 Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
126 return mNativeImageSourcePtr;
129 Dali::Texture Capture::GetTexture()
134 Dali::Devel::PixelBuffer Capture::GetCapturedBuffer()
136 if(!mPixelBuffer || !mPixelBuffer.GetBuffer())
138 uint8_t* bufferPointer = nullptr;
139 uint32_t width, height;
140 Dali::Pixel::Format pixelFormat;
141 std::vector<uint8_t> buffer;
142 if(mIsNativeImageSourcePossible)
144 if(mNativeImageSourcePtr->GetPixels(buffer, width, height, pixelFormat))
146 if(width > 0 && height > 0)
148 // Get captured imge only if it have more than 1 pixels.
149 bufferPointer = &buffer[0];
155 width = mTexture.GetWidth();
156 height = mTexture.GetHeight();
157 pixelFormat = Dali::Pixel::RGBA8888;
158 bufferPointer = mFrameBuffer.GetRenderedBuffer();
160 if(bufferPointer == nullptr)
162 // Fail to capture. Return empty pixel buffer.
163 return Dali::Devel::PixelBuffer();
165 mPixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
167 memcpy(mPixelBuffer.GetBuffer(), bufferPointer, width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat));
173 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
175 return mFinishedSignal;
178 void Capture::CreateTexture(const Vector2& size)
180 Dali::Adaptor& adaptor = Dali::Adaptor::Get();
182 DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
184 if(mIsNativeImageSourcePossible)
186 DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
187 // create the NativeImageSource object with our surface
188 mNativeImageSourcePtr = Dali::NativeImageSource::New(size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT);
189 mTexture = Dali::Texture::New(*mNativeImageSourcePtr);
193 mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(size.width), unsigned(size.height));
197 void Capture::DeleteNativeImageSource()
199 if(mNativeImageSourcePtr)
201 mNativeImageSourcePtr.Reset();
205 void Capture::CreateFrameBuffer()
207 DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
209 // Create a FrameBuffer object with depth attachments.
210 mFrameBuffer = Dali::FrameBuffer::New(mTexture.GetWidth(), mTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
211 // Add a color attachment to the FrameBuffer object.
212 mFrameBuffer.AttachColorTexture(mTexture);
215 void Capture::DeleteFrameBuffer()
217 DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
219 mFrameBuffer.Reset();
222 bool Capture::IsFrameBufferCreated()
227 void Capture::SetupRenderTask( const Dali::Vector2& position, const Dali::Vector2& size, Dali::Actor source, const Dali::Vector4& clearColor )
229 DALI_ASSERT_ALWAYS(source && "Source is empty.");
231 Dali::Window window = DevelWindow::Get( source );
234 DALI_LOG_ERROR("The source is not added on the window\n");
242 mCameraActor = Dali::CameraActor::New( size );
243 // Because input position and size are for 2 dimentional area,
244 // default z-directional position of the camera is required to be used for the new camera position.
245 float cameraDefaultZPosition = mCameraActor.GetProperty<float>( Dali::Actor::Property::POSITION_Z );
246 Vector2 positionTransition = position + size / 2;
247 mCameraActor.SetProperty( Dali::Actor::Property::POSITION, Vector3( positionTransition.x, positionTransition.y, cameraDefaultZPosition ) );
248 mCameraActor.SetProperty( Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
249 mCameraActor.SetProperty( Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
252 window.Add( mCameraActor );
254 DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
256 DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
258 Dali::RenderTaskList taskList = window.GetRenderTaskList();
259 mRenderTask = taskList.CreateTask();
260 mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
261 mRenderTask.SetSourceActor( source );
262 mRenderTask.SetCameraActor( mCameraActor );
263 mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
264 mRenderTask.SetFrameBuffer( mFrameBuffer );
265 mRenderTask.SetClearColor( clearColor );
266 mRenderTask.SetClearEnabled( true );
267 mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
268 mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
269 mRenderTask.GetCameraActor().SetInvertYAxis( true );
270 if(!mIsNativeImageSourcePossible)
272 mFrameBuffer.CaptureRenderedResult();
275 mTimer = Dali::Timer::New( TIME_OUT_DURATION );
276 mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
280 void Capture::UnsetRenderTask()
282 DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
286 mCameraActor.Unparent();
287 mCameraActor.Reset();
289 DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
291 Dali::Window window = DevelWindow::Get( mSource );
292 Dali::RenderTaskList taskList = window.GetRenderTaskList();
293 taskList.RemoveTask( mRenderTask );
298 bool Capture::IsRenderTaskSetup()
300 return mCameraActor && mRenderTask;
303 void Capture::SetupResources(const Dali::Vector2& position, const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source)
305 Dali::Internal::Adaptor::Adaptor& adaptor = Internal::Adaptor::Adaptor::GetImplementation(Internal::Adaptor::Adaptor::Get());
306 GraphicsInterface* graphics = &adaptor.GetGraphicsInterface();
307 auto eglGraphics = static_cast<EglGraphics*>(graphics);
309 if(eglGraphics->GetEglImplementation().GetGlesVersion() < VERSION_NATIVE_IMAGE_SOURCE)
311 mIsNativeImageSourcePossible = false;
318 SetupRenderTask( position, size, source, clearColor );
321 void Capture::UnsetResources()
323 if( IsRenderTaskSetup() )
328 if( IsFrameBufferCreated() )
334 void Capture::OnRenderFinished( Dali::RenderTask& task )
336 Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
344 state = Dali::Capture::FinishState::FAILED;
345 DALI_LOG_ERROR( "Fail to Capture Path[%s]", mPath.c_str() );
349 Dali::Capture handle( this );
350 mFinishedSignal.Emit( handle, state );
354 // Decrease the reference count forcely. It is increased at Start().
358 bool Capture::OnTimeOut()
360 Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
362 Dali::Capture handle( this );
363 mFinishedSignal.Emit( handle, state );
367 // Decrease the reference count forcely. It is increased at Start().
373 bool Capture::SaveFile()
375 if(mIsNativeImageSourcePossible)
377 DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
378 return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
382 uint8_t* buffer = mFrameBuffer.GetRenderedBuffer();
383 return Dali::EncodeToFile(buffer, mPath, Dali::Pixel::RGBA8888, mTexture.GetWidth(), mTexture.GetHeight(), mQuality);
387 } // End of namespace Adaptor
389 } // End of namespace Internal
391 } // End of namespace Dali