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