0c9487e2751e225d16f8c5c428fc63a607e39e87
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / tizen-wayland / tizen-wearable / capture-impl-tizen.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/tizen-wayland/tizen-wearable/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   mTbmSurface( NULL )
51 {
52 }
53
54 Capture::Capture( Dali::CameraActor cameraActor )
55 : mCameraActor( cameraActor ),
56   mTimer(),
57   mPath(),
58   mNativeImageSourcePtr( NULL ),
59   mTbmSurface( NULL )
60 {
61 }
62
63 Capture::~Capture()
64 {
65 }
66
67 CapturePtr Capture::New()
68 {
69   CapturePtr pWorker = new Capture();
70
71   return pWorker;
72 }
73
74 CapturePtr Capture::New( Dali::CameraActor cameraActor )
75 {
76   CapturePtr pWorker = new Capture( cameraActor );
77
78   return pWorker;
79 }
80
81 void Capture::Start( Dali::Actor source, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor )
82 {
83   DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
84
85   // Increase the reference count focely to avoid application mistake.
86   Reference();
87
88   mPath = path;
89
90   DALI_ASSERT_ALWAYS(source && "Source is NULL.");
91
92   UnsetResources();
93   SetupResources( size, clearColor, source );
94 }
95
96 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
97 {
98   return mFinishedSignal;
99 }
100
101 void Capture::CreateSurface( const Vector2& size )
102 {
103   DALI_ASSERT_ALWAYS(!mTbmSurface && "mTbmSurface is already created.");
104
105   mTbmSurface = tbm_surface_create( size.width, size.height, TBM_FORMAT_RGBA8888 );
106 }
107
108 void Capture::DeleteSurface()
109 {
110   DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
111
112   tbm_surface_destroy( mTbmSurface );
113   mTbmSurface = NULL;
114 }
115
116 void Capture::ClearSurface( const Vector2& size )
117 {
118   DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
119
120   tbm_surface_info_s surface_info;
121
122   if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_WRITE, &surface_info ) == TBM_SURFACE_ERROR_NONE )
123   {
124     //DALI_ASSERT_ALWAYS(surface_info.bpp == 32 && "unsupported tbm format");
125
126     unsigned char* ptr = surface_info.planes[0].ptr;
127     memset( ptr, 0, surface_info.size ); // TODO: support color
128
129     if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
130     {
131       DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
132     }
133   }
134   else
135   {
136      DALI_ASSERT_ALWAYS(0 && "tbm_surface_map failed");
137   }
138 }
139
140 bool Capture::IsSurfaceCreated()
141 {
142   return mTbmSurface != 0;
143 }
144
145 void Capture::CreateNativeImageSource()
146 {
147   Dali::Adaptor& adaptor = Dali::Adaptor::Get();
148
149   DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
150
151   DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
152
153   DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
154
155   // create the NativeImageSource object with our surface
156   mNativeImageSourcePtr = Dali::NativeImageSource::New( mTbmSurface );
157 }
158
159 void Capture::DeleteNativeImageSource()
160 {
161   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
162
163   mNativeImageSourcePtr.Reset();
164 }
165
166 bool Capture::IsNativeImageSourceCreated()
167 {
168   return mNativeImageSourcePtr;
169 }
170
171 void Capture::CreateFrameBuffer()
172 {
173   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
174
175   DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
176
177   mNativeTexture = Dali::Texture::New( *mNativeImageSourcePtr );
178
179   // Create a FrameBuffer object with depth attachments.
180   mFrameBuffer = Dali::FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH );
181   // Add a color attachment to the FrameBuffer object.
182   mFrameBuffer.AttachColorTexture( mNativeTexture );
183 }
184
185 void Capture::DeleteFrameBuffer()
186 {
187   DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
188
189   mFrameBuffer.Reset();
190   mNativeTexture.Reset();
191 }
192
193 bool Capture::IsFrameBufferCreated()
194 {
195   return mFrameBuffer;
196 }
197
198 void Capture::SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearColor )
199 {
200   DALI_ASSERT_ALWAYS(source && "Source is empty.");
201
202   mSource = source;
203
204   // Check the original parent about source.
205   mParent = mSource.GetParent();
206
207   Dali::Stage stage = Dali::Stage::GetCurrent();
208   Dali::Size stageSize = stage.GetSize();
209
210   // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
211   stage.Add( mSource );
212
213   if( !mCameraActor )
214   {
215     mCameraActor = Dali::CameraActor::New( stageSize );
216     mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
217     mCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
218   }
219
220   stage.Add( mCameraActor );
221
222   DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
223
224   DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
225
226   Dali::RenderTaskList taskList = stage.GetRenderTaskList();
227   mRenderTask = taskList.CreateTask();
228   mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
229   mRenderTask.SetSourceActor( source );
230   mRenderTask.SetCameraActor( mCameraActor );
231   mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
232   mRenderTask.SetFrameBuffer( mFrameBuffer );
233   mRenderTask.SetClearColor( clearColor );
234   mRenderTask.SetClearEnabled( true );
235   mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
236   mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
237   mRenderTask.GetCameraActor().SetInvertYAxis( true );
238
239   mTimer = Dali::Timer::New( TIME_OUT_DURATION );
240   mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
241   mTimer.Start();
242 }
243
244 void Capture::UnsetRenderTask()
245 {
246   DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
247
248   if( mParent )
249   {
250     // Restore the parent of source.
251     mParent.Add( mSource );
252     mParent.Reset();
253   }
254   else
255   {
256     mSource.Unparent();
257   }
258
259   mSource.Reset();
260
261   mTimer.Reset();
262
263   mCameraActor.Unparent();
264   mCameraActor.Reset();
265
266   DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
267
268   Dali::RenderTaskList taskList = Dali::Stage::GetCurrent().GetRenderTaskList();
269   taskList.RemoveTask( mRenderTask );
270   mRenderTask.Reset();
271 }
272
273 bool Capture::IsRenderTaskSetup()
274 {
275   return mCameraActor && mRenderTask;
276 }
277
278 void Capture::SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source )
279 {
280   CreateSurface( size );
281   ClearSurface( size );
282
283   CreateNativeImageSource();
284
285   CreateFrameBuffer();
286
287   SetupRenderTask( source, clearColor );
288 }
289
290 void Capture::UnsetResources()
291 {
292   if( IsRenderTaskSetup() )
293   {
294     UnsetRenderTask();
295   }
296
297   if( IsFrameBufferCreated() )
298   {
299     DeleteFrameBuffer();
300   }
301
302   if( IsNativeImageSourceCreated() )
303   {
304     DeleteNativeImageSource();
305   }
306
307   if( IsSurfaceCreated() )
308   {
309     DeleteSurface();
310   }
311 }
312
313 void Capture::OnRenderFinished( Dali::RenderTask& task )
314 {
315   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
316
317   mTimer.Stop();
318
319   if( !Save() )
320   {
321     state = Dali::Capture::FinishState::FAILED;
322     DALI_LOG_ERROR("Fail to Capture mTbmSurface[%p] Path[%s]", mTbmSurface, mPath.c_str());
323   }
324
325   Dali::Capture handle( this );
326   mFinishedSignal.Emit( handle, state );
327
328   UnsetResources();
329
330   // Decrease the reference count forcely. It is increased at Start().
331   Unreference();
332 }
333
334 bool Capture::OnTimeOut()
335 {
336   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
337
338   Dali::Capture handle( this );
339   mFinishedSignal.Emit( handle, state );
340
341   UnsetResources();
342
343   // Decrease the reference count forcely. It is increased at Start().
344   Unreference();
345
346   return false;
347 }
348
349 bool Capture::Save()
350 {
351   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
352
353   return mNativeImageSourcePtr->EncodeToFile( mPath );
354 }
355
356 }  // End of namespace Adaptor
357
358 }  // End of namespace Internal
359
360 }  // End of namespace Dali