[Tizen] Import Extension::Capture to support backward compatibility accepted/tizen/unified/20190605.215622 accepted/tizen/unified/20190606.220057 submit/tizen/20190605.005205 submit/tizen/20190605.094818
authorSunghyun kim <scholb.kim@samsung.com>
Tue, 4 Jun 2019 09:19:03 +0000 (18:19 +0900)
committerSunghyun kim <scholb.kim@samsung.com>
Tue, 4 Jun 2019 09:19:05 +0000 (18:19 +0900)
This reverts commit ebd0abe2809198b787d257155bac7c98e21b21fb.

Change-Id: I8ad2bd63e534be5fcff7781402a32be2ce096545

12 files changed:
build/tizen/configure.ac
build/tizen/dali-extension/Makefile.am [moved from build/tizen/evas-plugin/Makefile.am with 67% similarity]
build/tizen/dali-extension/configure.ac [moved from build/tizen/evas-plugin/configure.ac with 87% similarity]
dali-extension/dali-extension.h
dali-extension/devel-api/capture/capture.cpp [new file with mode: 0755]
dali-extension/devel-api/capture/capture.h [new file with mode: 0644]
dali-extension/devel-api/capture/file.list [new file with mode: 0644]
dali-extension/devel-api/evas-plugin/file.list
dali-extension/internal/capture/capture-impl.cpp [new file with mode: 0755]
dali-extension/internal/capture/capture-impl.h [new file with mode: 0755]
dali-extension/internal/capture/file.list [new file with mode: 0644]
packaging/dali-extension.spec

index ac23e70..99b1911 100755 (executable)
@@ -32,7 +32,7 @@ if test "x$with_tizen_55_or_greater" = "xyes"; then
   AC_CONFIG_SUBDIRS(web-engine-chromium)
   AC_CONFIG_SUBDIRS(web-engine-lwe)
 fi
-AC_CONFIG_SUBDIRS(evas-plugin)
+AC_CONFIG_SUBDIRS(dali-extension)
 
 devincludepath=${includedir}
 AC_SUBST(devincludepath)
similarity index 67%
rename from build/tizen/evas-plugin/Makefile.am
rename to build/tizen/dali-extension/Makefile.am
index 5073ba6..89cee34 100755 (executable)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015 Samsung Electronics Co., Ltd.
+# Copyright (c) 2019 Samsung Electronics Co., Ltd.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # limitations under the License.
 #
 
-# Build the Dali evas plugin
+# Build the Dali extension library
 
 extension_src_dir = ../../../dali-extension
 
 # evas-plugin
 include ../../../dali-extension/devel-api/evas-plugin/file.list
 include ../../../dali-extension/internal/evas-plugin/file.list
+# capture
+include ../../../dali-extension/devel-api/capture/file.list
+include ../../../dali-extension/internal/capture/file.list
 
 lib_LTLIBRARIES =
 
@@ -28,27 +31,36 @@ lib_LTLIBRARIES += libdali-extension.la
 
 # Todo Evas plugin separation
 libdali_extension_la_SOURCES = \
-                       $(evas_plugin_public_src_files) \
-                       $(evas_plugin_internal_src_files)
+                       $(evas_plugin_devel_src_files) \
+                       $(evas_plugin_internal_src_files) \
+                       $(capture_devel_src_files) \
+                       $(capture_internal_src_files)
 
 libdali_extension_la_DEPENDENCIES =
 
 libdali_extension_la_CXXFLAGS = \
                        $(DLOG_CFLAGS) \
+                       $(DALI_CFLAGS) \
+                       $(DALI_EXTENSION_CFLAGS) \
                        $(DALI_ADAPTOR_INTEGRATION_CFLAGS) \
                        $(ELEMENTARY_CFLAGS) \
                        $(EVAS_CFLAGS) \
                        $(WAYLAND_CFLAGS) \
