Make capture return Buffer.
[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/stage.h>
25 #include <dali/public-api/common/vector-wrapper.h>
26 #include <dali/public-api/render-tasks/render-task-list.h>
27 #include <dali/integration-api/debug.h>
28
29 // INTERNAL INCLUDES
30 #include <dali/integration-api/adaptor-framework/adaptor.h>
31
32 namespace
33 {
34 unsigned int TIME_OUT_DURATION = 1000;
35 }
36
37 namespace Dali
38 {
39
40 namespace Internal
41 {
42
43 namespace Adaptor
44 {
45
46 Capture::Capture()
47 : mTimer(),
48   mPath(),
49   mNativeImageSourcePtr( NULL ),
50   mFileSave( false )
51 {
52 }
53
54 Capture::Capture( Dali::CameraActor cameraActor )
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& size, const std::string &path, const Dali::Vector4& clearColor )
83 {
84   DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
85
86   // Increase the reference count focely to avoid application mistake.
87   Reference();
88
89   mPath = path;
90   if( mPath.size() > 0 )
91   {
92     mFileSave = true;
93   }
94
95   DALI_ASSERT_ALWAYS(source && "Source is NULL.");
96
97   UnsetResources();
98   SetupResources( size, clearColor, source );
99 }
100
101 Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
102 {
103   DALI_ASSERT_ALWAYS( mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL.");
104
105   return mNativeImageSourcePtr;
106 }
107
108 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
109 {
110   return mFinishedSignal;
111 }
112
113 void Capture::CreateNativeImageSource( const Vector2& size )
114 {
115   Dali::Adaptor& adaptor = Dali::Adaptor::Get();
116
117   DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
118
119   DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
120
121   // create the NativeImageSource object with our surface
122   mNativeImageSourcePtr = Dali::NativeImageSource::New( size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT );
123 }
124
125 void Capture::DeleteNativeImageSource()
126 {
127   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
128
129   mNativeImageSourcePtr.Reset();
130 }
131
132 bool Capture::IsNativeImageSourceCreated()
133 {
134   return mNativeImageSourcePtr;
135 }
136
137 void Capture::CreateFrameBuffer()
138 {
139   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
140
141   DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
142
143   mNativeTexture = Dali::Texture::New( *mNativeImageSourcePtr );
144
145   // Create a FrameBuffer object with depth attachments.
146   mFrameBuffer = Dali::FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH );
147   // Add a color attachment to the FrameBuffer object.
148   mFrameBuffer.AttachColorTexture( mNativeTexture );
149 }
150
151 void Capture::DeleteFrameBuffer()
152 {
153   DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
154
155   mFrameBuffer.Reset();
156   mNativeTexture.Reset();
157 }
158
159 bool Capture::IsFrameBufferCreated()
160 {
161   return mFrameBuffer;
162 }
163
164 void Capture::SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearColor )
165 {
166   DALI_ASSERT_ALWAYS(source && "Source is empty.");
167
168   mSource = source;
169
170   // Check the original parent about source.
171   mParent = mSource.GetParent();
172
173   Dali::Stage stage = Dali::Stage::GetCurrent();
174   Dali::Size stageSize = stage.GetSize();
175
176   // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
177   stage.Add( mSource );
178
179   if( !mCameraActor )
180   {
181     mCameraActor = Dali::CameraActor::New( stageSize );
182     mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
183     mCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
184   }
185
186   stage.Add( mCameraActor );
187
188   DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
189
190   DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
191
192   Dali::RenderTaskList taskList = stage.GetRenderTaskList();
193   mRenderTask = taskList.CreateTask();
194   mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
195   mRenderTask.SetSourceActor( source );
196   mRenderTask.SetCameraActor( mCameraActor );
197   mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
198   mRenderTask.SetFrameBuffer( mFrameBuffer );
199   mRenderTask.SetClearColor( clearColor );
200   mRenderTask.SetClearEnabled( true );
201   mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
202   mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
203   mRenderTask.GetCameraActor().SetInvertYAxis( true );
204
205   mTimer = Dali::Timer::New( TIME_OUT_DURATION );
206   mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
207   mTimer.Start();
208 }
209
210 void Capture::UnsetRenderTask()
211 {
212   DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
213
214   if( mParent )
215   {
216     // Restore the parent of source.
217     mParent.Add( mSource );
218     mParent.Reset();
219   }
220   else
221   {
222     mSource.Unparent();
223   }
224
225   mSource.Reset();
226
227   mTimer.Reset();
228
229   mCameraActor.Unparent();
230   mCameraActor.Reset();
231
232   DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
233
234   Dali::RenderTaskList taskList = Dali::Stage::GetCurrent().GetRenderTaskList();
235   taskList.RemoveTask( mRenderTask );
236   mRenderTask.Reset();
237 }
238
239 bool Capture::IsRenderTaskSetup()
240 {
241   return mCameraActor && mRenderTask;
242 }
243
244 void Capture::SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source )
245 {
246   CreateNativeImageSource( size );
247
248   CreateFrameBuffer();
249
250   SetupRenderTask( source, clearColor );
251 }
252
253 void Capture::UnsetResources()
254 {
255   if( IsRenderTaskSetup() )
256   {
257     UnsetRenderTask();
258   }
259
260   if( IsFrameBufferCreated() )
261   {
262     DeleteFrameBuffer();
263   }
264 }
265
266 void Capture::OnRenderFinished( Dali::RenderTask& task )
267 {
268   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
269
270   mTimer.Stop();
271
272   if( mFileSave )
273   {
274     if( !SaveFile() )
275     {
276       state = Dali::Capture::FinishState::FAILED;
277       DALI_LOG_ERROR( "Fail to Capture Path[%s]", mPath.c_str() );
278     }
279   }
280
281   Dali::Capture handle( this );
282   mFinishedSignal.Emit( handle, state );
283
284   UnsetResources();
285
286   // Decrease the reference count forcely. It is increased at Start().
287   Unreference();
288 }
289
290 bool Capture::OnTimeOut()
291 {
292   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
293
294   Dali::Capture handle( this );
295   mFinishedSignal.Emit( handle, state );
296
297   UnsetResources();
298
299   // Decrease the reference count forcely. It is increased at Start().
300   Unreference();
301
302   return false;
303 }
304
305 bool Capture::SaveFile()
306 {
307   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
308
309   return mNativeImageSourcePtr->EncodeToFile( mPath );
310 }
311
312 }  // End of namespace Adaptor
313
314 }  // End of namespace Internal
315
316 }  // End of namespace Dali