[Tizen] Fix build errors on Ubuntu
[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/vector-wrapper.h>
25 #include <dali/public-api/render-tasks/render-task-list.h>
26 #include <dali/integration-api/debug.h>
27
28 // INTERNAL INCLUDES
29 #include <dali/integration-api/adaptor-framework/adaptor.h>
30 #include <dali/devel-api/adaptor-framework/native-image-source-devel.h>
31 #include <dali/devel-api/adaptor-framework/window-devel.h>
32 #include <dali/devel-api/adaptor-framework/bitmap-saver.h>
33 #include <dali/internal/adaptor/common/adaptor-impl.h>
34 #include <dali/internal/graphics/gles/egl-graphics.h>
35
36 namespace Dali
37 {
38
39 namespace Internal
40 {
41
42 namespace Adaptor
43 {
44
45 namespace
46 {
47 constexpr int32_t VERSION_NATIVE_IMAGE_SOURCE = 30;
48 constexpr uint32_t TIME_OUT_DURATION = 1000;
49 }
50
51 Capture::Capture()
52 : mQuality( DEFAULT_QUALITY ),
53   mTimer(),
54   mPath(),
55   mNativeImageSourcePtr( NULL ),
56   mFileSave( false ),
57   mIsNativeImageSourcePossible(true)
58 {
59 }
60
61 Capture::Capture( Dali::CameraActor cameraActor )
62 : mQuality( DEFAULT_QUALITY ),
63   mCameraActor( cameraActor ),
64   mTimer(),
65   mPath(),
66   mNativeImageSourcePtr( NULL ),
67   mFileSave( false ),
68   mIsNativeImageSourcePossible(true)
69 {
70 }
71
72 Capture::~Capture()
73 {
74   DeleteNativeImageSource();
75   mTexture.Reset();
76 }
77
78 CapturePtr Capture::New()
79 {
80   CapturePtr pWorker = new Capture();
81
82   return pWorker;
83 }
84
85 CapturePtr Capture::New( Dali::CameraActor cameraActor )
86 {
87   CapturePtr pWorker = new Capture( cameraActor );
88
89   return pWorker;
90 }
91
92 void Capture::Start( Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor, const uint32_t quality )
93 {
94   mQuality = quality;
95   Start( source, position, size, path, clearColor );
96 }
97
98 void Capture::Start( Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor )
99 {
100   DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
101
102   // Increase the reference count focely to avoid application mistake.
103   Reference();
104
105   mPath = path;
106   if( mPath.size() > 0 )
107   {
108     mFileSave = true;
109   }
110
111   DALI_ASSERT_ALWAYS(source && "Source is NULL.");
112
113   UnsetResources();
114   SetupResources( position, size, clearColor, source );
115 }
116
117 void Capture::SetImageQuality( uint32_t quality )
118 {
119   mQuality = quality;
120 }
121
122 Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
123 {
124   return mNativeImageSourcePtr;
125 }
126
127 Dali::Texture Capture::GetTexture()
128 {
129   return mTexture;
130 }
131
132 Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
133 {
134   return mFinishedSignal;
135 }
136
137 void Capture::CreateTexture(const Vector2& size)
138 {
139   Dali::Adaptor& adaptor = Dali::Adaptor::Get();
140
141   DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
142
143   if(mIsNativeImageSourcePossible)
144   {
145     DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
146     // create the NativeImageSource object with our surface
147     mNativeImageSourcePtr = Dali::NativeImageSource::New(size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT);
148     mTexture              = Dali::Texture::New(*mNativeImageSourcePtr);
149   }
150   else
151   {
152     mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(size.width), unsigned(size.height));
153   }
154 }
155
156 void Capture::DeleteNativeImageSource()
157 {
158   if(mNativeImageSourcePtr)
159   {
160     mNativeImageSourcePtr.Reset();
161   }
162 }
163
164 void Capture::CreateFrameBuffer()
165 {
166   DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
167
168   // Create a FrameBuffer object with depth attachments.
169   mFrameBuffer = Dali::FrameBuffer::New(mTexture.GetWidth(), mTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
170   // Add a color attachment to the FrameBuffer object.
171   mFrameBuffer.AttachColorTexture(mTexture);
172 }
173
174 void Capture::DeleteFrameBuffer()
175 {
176   DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
177
178   mFrameBuffer.Reset();
179 }
180
181 bool Capture::IsFrameBufferCreated()
182 {
183   return mFrameBuffer;
184 }
185
186 void Capture::SetupRenderTask( const Dali::Vector2& position, const Dali::Vector2& size, Dali::Actor source, const Dali::Vector4& clearColor )
187 {
188   DALI_ASSERT_ALWAYS(source && "Source is empty.");
189
190   Dali::Window window = DevelWindow::Get( source );
191   if( !window )
192   {
193     DALI_LOG_ERROR("The source is not added on the window\n");
194     return;
195   }
196
197   mSource = source;
198
199   if( !mCameraActor )
200   {
201     mCameraActor = Dali::CameraActor::New( size );
202     // Because input position and size are for 2 dimentional area,
203     // default z-directional position of the camera is required to be used for the new camera position.
204     float cameraDefaultZPosition = mCameraActor.GetProperty<float>( Dali::Actor::Property::POSITION_Z );
205     Vector2 positionTransition = position + size / 2;
206     mCameraActor.SetProperty( Dali::Actor::Property::POSITION, Vector3( positionTransition.x, positionTransition.y, cameraDefaultZPosition ) );
207     mCameraActor.SetProperty( Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
208     mCameraActor.SetProperty( Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
209   }
210
211   window.Add( mCameraActor );
212
213   DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
214
215   DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
216
217   Dali::RenderTaskList taskList = window.GetRenderTaskList();
218   mRenderTask = taskList.CreateTask();
219   mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
220   mRenderTask.SetSourceActor( source );
221   mRenderTask.SetCameraActor( mCameraActor );
222   mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
223   mRenderTask.SetFrameBuffer( mFrameBuffer );
224   mRenderTask.SetClearColor( clearColor );
225   mRenderTask.SetClearEnabled( true );
226   mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
227   mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
228   mRenderTask.GetCameraActor().SetInvertYAxis( true );
229   if(!mIsNativeImageSourcePossible)
230   {
231     mFrameBuffer.CaptureRenderedResult();
232   }
233
234   mTimer = Dali::Timer::New( TIME_OUT_DURATION );
235   mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
236   mTimer.Start();
237 }
238
239 void Capture::UnsetRenderTask()
240 {
241   DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
242
243   mTimer.Reset();
244
245   mCameraActor.Unparent();
246   mCameraActor.Reset();
247
248   DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
249
250   Dali::Window window = DevelWindow::Get( mSource );
251   Dali::RenderTaskList taskList = window.GetRenderTaskList();
252   taskList.RemoveTask( mRenderTask );
253   mRenderTask.Reset();
254   mSource.Reset();
255 }
256
257 bool Capture::IsRenderTaskSetup()
258 {
259   return mCameraActor && mRenderTask;
260 }
261
262 void Capture::SetupResources(const Dali::Vector2& position, const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source)
263 {
264   Dali::Internal::Adaptor::Adaptor& adaptor     = Internal::Adaptor::Adaptor::GetImplementation(Internal::Adaptor::Adaptor::Get());
265   GraphicsInterface*                graphics    = &adaptor.GetGraphicsInterface();
266   auto                              eglGraphics = static_cast<EglGraphics*>(graphics);
267
268   if(eglGraphics->GetEglImplementation().GetGlesVersion() < VERSION_NATIVE_IMAGE_SOURCE)
269   {
270     mIsNativeImageSourcePossible = false;
271   }
272
273   CreateTexture(size);
274
275   CreateFrameBuffer();
276
277   SetupRenderTask( position, size, source, clearColor );
278 }
279
280 void Capture::UnsetResources()
281 {
282   if( IsRenderTaskSetup() )
283   {
284     UnsetRenderTask();
285   }
286
287   if( IsFrameBufferCreated() )
288   {
289     DeleteFrameBuffer();
290   }
291 }
292
293 void Capture::OnRenderFinished( Dali::RenderTask& task )
294 {
295   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
296
297   mTimer.Stop();
298
299   if( mFileSave )
300   {
301     if( !SaveFile() )
302     {
303       state = Dali::Capture::FinishState::FAILED;
304       DALI_LOG_ERROR( "Fail to Capture Path[%s]", mPath.c_str() );
305     }
306   }
307
308   Dali::Capture handle( this );
309   mFinishedSignal.Emit( handle, state );
310
311   UnsetResources();
312
313   // Decrease the reference count forcely. It is increased at Start().
314   Unreference();
315 }
316
317 bool Capture::OnTimeOut()
318 {
319   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
320
321   Dali::Capture handle( this );
322   mFinishedSignal.Emit( handle, state );
323
324   UnsetResources();
325
326   // Decrease the reference count forcely. It is increased at Start().
327   Unreference();
328
329   return false;
330 }
331
332 bool Capture::SaveFile()
333 {
334   if(mIsNativeImageSourcePossible)
335   {
336     DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
337     return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
338   }
339   else
340   {
341     uint8_t* buffer = mFrameBuffer.GetRenderedBuffer();
342     return Dali::EncodeToFile(buffer, mPath, Dali::Pixel::RGBA8888, mTexture.GetWidth(), mTexture.GetHeight(), mQuality);
343   }
344 }
345
346 }  // End of namespace Adaptor
347
348 }  // End of namespace Internal
349
350 }  // End of namespace Dali