2 * Copyright (c) 2022 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>
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/common/vector-wrapper.h>
24 #include <dali/public-api/render-tasks/render-task-list.h>
29 #include <dali/devel-api/adaptor-framework/bitmap-saver.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/integration-api/adaptor-framework/adaptor.h>
33 #include <dali/internal/adaptor/common/adaptor-impl.h>
34 #include <dali/internal/graphics/gles/egl-graphics.h>
44 constexpr int32_t GL_VERSION_NATIVE_IMAGE_SOURCE_AVAILABLE = 30;
45 constexpr uint32_t TIME_OUT_DURATION = 1000;
49 : mQuality(DEFAULT_QUALITY),
52 mNativeImageSourcePtr(NULL),
54 mUseDefaultCamera(true),
55 mSceneOffCameraAfterCaptureFinished(false),
56 mIsNativeImageSourcePossible(true)
60 Capture::Capture(Dali::CameraActor cameraActor)
61 : mQuality(DEFAULT_QUALITY),
62 mCameraActor(cameraActor),
65 mNativeImageSourcePtr(NULL),
67 mUseDefaultCamera(!cameraActor),
68 mSceneOffCameraAfterCaptureFinished(false),
69 mIsNativeImageSourcePossible(true)
75 DeleteNativeImageSource();
79 CapturePtr Capture::New()
81 CapturePtr pWorker = new Capture();
86 CapturePtr Capture::New(Dali::CameraActor cameraActor)
88 CapturePtr pWorker = new Capture(cameraActor);
93 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)
96 Start(source, position, size, path, clearColor);
99 void Capture::Start(Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string& path, const Dali::Vector4& clearColor)
106 // Increase the reference count focely to avoid application mistake.
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 && !mPixelBuffer.GetBuffer()))
138 uint32_t width, height;
139 Dali::Pixel::Format pixelFormat;
140 if(mIsNativeImageSourcePossible)
142 std::vector<uint8_t> buffer;
143 if(!mNativeImageSourcePtr || !mNativeImageSourcePtr->GetPixels(buffer, width, height, pixelFormat))
145 return Dali::Devel::PixelBuffer();
147 mPixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
148 memcpy(mPixelBuffer.GetBuffer(), &buffer[0], width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat));
152 if(!mFrameBuffer || !mTexture)
154 DALI_LOG_ERROR("Capture is not started yet.");
155 return Dali::Devel::PixelBuffer();
157 uint8_t* buffer = mFrameBuffer.GetRenderedBuffer();
158 if(buffer == nullptr)
160 DALI_LOG_ERROR("Capture is not finished.");
161 return Dali::Devel::PixelBuffer();
163 width = mTexture.GetWidth();
164 height = mTexture.GetHeight();
165 pixelFormat = mTexture.GetPixelFormat();
166 mPixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
167 memcpy(mPixelBuffer.GetBuffer(), buffer, width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat));
173 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
175 return mFinishedSignal;
178 void Capture::CreateTexture(const Vector2& size)
180 if(mIsNativeImageSourcePossible)
182 if(!mNativeImageSourcePtr)
184 mNativeImageSourcePtr = Dali::NativeImageSource::New(size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT);
185 mTexture = Dali::Texture::New(*mNativeImageSourcePtr);
190 mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
194 void Capture::DeleteNativeImageSource()
196 if(mNativeImageSourcePtr)
198 mNativeImageSourcePtr.Reset();
202 void Capture::CreateFrameBuffer()
206 // Create a FrameBuffer object with depth attachments.
207 mFrameBuffer = Dali::FrameBuffer::New(mTexture.GetWidth(), mTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
208 // Add a color attachment to the FrameBuffer object.
209 mFrameBuffer.AttachColorTexture(mTexture);
213 void Capture::DeleteFrameBuffer()
217 mFrameBuffer.Reset();
221 bool Capture::IsFrameBufferCreated()
223 return static_cast<bool>(mFrameBuffer);
226 void Capture::SetupRenderTask(const Dali::Vector2& position, const Dali::Vector2& size, Dali::Actor source, const Dali::Vector4& clearColor)
230 DALI_LOG_ERROR("Source is empty\n");
234 Dali::Window window = DevelWindow::Get(source);
237 DALI_LOG_ERROR("The source is not added on the scene\n");
245 mUseDefaultCamera = true;
246 mCameraActor = Dali::CameraActor::New(size);
247 // Because input position and size are for 2 dimentional area,
248 // default z-directional position of the camera is required to be used for the new camera position.
249 float cameraDefaultZPosition = mCameraActor.GetProperty<float>(Dali::Actor::Property::POSITION_Z);
250 Vector2 positionTransition = position + size / 2;
251 mCameraActor.SetProperty(Dali::Actor::Property::POSITION, Vector3(positionTransition.x, positionTransition.y, cameraDefaultZPosition));
252 mCameraActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
253 mCameraActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
256 // Camera must be scene on. Add camera to window.
257 if(!mCameraActor.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
259 if(!mUseDefaultCamera)
261 DALI_LOG_ERROR("Camera must be on scene. Camera is connected to window now.\n");
263 window.Add(mCameraActor);
264 mSceneOffCameraAfterCaptureFinished = true;
269 DALI_LOG_ERROR("Frame buffer is not created.\n");
273 Dali::RenderTaskList taskList = window.GetRenderTaskList();
274 mRenderTask = taskList.CreateTask();
275 mRenderTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
276 mRenderTask.SetSourceActor(source);
277 mRenderTask.SetCameraActor(mCameraActor);
278 mRenderTask.SetScreenToFrameBufferFunction(Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
279 mRenderTask.SetFrameBuffer(mFrameBuffer);
280 mRenderTask.SetClearColor(clearColor);
281 mRenderTask.SetClearEnabled(true);
282 mRenderTask.SetProperty(Dali::RenderTask::Property::REQUIRES_SYNC, true);
283 mRenderTask.FinishedSignal().Connect(this, &Capture::OnRenderFinished);
284 mRenderTask.GetCameraActor().SetInvertYAxis(true);
285 if(!mIsNativeImageSourcePossible)
287 mFrameBuffer.CaptureRenderedResult();
290 mTimer = Dali::Timer::New(TIME_OUT_DURATION);
291 mTimer.TickSignal().Connect(this, &Capture::OnTimeOut);
295 void Capture::UnsetRenderTask()
299 if(mSceneOffCameraAfterCaptureFinished && mCameraActor)
301 if(!mUseDefaultCamera)
303 DALI_LOG_ERROR("Camera is disconnected from window now.\n");
305 mSceneOffCameraAfterCaptureFinished = false;
306 mCameraActor.Unparent();
307 mCameraActor.Reset();
312 Dali::Window window = DevelWindow::Get(mSource);
313 Dali::RenderTaskList taskList = window.GetRenderTaskList();
314 taskList.RemoveTask(mRenderTask);
320 bool Capture::IsRenderTaskSetup()
322 return mCameraActor && mRenderTask;
325 void Capture::SetupResources(const Dali::Vector2& position, const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source)
327 Dali::Internal::Adaptor::Adaptor& adaptor = Internal::Adaptor::Adaptor::GetImplementation(Internal::Adaptor::Adaptor::Get());
328 GraphicsInterface* graphics = &adaptor.GetGraphicsInterface();
329 auto eglGraphics = static_cast<EglGraphics*>(graphics);
331 if(eglGraphics->GetEglImplementation().GetGlesVersion() < GL_VERSION_NATIVE_IMAGE_SOURCE_AVAILABLE)
333 DALI_LOG_ERROR("GLES is 2.0, we can't use native image source \n");
334 mIsNativeImageSourcePossible = false;
341 SetupRenderTask(position, size, source, clearColor);
344 void Capture::UnsetResources()
346 if(IsRenderTaskSetup())
351 if(IsFrameBufferCreated())
357 void Capture::OnRenderFinished(Dali::RenderTask& task)
359 Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
367 DALI_LOG_ERROR("Fail to Capture Path[%s]\n", mPath.c_str());
368 state = Dali::Capture::FinishState::FAILED;
372 Dali::Capture handle(this);
373 mFinishedSignal.Emit(handle, state);
377 // Decrease the reference count forcely. It is increased at Start().
381 bool Capture::OnTimeOut()
383 Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
385 Dali::Capture handle(this);
386 mFinishedSignal.Emit(handle, state);
390 // Decrease the reference count forcely. It is increased at Start().
396 bool Capture::SaveFile()
398 if(mIsNativeImageSourcePossible)
400 if(mNativeImageSourcePtr)
402 return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
407 uint8_t* buffer = mFrameBuffer.GetRenderedBuffer();
408 return Dali::EncodeToFile(buffer, mPath, Dali::Pixel::RGBA8888, mTexture.GetWidth(), mTexture.GetHeight(), mQuality);
414 } // End of namespace Adaptor
416 } // End of namespace Internal
418 } // End of namespace Dali