2 * Copyright (c) 2024 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>
43 static constexpr uint32_t ORDER_INDEX_CAPTURE_RENDER_TASK = 1000;
44 constexpr int32_t SHADER_VERSION_NATIVE_IMAGE_SOURCE_AVAILABLE = 300;
45 constexpr uint32_t TIME_OUT_DURATION = 1000;
49 : mQuality(DEFAULT_QUALITY),
52 mNativeImageSourcePtr(NULL),
54 mUseDefaultCamera(true),
55 mSceneOffCameraAfterCaptureFinished(false)
59 Capture::Capture(Dali::CameraActor cameraActor)
60 : mQuality(DEFAULT_QUALITY),
61 mCameraActor(cameraActor),
64 mNativeImageSourcePtr(NULL),
66 mUseDefaultCamera(!cameraActor),
67 mSceneOffCameraAfterCaptureFinished(false)
73 DeleteNativeImageSource();
77 CapturePtr Capture::New()
79 CapturePtr pWorker = new Capture();
84 CapturePtr Capture::New(Dali::CameraActor cameraActor)
86 CapturePtr pWorker = new Capture(cameraActor);
91 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)
94 Start(source, position, size, path, clearColor);
97 void Capture::Start(Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string& path, const Dali::Vector4& clearColor)
104 // Increase the reference count focely to avoid application mistake.
114 SetupResources(position, size, clearColor, source);
117 void Capture::SetImageQuality(uint32_t quality)
122 void Capture::SetExclusive(bool exclusive)
124 if(mIsExclusive != exclusive)
126 mIsExclusive = exclusive;
129 mRenderTask.SetExclusive(mIsExclusive);
134 bool Capture::IsExclusive() const
139 Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
141 return mNativeImageSourcePtr;
144 Dali::Texture Capture::GetTexture() const
149 Dali::Devel::PixelBuffer Capture::GetCapturedBuffer()
151 if(!mPixelBuffer || (mPixelBuffer && !mPixelBuffer.GetBuffer()))
153 std::vector<uint8_t> buffer;
154 uint32_t width, height;
155 Dali::Pixel::Format pixelFormat;
156 if(!mNativeImageSourcePtr->GetPixels(buffer, width, height, pixelFormat))
158 return Dali::Devel::PixelBuffer();
160 mPixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
161 memcpy(mPixelBuffer.GetBuffer(), &buffer[0], width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat));
166 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
168 return mFinishedSignal;
171 void Capture::CreateTexture(const Vector2& size)
175 if(!mNativeImageSourcePtr)
177 mNativeImageSourcePtr = Dali::NativeImageSource::New(size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT);
178 mTexture = Dali::Texture::New(*mNativeImageSourcePtr);
183 mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
187 void Capture::DeleteNativeImageSource()
189 if(mNativeImageSourcePtr)
191 mNativeImageSourcePtr.Reset();
195 void Capture::CreateFrameBuffer()
199 // Create a FrameBuffer object with depth attachments.
200 mFrameBuffer = Dali::FrameBuffer::New(mTexture.GetWidth(), mTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
201 // Add a color attachment to the FrameBuffer object.
202 mFrameBuffer.AttachColorTexture(mTexture);
206 void Capture::DeleteFrameBuffer()
210 mFrameBuffer.Reset();
214 bool Capture::IsFrameBufferCreated()
216 return static_cast<bool>(mFrameBuffer);
219 void Capture::SetupRenderTask(const Dali::Vector2& position, const Dali::Vector2& size, Dali::Actor source, const Dali::Vector4& clearColor)
223 DALI_LOG_ERROR("Source is empty\n");
227 Dali::Integration::SceneHolder sceneHolder = Dali::Integration::SceneHolder::Get(source);
230 DALI_LOG_ERROR("The source is not added on the scene\n");
238 mUseDefaultCamera = true;
239 mCameraActor = Dali::CameraActor::New(size);
240 // Because input position and size are for 2 dimentional area,
241 // default z-directional position of the camera is required to be used for the new camera position.
242 float cameraDefaultZPosition = mCameraActor.GetProperty<float>(Dali::Actor::Property::POSITION_Z);
243 Vector2 positionTransition = position + size / 2;
244 mCameraActor.SetProperty(Dali::Actor::Property::POSITION, Vector3(positionTransition.x, positionTransition.y, cameraDefaultZPosition));
245 mCameraActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
246 mCameraActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
249 // Camera must be scene on. Add camera to window.
250 if(!mCameraActor.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
252 if(!mUseDefaultCamera)
254 DALI_LOG_ERROR("Camera must be on scene. Camera is connected to window now.\n");
256 sceneHolder.Add(mCameraActor);
257 mSceneOffCameraAfterCaptureFinished = true;
262 DALI_LOG_ERROR("Frame buffer is not created.\n");
266 mSceneHolderHandle = sceneHolder;
267 Dali::RenderTaskList taskList = sceneHolder.GetRenderTaskList();
268 mRenderTask = taskList.CreateTask();
269 mRenderTask.SetOrderIndex(ORDER_INDEX_CAPTURE_RENDER_TASK);
270 mRenderTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
271 mRenderTask.SetSourceActor(source);
272 mRenderTask.SetCameraActor(mCameraActor);
273 mRenderTask.SetScreenToFrameBufferFunction(Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
274 mRenderTask.SetFrameBuffer(mFrameBuffer);
275 mRenderTask.SetClearColor(clearColor);
276 mRenderTask.SetClearEnabled(true);
277 mRenderTask.SetExclusive(mIsExclusive);
278 mRenderTask.SetProperty(Dali::RenderTask::Property::REQUIRES_SYNC, true);
279 mRenderTask.FinishedSignal().Connect(this, &Capture::OnRenderFinished);
280 mRenderTask.GetCameraActor().SetInvertYAxis(true);
282 mTimer = Dali::Timer::New(TIME_OUT_DURATION);
283 mTimer.TickSignal().Connect(this, &Capture::OnTimeOut);
287 void Capture::UnsetRenderTask()
291 if(mSceneOffCameraAfterCaptureFinished && mCameraActor)
293 if(!mUseDefaultCamera)
295 DALI_LOG_ERROR("Camera is disconnected from window now.\n");
297 mSceneOffCameraAfterCaptureFinished = false;
298 mCameraActor.Unparent();
299 mCameraActor.Reset();
302 Dali::Integration::SceneHolder sceneHolder = mSceneHolderHandle.GetHandle();
303 if(mRenderTask && sceneHolder)
305 Dali::RenderTaskList taskList = sceneHolder.GetRenderTaskList();
306 taskList.RemoveTask(mRenderTask);
310 mSceneHolderHandle.Reset();
313 bool Capture::IsRenderTaskSetup()
315 return mCameraActor && mRenderTask;
318 void Capture::SetupResources(const Dali::Vector2& position, const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source)
320 if(mFileSave && Dali::Shader::GetShaderLanguageVersion() < SHADER_VERSION_NATIVE_IMAGE_SOURCE_AVAILABLE)
322 DALI_LOG_ERROR("GLES is 2.0, we can't use native image source \n");
330 SetupRenderTask(position, size, source, clearColor);
333 void Capture::UnsetResources()
335 if(IsRenderTaskSetup())
340 if(IsFrameBufferCreated())
346 void Capture::OnRenderFinished(Dali::RenderTask& task)
348 Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
356 DALI_LOG_ERROR("Fail to Capture Path[%s]\n", mPath.c_str());
357 state = Dali::Capture::FinishState::FAILED;
361 Dali::Capture handle(this);
362 mFinishedSignal.Emit(handle, state);
366 // Decrease the reference count forcely. It is increased at Start().
370 bool Capture::OnTimeOut()
372 Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
374 Dali::Capture handle(this);
375 mFinishedSignal.Emit(handle, state);
379 // Decrease the reference count forcely. It is increased at Start().
385 bool Capture::SaveFile()
387 if(mNativeImageSourcePtr)
389 return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
395 } // End of namespace Adaptor
397 } // End of namespace Internal
399 } // End of namespace Dali