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