2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/public-api/common/vector-wrapper.h>
21 #include <dali/integration-api/debug.h>
22 #include <dali/integration-api/adaptors/adaptor.h>
28 #include <dali-extension/internal/capture/capture-impl.h>
30 #define ENABLED_CAPTURE_LOGGING
32 #ifdef ENABLED_CAPTURE_LOGGING
33 #define DALI_CAPTURE_STATE(format, args...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, "%s:%d " format "\n", __PRETTY_FUNCTION__, __LINE__, ## args)
35 #define DALI_CAPTURE_STATE(format, args...)
40 unsigned int TIME_OUT_DURATION = 1000;
53 : mProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION)
55 , mFinishState(Dali::Extension::Capture::FAILED)
59 Capture::Capture(Dali::Camera::ProjectionMode mode)
60 : mProjectionMode(mode)
62 , mFinishState(Dali::Extension::Capture::FAILED)
66 CapturePtr Capture::New()
68 CapturePtr pWorker = new Capture();
70 // Second-phase construction
71 pWorker->Initialize();
76 CapturePtr Capture::New(Dali::Camera::ProjectionMode mode)
78 CapturePtr pWorker = new Capture(mode);
80 // Second-phase construction
81 pWorker->Initialize();
86 void Capture::Start(Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor)
88 DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
90 // Increase the reference count focely to avoid application mistake.
95 DALI_CAPTURE_STATE("Start Size[%.2f, %.2f] Path[%s]", size.width, size.height, path.c_str());
97 DALI_ASSERT_ALWAYS(source && "Source is NULL.");
100 SetupResources(size, clearColor, source);
103 Dali::Extension::Capture::FinishState Capture::GetFinishState()
108 Dali::Extension::Capture::CaptureSignalType& Capture::FinishedSignal()
110 return mFinishedSignal;
113 void Capture::Initialize()
121 void Capture::CreateSurface(const Vector2& size)
123 DALI_ASSERT_ALWAYS(!mTbmSurface && "mTbmSurface is already created.");
125 mTbmSurface = tbm_surface_create(size.width, size.height, TBM_FORMAT_RGBA8888);
126 DALI_CAPTURE_STATE("Create mTbmSurface[%p]", mTbmSurface);
129 void Capture::DeleteSurface()
131 DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
133 DALI_CAPTURE_STATE("Delete mTbmSurface[%p]", mTbmSurface);
135 tbm_surface_destroy(mTbmSurface);
139 void Capture::ClearSurface(const Vector2& size)
141 DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
143 tbm_surface_info_s surface_info;
145 if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_WRITE, &surface_info) == TBM_SURFACE_ERROR_NONE )
147 //DALI_ASSERT_ALWAYS(surface_info.bpp == 32 && "unsupported tbm format");
149 unsigned char* ptr = surface_info.planes[0].ptr;
150 memset( ptr, 0, surface_info.size ); // TODO: support color
152 if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
154 DALI_CAPTURE_STATE( "Fail to unmap tbm_surface\n" );
159 DALI_ASSERT_ALWAYS(0 && "tbm_surface_map failed");
162 DALI_CAPTURE_STATE("Clear mTbmSurface[%p]", mTbmSurface);
165 bool Capture::IsSurfaceCreated()
167 return mTbmSurface != 0;
170 void Capture::CreateNativeImageSource()
172 Dali::Adaptor& adaptor = Dali::Adaptor::Get();
174 DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
176 DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
178 DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
180 // create the NativeImageSource object with our surface
181 mNativeImageSourcePtr = NativeImageSource::New(Dali::Any(mTbmSurface));
183 DALI_CAPTURE_STATE("Create NativeImageSource[0x%X]", mNativeImageSourcePtr.Get());
186 void Capture::DeleteNativeImageSource()
188 DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
190 DALI_CAPTURE_STATE("Delete NativeImageSource[0x%X]", mNativeImageSourcePtr.Get());
192 mNativeImageSourcePtr.Reset();
195 bool Capture::IsNativeImageSourceCreated()
197 return mNativeImageSourcePtr;
200 void Capture::CreateFrameBuffer()
202 DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
204 DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
206 mNativeTexture = Texture::New( *mNativeImageSourcePtr );
208 // Create a FrameBuffer object with no default attachments.
209 mFrameBuffer = FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), FrameBuffer::Attachment::NONE );
210 // Add a color attachment to the FrameBuffer object.
211 mFrameBuffer.AttachColorTexture( mNativeTexture );
213 DALI_CAPTURE_STATE("Create FrameBuffer");
216 void Capture::DeleteFrameBuffer()
218 DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
220 DALI_CAPTURE_STATE("Delete FrameBuffer");
222 mFrameBuffer.Reset();
223 mNativeTexture.Reset();
226 bool Capture::IsFrameBufferCreated()
231 void Capture::SetupRenderTask(Actor source, const Vector4& clearColor)
233 DALI_ASSERT_ALWAYS(source && "Source is empty.");
237 // Check the original parent about source.
238 mParent = mSource.GetParent();
240 Stage stage = Stage::GetCurrent();
241 Size stageSize = stage.GetSize();
243 // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
246 DALI_ASSERT_ALWAYS(!mCameraActor && "CameraActor is already created.");
248 mCameraActor = CameraActor::New( stageSize );
249 mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
250 mCameraActor.SetAnchorPoint(AnchorPoint::CENTER);
252 if(mProjectionMode == Camera::ORTHOGRAPHIC_PROJECTION)
254 mCameraActor.SetOrthographicProjection(stageSize);
256 stage.Add(mCameraActor);
258 DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
260 DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
262 RenderTaskList taskList = stage.GetRenderTaskList();
263 mRenderTask = taskList.CreateTask();
264 mRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
265 mRenderTask.SetSourceActor(source);
266 mRenderTask.SetCameraActor(mCameraActor);
267 mRenderTask.SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
268 mRenderTask.SetFrameBuffer(mFrameBuffer);
269 mRenderTask.SetClearColor( clearColor );
270 mRenderTask.SetClearEnabled( true );
271 mRenderTask.SetProperty( RenderTask::Property::REQUIRES_SYNC, true );
272 mRenderTask.FinishedSignal().Connect(this, &Capture::OnRenderFinished);
273 mRenderTask.GetCameraActor().SetInvertYAxis( true );
275 mTimer = Timer::New(TIME_OUT_DURATION);
276 mTimer.TickSignal().Connect(this, &Capture::OnTimeOut);
279 DALI_CAPTURE_STATE("Setup Camera and RenderTask.");
282 void Capture::UnsetRenderTask()
284 DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
286 DALI_CAPTURE_STATE("Unset Camera and RenderTask");
290 // Restore the parent of source.
291 mParent.Add(mSource);
303 mCameraActor.Unparent();
304 mCameraActor.Reset();
306 DALI_ASSERT_ALWAYS(mRenderTask && "RenderTask is NULL.");
308 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
309 RenderTask firstTask = taskList.GetTask( 0u );
311 // Stop rendering via frame-buffers as empty handle is used to clear target
312 firstTask.SetFrameBuffer(FrameBuffer());
314 taskList.RemoveTask(mRenderTask);
318 bool Capture::IsRenderTaskSetup()
320 return mCameraActor && mRenderTask;
323 void Capture::SetupResources(const Vector2& size, const Vector4& clearColor, Actor source)
328 CreateNativeImageSource();
332 SetupRenderTask(source, clearColor);
334 DALI_CAPTURE_STATE("Setup Resources");
337 void Capture::UnsetResources()
339 if (IsRenderTaskSetup())
344 if (IsFrameBufferCreated())
349 if (IsNativeImageSourceCreated())
351 DeleteNativeImageSource();
354 if (IsSurfaceCreated())
359 DALI_CAPTURE_STATE("Unset Resources");
362 void Capture::OnRenderFinished(RenderTask& task)
364 DALI_CAPTURE_STATE("Render finished");
366 mFinishState = Dali::Extension::Capture::SUCCESSED;
372 mFinishState = Dali::Extension::Capture::FAILED;
373 DALI_LOG_ERROR("Fail to Capture mTbmSurface[%p] Path[%s]", mTbmSurface, mPath.c_str());
376 Dali::Extension::Capture handle(this);
377 mFinishedSignal.Emit(handle);
381 // Decrease the reference count forcely. It is increased at Start().
385 bool Capture::OnTimeOut()
387 DALI_CAPTURE_STATE("Timeout");
389 mFinishState = Dali::Extension::Capture::FAILED;
391 Dali::Extension::Capture handle(this);
392 mFinishedSignal.Emit(handle);
396 // Decrease the reference count forcely. It is increased at Start().
404 DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
406 return mNativeImageSourcePtr->EncodeToFile(mPath);
409 } // End of namespace Internal
411 } // End of namespace Extension
413 } // End of namespace Dali