dfd48e2027718d1c4dcc420e164b49ac527afc67
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / common / capture-impl.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/system/common/capture-impl.h>
20
21 // EXTERNAL INCLUDES
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>
25 #include <string.h>
26 #include <fstream>
27
28 // INTERNAL INCLUDES
29 #include <dali/devel-api/adaptor-framework/native-image-source-devel.h>
30 #include <dali/devel-api/adaptor-framework/window-devel.h>
31 #include <dali/integration-api/adaptor-framework/adaptor.h>
32
33 namespace
34 {
35 unsigned int TIME_OUT_DURATION = 1000;
36 }
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44 Capture::Capture()
45 : mQuality(DEFAULT_QUALITY),
46   mTimer(),
47   mPath(),
48   mNativeImageSourcePtr(NULL),
49   mFileSave(false)
50 {
51 }
52
53 Capture::Capture(Dali::CameraActor cameraActor)
54 : mQuality(DEFAULT_QUALITY),
55   mCameraActor(cameraActor),
56   mTimer(),
57   mPath(),
58   mNativeImageSourcePtr(NULL),
59   mFileSave(false)
60 {
61 }
62
63 Capture::~Capture()
64 {
65   DeleteNativeImageSource();
66 }
67
68 CapturePtr Capture::New()
69 {
70   CapturePtr pWorker = new Capture();
71
72   return pWorker;
73 }
74
75 CapturePtr Capture::New(Dali::CameraActor cameraActor)
76 {
77   CapturePtr pWorker = new Capture(cameraActor);
78
79   return pWorker;
80 }
81
82 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)
83 {
84   mQuality = quality;
85   Start(source, position, size, path, clearColor);
86 }
87
88 void Capture::Start(Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string& path, const Dali::Vector4& clearColor)
89 {
90   // Increase the reference count focely to avoid application mistake.
91   Reference();
92
93   mPath = path;
94   if(!mPath.empty())
95   {
96     mFileSave = true;
97   }
98
99   DALI_ASSERT_ALWAYS(source && "Source is NULL.");
100
101   UnsetResources();
102   SetupResources(position, size, clearColor, source);
103 }
104
105 void Capture::SetImageQuality(uint32_t quality)
106 {
107   mQuality = quality;
108 }
109
110 Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
111 {
112   return mNativeImageSourcePtr;
113 }
114
115 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
116 {
117   return mFinishedSignal;
118 }
119
120 void Capture::CreateNativeImageSource(const Vector2& size)
121 {
122   Dali::Adaptor& adaptor = Dali::Adaptor::Get();
123
124   DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
125
126   DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
127
128   // create the NativeImageSource object with our surface
129   mNativeImageSourcePtr = Dali::NativeImageSource::New(size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT);
130 }
131
132 void Capture::DeleteNativeImageSource()
133 {
134   mNativeImageSourcePtr.Reset();
135 }
136
137 bool Capture::IsNativeImageSourceCreated()
138 {
139   return mNativeImageSourcePtr;
140 }
141
142 void Capture::CreateFrameBuffer()
143 {
144   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
145
146   DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
147
148   mNativeTexture = Dali::Texture::New(*mNativeImageSourcePtr);
149
150   // Create a FrameBuffer object with depth attachments.
151   mFrameBuffer = Dali::FrameBuffer::New(mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
152   // Add a color attachment to the FrameBuffer object.
153   mFrameBuffer.AttachColorTexture(mNativeTexture);
154 }
155
156 void Capture::DeleteFrameBuffer()
157 {
158   DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
159
160   mFrameBuffer.Reset();
161   mNativeTexture.Reset();
162 }
163
164 bool Capture::IsFrameBufferCreated()
165 {
166   return mFrameBuffer;
167 }
168
169 void Capture::SetupRenderTask(const Dali::Vector2& position, const Dali::Vector2& size, Dali::Actor source, const Dali::Vector4& clearColor)
170 {
171   DALI_ASSERT_ALWAYS(source && "Source is empty.");
172
173   Dali::Window window = DevelWindow::Get(source);
174   if(!window)
175   {
176     DALI_LOG_ERROR("The source is not added on the window\n");
177     return;
178   }
179
180   mSource = source;
181
182   if(!mCameraActor)
183   {
184     mCameraActor = Dali::CameraActor::New(size);
185     // Because input position and size are for 2 dimentional area,
186     // default z-directional position of the camera is required to be used for the new camera position.
187     float   cameraDefaultZPosition = mCameraActor.GetProperty<float>(Dali::Actor::Property::POSITION_Z);
188     Vector2 positionTransition     = position + size / 2;
189     mCameraActor.SetProperty(Dali::Actor::Property::POSITION, Vector3(positionTransition.x, positionTransition.y, cameraDefaultZPosition));
190     mCameraActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
191     mCameraActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
192   }
193
194   window.Add(mCameraActor);
195
196   DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
197
198   DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
199
200   Dali::RenderTaskList taskList = window.GetRenderTaskList();
201   mRenderTask                   = taskList.CreateTask();
202   mRenderTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
203   mRenderTask.SetSourceActor(source);
204   mRenderTask.SetCameraActor(mCameraActor);
205   mRenderTask.SetScreenToFrameBufferFunction(Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
206   mRenderTask.SetFrameBuffer(mFrameBuffer);
207   mRenderTask.SetClearColor(clearColor);
208   mRenderTask.SetClearEnabled(true);
209   mRenderTask.SetProperty(Dali::RenderTask::Property::REQUIRES_SYNC, true);
210   mRenderTask.FinishedSignal().Connect(this, &Capture::OnRenderFinished);
211   mRenderTask.GetCameraActor().SetInvertYAxis(true);
212
213   mTimer = Dali::Timer::New(TIME_OUT_DURATION);
214   mTimer.TickSignal().Connect(this, &Capture::OnTimeOut);
215   mTimer.Start();
216 }
217
218 void Capture::UnsetRenderTask()
219 {
220   DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
221
222   mTimer.Reset();
223
224   mCameraActor.Unparent();
225   mCameraActor.Reset();
226
227   DALI_ASSERT_ALWAYS(mRenderTask && "RenderTask is NULL.");
228
229   Dali::Window         window   = DevelWindow::Get(mSource);
230   Dali::RenderTaskList taskList = window.GetRenderTaskList();
231   taskList.RemoveTask(mRenderTask);
232   mRenderTask.Reset();
233   mSource.Reset();
234 }
235
236 bool Capture::IsRenderTaskSetup()
237 {
238   return mCameraActor && mRenderTask;
239 }
240
241 void Capture::SetupResources(const Dali::Vector2& position, const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source)
242 {
243   CreateNativeImageSource(size);
244
245   CreateFrameBuffer();
246
247   SetupRenderTask(position, size, source, clearColor);
248 }
249
250 void Capture::UnsetResources()
251 {
252   if(IsRenderTaskSetup())
253   {
254     UnsetRenderTask();
255   }
256
257   if(IsFrameBufferCreated())
258   {
259     DeleteFrameBuffer();
260   }
261 }
262
263 void Capture::OnRenderFinished(Dali::RenderTask& task)
264 {
265   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
266
267   mTimer.Stop();
268
269   if(mFileSave)
270   {
271     if(!SaveFile())
272     {
273       state = Dali::Capture::FinishState::FAILED;
274       DALI_LOG_ERROR("Fail to Capture Path[%s]", mPath.c_str());
275     }
276   }
277
278   Dali::Capture handle(this);
279   mFinishedSignal.Emit(handle, state);
280
281   UnsetResources();
282
283   // Decrease the reference count forcely. It is increased at Start().
284   Unreference();
285 }
286
287 bool Capture::OnTimeOut()
288 {
289   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
290
291   Dali::Capture handle(this);
292   mFinishedSignal.Emit(handle, state);
293
294   UnsetResources();
295
296   // Decrease the reference count forcely. It is increased at Start().
297   Unreference();
298
299   return false;
300 }
301
302 bool Capture::SaveFile()
303 {
304   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
305
306   return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
307 }
308
309 } // End of namespace Adaptor
310
311 } // End of namespace Internal
312
313 } // End of namespace Dali