Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / 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   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 no default attachments.
180   mFrameBuffer = Dali::FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::NONE );
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   Dali::RenderTask firstTask = taskList.GetTask( 0u );
270
271   // Stop rendering via frame-buffers as empty handle is used to clear target
272   firstTask.SetFrameBuffer( Dali::FrameBuffer() );
273
274   taskList.RemoveTask( mRenderTask );
275   mRenderTask.Reset();
276 }
277
278 bool Capture::IsRenderTaskSetup()
279 {
280   return mCameraActor && mRenderTask;
281 }
282
283 void Capture::SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source )
284 {
285   CreateSurface( size );
286   ClearSurface( size );
287
288   CreateNativeImageSource();
289
290   CreateFrameBuffer();
291
292   SetupRenderTask( source, clearColor );
293 }
294
295 void Capture::UnsetResources()
296 {
297   if( IsRenderTaskSetup() )
298   {
299     UnsetRenderTask();
300   }
301
302   if( IsFrameBufferCreated() )
303   {
304     DeleteFrameBuffer();
305   }
306
307   if( IsNativeImageSourceCreated() )
308   {
309     DeleteNativeImageSource();
310   }
311
312   if( IsSurfaceCreated() )
313   {
314     DeleteSurface();
315   }
316 }
317
318 void Capture::OnRenderFinished( Dali::RenderTask& task )
319 {
320   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
321
322   mTimer.Stop();
323
324   if( !Save() )
325   {
326     state = Dali::Capture::FinishState::FAILED;
327     DALI_LOG_ERROR("Fail to Capture mTbmSurface[%p] Path[%s]", mTbmSurface, mPath.c_str());
328   }
329
330   Dali::Capture handle( this );
331   mFinishedSignal.Emit( handle, state );
332
333   UnsetResources();
334
335   // Decrease the reference count forcely. It is increased at Start().
336   Unreference();
337 }
338
339 bool Capture::OnTimeOut()
340 {
341   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
342
343   Dali::Capture handle( this );
344   mFinishedSignal.Emit( handle, state );
345
346   UnsetResources();
347
348   // Decrease the reference count forcely. It is increased at Start().
349   Unreference();
350
351   return false;
352 }
353
354 bool Capture::Save()
355 {
356   DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
357
358   return mNativeImageSourcePtr->EncodeToFile( mPath );
359 }
360
361 }  // End of namespace Adaptor
362
363 }  // End of namespace Internal
364
365 }  // End of namespace Dali