+                       $(LIBTBM_CFLAGS) \
+                       $(LIBPNG_CFLAGS) \
                        -DEFL_BETA_API_SUPPORT \
                        -I../../../ \
                        -Werror -Wall
 
 libdali_extension_la_LIBADD = \
                        $(DLOG_LIBS) \
+                       $(DALI_LIBS) \
                        $(DALI_ADAPTOR_INTEGRATION_LIBS) \
                        $(ELEMENTARY_LIBS) \
                        $(EVAS_LIBS) \
-                       $(WAYLAND_LIBS)
+                       $(WAYLAND_LIBS) \
+                       $(LIBTBM_LIBS) \
+                       $(LIBPNG_LIBS)
 
 libdali_extension_la_LDFLAGS = \
                        -rdynamic
@@ -57,5 +69,8 @@ libdali_extension_la_LDFLAGS = \
 dali_extensiondir = $(devincludepath)/dali-extension
 dali_extension_HEADERS = ../../../dali-extension/dali-extension.h
 
+dali_extension_capturedir = $(devincludepath)/dali-extension/devel-api/capture
+dali_extension_capture_HEADERS = $(capture_devel_header_files)
+
 dali_extension_evasplugindir = $(devincludepath)/dali-extension/devel-api/evas-plugin
-dali_extension_evasplugin_HEADERS = $(evas_plugin_public_header_files)
+dali_extension_evasplugin_HEADERS = $(evas_plugin_devel_header_files)
similarity index 87%
rename from build/tizen/evas-plugin/configure.ac
rename to build/tizen/dali-extension/configure.ac
index 06b5c12..add46a1 100755 (executable)
@@ -20,6 +20,10 @@ PKG_CHECK_MODULES(ELEMENTARY, elementary)
 PKG_CHECK_MODULES(EVAS, evas)
 PKG_CHECK_MODULES(WAYLAND, [ecore-wl2])
 
+# For capture
+PKG_CHECK_MODULES(LIBTBM, libtbm)
+PKG_CHECK_MODULES(LIBPNG, libpng)
+
 devincludepath=${includedir}
 AC_SUBST(devincludepath)
 
index 762dd96..d3f68ac 100644 (file)
@@ -18,6 +18,7 @@
  *
  */
 
+#include <dali-extension/devel-api/capture/capture.h>
 #include <dali-extension/devel-api/evas-plugin/evas-plugin.h>
 
 #endif // __DALI_EXTENSION_H__
