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