Make Capture api common.
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / common / capture-impl.cpp
1 /*
2  * Copyright (c) 2019 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 {
51 }
52
53 Capture::Capture( Dali::CameraActor cameraActor )
54 : mCameraActor( cameraActor ),
55   mTimer(),
56   mPath(),
57   mNativeImageSourcePtr( NULL )
58 {
59 }
60
61 Capture::~Capture()
62 {
63   DeleteNativeImageSource();
64 }
65
66 CapturePtr Capture::New()
67 {
68   CapturePtr pWorker = new Capture();
69
70   return pWorker;
71 }
72
73 CapturePtr Capture::New( Dali::CameraActor cameraActor )
74 {
75   CapturePtr pWorker = new Capture( cameraActor );
76
77   return pWorker;
78 }
79
80 void Capture::Start( Dali::Actor source, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor )
81 {
82   DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
83
84   // Increase the reference count focely to avoid application mistake.
85   Reference();
86
87   mPath = path;
88
89   DALI_ASSERT_ALWAYS(source && "Source is NULL.");
90
91   UnsetResources();
92   SetupResources( size, clearColor, source );
93 }
94
95 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
96 {
97   return mFinishedSignal;
98 }
99
100 void Capture::CreateNativeImageSource( const Vector2& size )
101 {
102   Dali::Adaptor& adaptor = Dali::Adaptor::Get();
103
104   DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
105
106   DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
107
108   // create the NativeImageSource object with our surface
109   mNativeImageSourcePtr = Dali::NativeImageSource::New( size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT );
110 }
111
112 void Capture::DeleteNativeImageSource()
113 {
114   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
115
116   mNativeImageSourcePtr.Reset();
117 }
118
119 bool Capture::IsNativeImageSourceCreated()
120 {
121   return mNativeImageSourcePtr;
122 }
123
124 void Capture::CreateFrameBuffer()
125 {
126   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
127
128   DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
129
130   mNativeTexture = Dali::Texture::New( *mNativeImageSourcePtr );
131
132   // Create a FrameBuffer object with depth attachments.
133   mFrameBuffer = Dali::FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH );
134   // Add a color attachment to the FrameBuffer object.
135   mFrameBuffer.AttachColorTexture( mNativeTexture );
136 }
137
138 void Capture::DeleteFrameBuffer()
139 {
140   DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
141
142   mFrameBuffer.Reset();
143   mNativeTexture.Reset();
144 }
145
146 bool Capture::IsFrameBufferCreated()
147 {
148   return mFrameBuffer;
149 }
150
151 void Capture::SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearColor )
152 {
153   DALI_ASSERT_ALWAYS(source && "Source is empty.");
154
155   mSource = source;
156
157   // Check the original parent about source.
158   mParent = mSource.GetParent();
159
160   Dali::Stage stage = Dali::Stage::GetCurrent();
161   Dali::Size stageSize = stage.GetSize();
162
163   // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
164   stage.Add( mSource );
165
166   if( !mCameraActor )
167   {
168     mCameraActor = Dali::CameraActor::New( stageSize );
169     mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
170     mCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
171   }
172
173   stage.Add( mCameraActor );
174
175   DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
176
177   DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
178
179   Dali::RenderTaskList taskList = stage.GetRenderTaskList();
180   mRenderTask = taskList.CreateTask();
181   mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
182   mRenderTask.SetSourceActor( source );
183   mRenderTask.SetCameraActor( mCameraActor );
184   mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
185   mRenderTask.SetFrameBuffer( mFrameBuffer );
186   mRenderTask.SetClearColor( clearColor );
187   mRenderTask.SetClearEnabled( true );
188   mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
189   mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
190   mRenderTask.GetCameraActor().SetInvertYAxis( true );
191
192   mTimer = Dali::Timer::New( TIME_OUT_DURATION );
193   mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
194   mTimer.Start();
195 }
196
197 void Capture::UnsetRenderTask()
198 {
199   DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
200
201   if( mParent )
202   {
203     // Restore the parent of source.
204     mParent.Add( mSource );
205     mParent.Reset();
206   }
207   else
208   {
209     mSource.Unparent();
210   }
211
212   mSource.Reset();
213
214   mTimer.Reset();
215
216   mCameraActor.Unparent();
217   mCameraActor.Reset();
218
219   DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
220
221   Dali::RenderTaskList taskList = Dali::Stage::GetCurrent().GetRenderTaskList();
222   taskList.RemoveTask( mRenderTask );
223   mRenderTask.Reset();
224 }
225
226 bool Capture::IsRenderTaskSetup()
227 {
228   return mCameraActor && mRenderTask;
229 }
230
231 void Capture::SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source )
232 {
233   CreateNativeImageSource( size );
234
235   CreateFrameBuffer();
236
237   SetupRenderTask( source, clearColor );
238 }
239
240 void Capture::UnsetResources()
241 {
242   if( IsRenderTaskSetup() )
243   {
244     UnsetRenderTask();
245   }
246
247   if( IsFrameBufferCreated() )
248   {
249     DeleteFrameBuffer();
250   }
251 }
252
253 void Capture::OnRenderFinished( Dali::RenderTask& task )
254 {
255   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
256
257   mTimer.Stop();
258
259   if( !Save() )
260   {
261     state = Dali::Capture::FinishState::FAILED;
262     DALI_LOG_ERROR("Fail to Capture Path[%s]", mPath.c_str());
263   }
264
265   Dali::Capture handle( this );
266   mFinishedSignal.Emit( handle, state );
267
268   UnsetResources();
269
270   // Decrease the reference count forcely. It is increased at Start().
271   Unreference();
272 }
273
274 bool Capture::OnTimeOut()
275 {
276   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
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   return false;
287 }
288
289 bool Capture::Save()
290 {
291   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
292
293   return mNativeImageSourcePtr->EncodeToFile( mPath );
294 }
295
296 }  // End of namespace Adaptor
297
298 }  // End of namespace Internal
299
300 }  // End of namespace Dali