diff --git a/dali-extension/devel-api/capture/capture.cpp b/dali-extension/devel-api/capture/capture.cpp
new file mode 100755 (executable)
index 0000000..b490abc
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-extension/devel-api/capture/capture.h>
+#include <dali-extension/internal/capture/capture-impl.h>
+
+namespace Dali
+{
+
+namespace Extension
+{
+
+Capture::Capture()
+{
+}
+
+Capture Capture::New()
+{
+  Internal::CapturePtr internal = Internal::Capture::New();
+
+  return Capture(internal.Get());
+}
+
+Capture Capture::New(Dali::Camera::ProjectionMode mode)
+{
+  Internal::CapturePtr internal = Internal::Capture::New(mode);
+
+  return Capture(internal.Get());
+}
+
+Capture Capture::DownCast(BaseHandle handle)
+{
+  return Capture(dynamic_cast<Internal::Capture*>(handle.GetObjectPtr()));
+}
+
+Capture::~Capture()
+{
+}
+
+Capture::Capture(const Capture& copy)
+: BaseHandle(copy)
+{
+}
+
+Capture& Capture::operator=(const Capture& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void Capture::Start(Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor )
+{
+  GetImpl(*this).Start(source, size, path, clearColor);
+}
+
+Capture::FinishState Capture::GetFinishState()
+{
+  return GetImpl(*this).GetFinishState();
+}
+
+Capture::CaptureSignalType& Capture::FinishedSignal()
+{
+  return GetImpl(*this).FinishedSignal();
+}
+
+Capture::Capture(Internal::Capture* internal)
+: BaseHandle(internal)
+{
+}
+
+} // namespace Extension
+
+} // namespace Dali
diff --git a/dali-extension/devel-api/capture/capture.h b/dali-extension/devel-api/capture/capture.h
new file mode 100644 (file)
index 0000000..8a9998e
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef __DALI_EXTENSION_CAPTURE_H__
+#define __DALI_EXTENSION_CAPTURE_H__
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @addtogroup CAPI_DALI_EXTENSION_FRAMEWORK_MODULE
+ * @{
+ */
+
+// EXTERNAL HEADERS
+#include <dali/dali.h>
+
+// INTERNAL HEADERS
+
+namespace Dali
+{
+
+namespace Extension
+{
+
+namespace Internal
+{
+class Capture;
+}
+
+/**
+ * @brief Capture snapshots the current scene and save as a file.
+ *
+ * Applications should follow the example below to create capture :
+ *
+ * @code
+ * Capture capture = Capture::New();
+ * @endcode
+ *
+ * If required, you can also connect class member function to a signal :
+ *
+ * @code
+ * capture.FinishedSignal().Connect(this, &CaptureSceneExample::OnCaptureFinished);
+ * @endcode
+ *
+ * At the connected class member function, you can know whether capture finish state.
+ *
+ * @code
+ * void CaptureSceneExample::OnCaptureFinished(Capture capture)
+ * {
+ *   if (capture.GetFinishState() == Capture::SUCCESSED)
+ *   {
+ *     // Do something
+ *   }
+ *   else
+ *   {
+ *     // Do something
+ *   }
+ * }
+ * @endcode
+ */
+class DALI_IMPORT_API Capture : public BaseHandle
+{
+public:
+  enum FinishState
+  {
+    SUCCESSED,
+    FAILED
+  };
+
+  /**
+   * @brief Typedef for signals sent by this class.
+   */
+  typedef Signal< void (Capture) > CaptureSignalType;
+
+  /**
+   * @brief Create an uninitialized Capture; this can be initialized with Actor::New().
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  Capture();
+
+  /**
+   * @brief Create an initialized Capture.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static Capture New();
+
+  /**
+   * @brief Create an initialized Capture.
+   *
+   * @param[in] mode camera projection mode.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static Capture New(Dali::Camera::ProjectionMode mode);
+
+  /**
+   * @brief Downcast an Object handle to Capture handle.
+   *
+   * If handle points to a Capture object the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object.
+   * @return handle to a Capture object or an uninitialized handle.
+   */
+  static Capture DownCast( BaseHandle handle );
+
+  /**
+   * @brief Dali::Actor is intended as a base class.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Capture();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] copy A reference to the copied handle.
+   */
+  Capture(const Capture& copy);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param[in] rhs  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  Capture& operator=(const Capture& rhs);
+
+  /**
+   * @brief Start capture and save the image as a file.
+   *
+   * @param[in] source source actor to be used for capture.
+   * @param[in] size captured size.
+   * @param[in] path image file path to be saved as a file.
+   * @param[in] clearColor background color of captured scene
+   */
+  void Start(Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor = Dali::Color::TRANSPARENT );
+
+  /**
+   * @brief Retrieve the capture finish status.
+   *
+   * @return Whether success or not.
+   */
+  FinishState GetFinishState();
+
+  /**
+   * @brief Get finished signal.
+   *
+   * @return finished signal instance.
+   */
+  CaptureSignalType& FinishedSignal();
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used by New() methods.
+   *
+   * @param[in] internal A pointer to a newly allocated Dali resource.
+   */
+  explicit DALI_INTERNAL Capture(Internal::Capture* internal);
+};
+
+} // namespace Extension
+
+} // namespace Dali
+
+/**
+ * @}
+ */
+
+#endif // __DALI_EXTENSION_CAPTURE_H__
diff --git a/dali-extension/devel-api/capture/file.list b/dali-extension/devel-api/capture/file.list
new file mode 100644 (file)
index 0000000..ddd0f93
--- /dev/null
@@ -0,0 +1,5 @@
+capture_devel_header_files = \
+   $(extension_src_dir)/devel-api/capture/capture.h
+
+capture_devel_src_files = \
+   $(extension_src_dir)/devel-api/capture/capture.cpp
index 6f1cafe..7796046 100644 (file)
@@ -1,5 +1,5 @@
-evas_plugin_public_header_files = \
+evas_plugin_devel_header_files = \
    $(extension_src_dir)/devel-api/evas-plugin/evas-plugin.h
 
-evas_plugin_public_src_files = \
+evas_plugin_devel_src_files = \
    $(extension_src_dir)/devel-api/evas-plugin/evas-plugin.cpp
diff --git a/dali-extension/internal/capture/capture-impl.cpp b/dali-extension/internal/capture/capture-impl.cpp
new file mode 100755 (executable)
index 0000000..3f0ad18
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptors/adaptor.h>
+
+#include <fstream>
+#include <string.h>
+
+// INTERNAL INCLUDES
+#include <dali-extension/internal/capture/capture-impl.h>
+
+#define ENABLED_CAPTURE_LOGGING
+
+#ifdef ENABLED_CAPTURE_LOGGING
+#define DALI_CAPTURE_STATE(format, args...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, "%s:%d " format "\n", __PRETTY_FUNCTION__, __LINE__, ## args)
+#else
+#define DALI_CAPTURE_STATE(format, args...)
+#endif
+
+namespace
+{
+unsigned int TIME_OUT_DURATION = 1000;
+}
+
+namespace Dali
+{
+
+namespace Extension
+{
+
+namespace Internal
+{
+
+Capture::Capture()
+: mProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION)
+, mTbmSurface(NULL)
+, mFinishState(Dali::Extension::Capture::FAILED)
+{
+}
+
+Capture::Capture(Dali::Camera::ProjectionMode mode)
+: mProjectionMode(mode)
+, mTbmSurface(NULL)
+, mFinishState(Dali::Extension::Capture::FAILED)
+{
+}
+
+CapturePtr Capture::New()
+{
+  CapturePtr pWorker = new Capture();
+
+  // Second-phase construction
+  pWorker->Initialize();
+
+  return pWorker;
+}
+
+CapturePtr Capture::New(Dali::Camera::ProjectionMode mode)
+{
+  CapturePtr pWorker = new Capture(mode);
+
+  // Second-phase construction
+  pWorker->Initialize();
+
+  return pWorker;
+}
+
+void Capture::Start(Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor)
+{
+  DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
+
+  // Increase the reference count focely to avoid application mistake.
+  Reference();
+
+  mPath = path;
+
+  DALI_CAPTURE_STATE("Start Size[%.2f, %.2f] Path[%s]", size.width, size.height, path.c_str());
+
+  DALI_ASSERT_ALWAYS(source && "Source is NULL.");
+
+  UnsetResources();
+  SetupResources(size, clearColor, source);
+}
+
+Dali::Extension::Capture::FinishState Capture::GetFinishState()
+{
+  return mFinishState;
+}
+
+Dali::Extension::Capture::CaptureSignalType& Capture::FinishedSignal()
+{
+  return mFinishedSignal;
+}
+
+void Capture::Initialize()
+{
+}
+
+Capture::~Capture()
+{
+}
+
+void Capture::CreateSurface(const Vector2& size)
+{
+  DALI_ASSERT_ALWAYS(!mTbmSurface && "mTbmSurface is already created.");
+
+  mTbmSurface = tbm_surface_create(size.width, size.height, TBM_FORMAT_RGBA8888);
+  DALI_CAPTURE_STATE("Create mTbmSurface[%p]", mTbmSurface);
+}
+
+void Capture::DeleteSurface()
+{
+  DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
+
+  DALI_CAPTURE_STATE("Delete mTbmSurface[%p]", mTbmSurface);
+
+  tbm_surface_destroy(mTbmSurface);
+  mTbmSurface = NULL;
+}
+
+void Capture::ClearSurface(const Vector2& size)
+{
+  DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
+
+  tbm_surface_info_s surface_info;
+
+  if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_WRITE, &surface_info) == TBM_SURFACE_ERROR_NONE )
+  {
+    //DALI_ASSERT_ALWAYS(surface_info.bpp == 32 && "unsupported tbm format");
+
+    unsigned char* ptr = surface_info.planes[0].ptr;
+    memset( ptr, 0, surface_info.size ); // TODO: support color
+
+    if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
+    {
+      DALI_CAPTURE_STATE( "Fail to unmap tbm_surface\n" );
+    }
+  }
+  else
+  {
+     DALI_ASSERT_ALWAYS(0 && "tbm_surface_map failed");
+  }
+
+  DALI_CAPTURE_STATE("Clear mTbmSurface[%p]", mTbmSurface);
+}
+
+bool Capture::IsSurfaceCreated()
+{
+  return mTbmSurface != 0;
+}
+
+void Capture::CreateNativeImageSource()
+{
+  Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+
+  DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
+
+  DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
+
+  DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
+
+  // create the NativeImageSource object with our surface
+  mNativeImageSourcePtr = NativeImageSource::New(Dali::Any(mTbmSurface));
+
+  DALI_CAPTURE_STATE("Create NativeImageSource[0x%X]", mNativeImageSourcePtr.Get());
+}
+
+void Capture::DeleteNativeImageSource()
+{
+  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
+
+  DALI_CAPTURE_STATE("Delete NativeImageSource[0x%X]", mNativeImageSourcePtr.Get());
+
+  mNativeImageSourcePtr.Reset();
+}
+
+bool Capture::IsNativeImageSourceCreated()
+{
+  return mNativeImageSourcePtr;
+}
+
+void Capture::CreateFrameBuffer()
+{
+  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
+
+  DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
+
+  mNativeTexture = Texture::New( *mNativeImageSourcePtr );
+
+  // Create a FrameBuffer object with no default attachments.
+  mFrameBuffer = FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), FrameBuffer::Attachment::NONE );
+  // Add a color attachment to the FrameBuffer object.
+  mFrameBuffer.AttachColorTexture( mNativeTexture );
+
+  DALI_CAPTURE_STATE("Create FrameBuffer");
+}
+
+void Capture::DeleteFrameBuffer()
+{
+  DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
+
+  DALI_CAPTURE_STATE("Delete FrameBuffer");
+
+  mFrameBuffer.Reset();
+  mNativeTexture.Reset();
+}
+
+bool Capture::IsFrameBufferCreated()
+{
+  return mFrameBuffer;
+}
+
+void Capture::SetupRenderTask(Actor source, const Vector4& clearColor)
+{
+  DALI_ASSERT_ALWAYS(source && "Source is empty.");
+
+  mSource = source;
+
+  // Check the original parent about source.
+  mParent = mSource.GetParent();
+
+  Stage stage = Stage::GetCurrent();
+  Size stageSize = stage.GetSize();
+
+  // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
+  stage.Add(mSource);
+
+  DALI_ASSERT_ALWAYS(!mCameraActor && "CameraActor is already created.");
+
+  mCameraActor = CameraActor::New( stageSize );
+  mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
+  mCameraActor.SetAnchorPoint(AnchorPoint::CENTER);
+
+  if(mProjectionMode == Camera::ORTHOGRAPHIC_PROJECTION)
+  {
+       mCameraActor.SetOrthographicProjection(stageSize);
+  }
+  stage.Add(mCameraActor);
+
+  DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
+
+  DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
+
+  RenderTaskList taskList = stage.GetRenderTaskList();
+  mRenderTask = taskList.CreateTask();
+  mRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+  mRenderTask.SetSourceActor(source);
+  mRenderTask.SetCameraActor(mCameraActor);
+  mRenderTask.SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
+  mRenderTask.SetFrameBuffer(mFrameBuffer);
+  mRenderTask.SetClearColor( clearColor );
+  mRenderTask.SetClearEnabled( true );
+  mRenderTask.SetProperty( RenderTask::Property::REQUIRES_SYNC, true );
+  mRenderTask.FinishedSignal().Connect(this, &Capture::OnRenderFinished);
+  mRenderTask.GetCameraActor().SetInvertYAxis( true );
+
+  mTimer = Timer::New(TIME_OUT_DURATION);
+  mTimer.TickSignal().Connect(this, &Capture::OnTimeOut);
+  mTimer.Start();
+
+  DALI_CAPTURE_STATE("Setup Camera and RenderTask.");
+}
+
+void Capture::UnsetRenderTask()
+{
+  DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
+
+  DALI_CAPTURE_STATE("Unset Camera and RenderTask");
+
+  if (mParent)
+  {
+    // Restore the parent of source.
+    mParent.Add(mSource);
+    mParent.Reset();
+  }
+  else
+  {
+    mSource.Unparent();
+  }
+
+  mSource.Reset();
+
+  mTimer.Reset();
+
+  mCameraActor.Unparent();
+  mCameraActor.Reset();
+
+  DALI_ASSERT_ALWAYS(mRenderTask && "RenderTask is NULL.");
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  RenderTask firstTask = taskList.GetTask( 0u );
+
+  // Stop rendering via frame-buffers as empty handle is used to clear target
+  firstTask.SetFrameBuffer(FrameBuffer());
+
+  taskList.RemoveTask(mRenderTask);
+  mRenderTask.Reset();
+}
+
+bool Capture::IsRenderTaskSetup()
+{
+  return mCameraActor && mRenderTask;
+}
+
+void Capture::SetupResources(const Vector2& size, const Vector4& clearColor, Actor source)
+{
+  CreateSurface(size);
+  ClearSurface(size);
+
+  CreateNativeImageSource();
+
+  CreateFrameBuffer();
+
+  SetupRenderTask(source, clearColor);
+
+  DALI_CAPTURE_STATE("Setup Resources");
+}
+
+void Capture::UnsetResources()
+{
+  if (IsRenderTaskSetup())
+  {
+    UnsetRenderTask();
+  }
+
+  if (IsFrameBufferCreated())
+  {
+    DeleteFrameBuffer();
+  }
+
+  if (IsNativeImageSourceCreated())
+  {
+    DeleteNativeImageSource();
+  }
+
+  if (IsSurfaceCreated())
+  {
+    DeleteSurface();
+  }
+
+  DALI_CAPTURE_STATE("Unset Resources");
+}
+
+void Capture::OnRenderFinished(RenderTask& task)
+{
+  DALI_CAPTURE_STATE("Render finished");
+
+  mFinishState = Dali::Extension::Capture::SUCCESSED;
+
+  mTimer.Stop();
+
+  if (!Save())
+  {
+    mFinishState = Dali::Extension::Capture::FAILED;
+    DALI_LOG_ERROR("Fail to Capture mTbmSurface[%p] Path[%s]", mTbmSurface, mPath.c_str());
+  }
+
+  Dali::Extension::Capture handle(this);
+  mFinishedSignal.Emit(handle);
+
+  UnsetResources();
+
+  // Decrease the reference count forcely. It is increased at Start().
+  Unreference();
+}
+
+bool Capture::OnTimeOut()
+{
+  DALI_CAPTURE_STATE("Timeout");
+
+  mFinishState = Dali::Extension::Capture::FAILED;
+
+  Dali::Extension::Capture handle(this);
+  mFinishedSignal.Emit(handle);
+
+  UnsetResources();
+
+  // Decrease the reference count forcely. It is increased at Start().
+  Unreference();
+
+  return false;
+}
+
+bool Capture::Save()
+{
+  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
+
+  return mNativeImageSourcePtr->EncodeToFile(mPath);
+}
+
+}  // End of namespace Internal
+
+}  // End of namespace Extension
+
+}  // End of namespace Dali
diff --git a/dali-extension/internal/capture/capture-impl.h b/dali-extension/internal/capture/capture-impl.h
new file mode 100755 (executable)
index 0000000..5e8b073
--- /dev/null
@@ -0,0 +1,260 @@
+#ifndef __DALI_EXTENSION_INTERNAL_CAPTURE_H__
+#define __DALI_EXTENSION_INTERNAL_CAPTURE_H__
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <tbm_surface.h>
+
+// INTERNAL INCLUDES
+#include <dali/dali.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali-extension/devel-api/capture/capture.h>
+
+namespace Dali
+{
+
+namespace Extension
+{
+
+namespace Internal
+{
+
+class Capture;
+typedef IntrusivePtr<Capture> CapturePtr;
+
+class Capture : public BaseObject, public ConnectionTracker
+{
+public:
+  typedef unsigned char Pixel;
+  typedef Pixel* PixelPtr;
+
+public:
+  /**
+   * @brief Constructor.
+   */
+  Capture();
+  Capture(Dali::Camera::ProjectionMode mode);
+
+  /**
+   * @copydoc Dali::Extension::New
+   */
+  static CapturePtr New();
+
+  /**
+   * @copydoc Dali::Extension::New
+   */
+  static CapturePtr New(Dali::Camera::ProjectionMode mode);
+
+  /**
+   * @copydoc Dali::Extension::Start
+   */
+  void Start(Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor);
+
+  /**
+   * @copydoc Dali::Extension::GetFinishState
+   */
+  Dali::Extension::Capture::FinishState GetFinishState();
+
+  /**
+   * @copydoc Dali::Extension::FinishedSignal
+   */
+  Dali::Extension::Capture::CaptureSignalType& FinishedSignal();
+
+protected:
+
+  /**
+   * @brief Second-phase constructor. Must be called immediately after creating a new Capture;
+   */
+  void Initialize(void);
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Capture();
+
+private:
+  /**
+   * @brief Create surface.
+   *
+   * @param[in] size of surface.
+   */
+  void CreateSurface(const Vector2& size);
+
+  /**
+   * @brief Delete surface.
+   */
+  void DeleteSurface();
+
+  /**
+   * @brief Clear surface with color.
+   *
+   * @param[in] size of clear aread.
+   */
+  void ClearSurface(const Vector2& size);
+
+  /**
+   * @brief Query whether surface is created or not.
+   *
+   * @return True is surface is created.
+   */
+  bool IsSurfaceCreated();
+
+  /**
+   * @brief Create native image source.
+   */
+  void CreateNativeImageSource();
+
+  /**
+   * @brief Delete native image source.
+   */
+  void DeleteNativeImageSource();
+
+  /**
+   * @brief Query whether native image source is created or not.
+   *
+   * @return True is native image source is created.
+   */
+  bool IsNativeImageSourceCreated();
+
+  /**
+   * @brief Create frame buffer.
+   */
+  void CreateFrameBuffer();
+
+  /**
+   * @brief Delete frame buffer.
+   */
+  void DeleteFrameBuffer();
+
+  /**
+   * @brief Query whether frame buffer is created or not.
+   *
+   * @return True is frame buffer is created.
+   */
+  bool IsFrameBufferCreated();
+
+  /**
+   * @brief Setup render task.
+   *
+   * @param[in] source is captured.
+   * @param[in] clearColor background color
+   */
+  void SetupRenderTask(Actor source, const Vector4& clearColor);
+
+  /**
+   * @brief Unset render task.
+   */
+  void UnsetRenderTask();
+
+  /**
+   * @brief Query whether render task is setup or not.
+   *
+   * @return True is render task is setup.
+   */
+  bool IsRenderTaskSetup();
+
+  /**
+   * @brief Setup resources for capture.
+   *
+   * @param[in] size is surface size.
+   * @param[in] clearColor is clear color of surface.
+   * @param[in] source is captured.
+   */
+  void SetupResources(const Vector2& size, const Vector4& clearColor, Actor source);
+
+  /**
+   * @brief Unset resources for capture.
+   */
+  void UnsetResources();
+
+  /**
+   * @brief Callback when render is finished.
+   *
+   * @param[in] task is used for capture.
+   */
+  void OnRenderFinished(RenderTask& task);
+
+  /**
+   * @brief Callback when timer is finished.
+   *
+   * @return True is timer start again.
+   */
+  bool OnTimeOut();
+
+  /**
+   * @brief Save framebuffer.
+   *
+   * @return True is success to save, false is fail.
+   */
+  bool Save();
+
+private:
+
+  // Undefined
+  Capture(const Capture&);
+
+  // Undefined
+  Capture& operator=(const Capture& rhs);
+
+private:
+  Texture                                     mNativeTexture;
+  FrameBuffer                                 mFrameBuffer;
+  RenderTask                                  mRenderTask;
+  Actor                                       mParent;
+  Actor                                       mSource;
+  CameraActor                                 mCameraActor;
+  Camera::ProjectionMode                      mProjectionMode;
+  Timer                                       mTimer;           ///< For timeout.
+  Dali::Extension::Capture::CaptureSignalType mFinishedSignal;
+  std::string                                 mPath;
+  NativeImageSourcePtr                        mNativeImageSourcePtr;  ///< pointer to surface image
+  tbm_surface_h                               mTbmSurface;
+  Dali::Extension::Capture::FinishState       mFinishState;
+};
+
+}  // End of namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Capture& GetImpl(Extension::Capture& captureWorker)
+{
+  DALI_ASSERT_ALWAYS(captureWorker && "Capture handle is empty");
+
+  BaseObject& handle = captureWorker.GetBaseObject();
+
+  return static_cast<Internal::Capture&>(handle);
+}
+
+inline const Internal::Capture& GetImpl(const Extension::Capture& captureWorker)
+{
+  DALI_ASSERT_ALWAYS(captureWorker && "Capture handle is empty");
+
+  const BaseObject& handle = captureWorker.GetBaseObject();
+
+  return static_cast<const Internal::Capture&>(handle);
+}
+
+}  // End of namespace Extension
+
+}  // End of namespace Dali
+
+#endif // __DALI_EXTENSION_INTERNAL_CAPTURE_H__
diff --git a/dali-extension/internal/capture/file.list b/dali-extension/internal/capture/file.list
new file mode 100644 (file)
index 0000000..580ea95
--- /dev/null
@@ -0,0 +1,5 @@
+capture_internal_header_files = \
+   $(extension_src_dir)/internal/capture/capture-impl.h
+
+capture_internal_src_files = \
+   $(extension_src_dir)/internal/capture/capture-impl.cpp
index f707efc..99e03bb 100755 (executable)
@@ -23,6 +23,10 @@ BuildRequires:  pkgconfig(dali-adaptor)
 BuildRequires:  pkgconfig(dali-toolkit)
 BuildRequires:  pkgconfig(dlog)
 
+# For capture
+BuildRequires:  pkgconfig(libtbm)
+BuildRequires:  pkgconfig(libpng)
+
 # For evas-plugin
 BuildRequires:  pkgconfig(dali-adaptor-integration)
 BuildRequires:  pkgconfig(elementary)