From: Jiyun Yang Date: Mon, 29 Apr 2019 04:10:54 +0000 (+0900) Subject: [Tizen] Import Extension::Capture to support backward compatibility X-Git-Tag: accepted/tizen/unified/20190514.080114^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=da11f011c8e1584817adb5a7cc8bd6aa3c5fa26c;p=platform%2Fcore%2Fuifw%2Fdali-extension.git [Tizen] Import Extension::Capture to support backward compatibility This reverts commit ed8669b6c45dfe0b5164b8a9217d41eb2bfba2ed. --- diff --git a/build/tizen/configure.ac b/build/tizen/configure.ac index 6b45282..5b8091b 100755 --- a/build/tizen/configure.ac +++ b/build/tizen/configure.ac @@ -23,7 +23,7 @@ AC_CONFIG_SUBDIRS(image-loader) AC_CONFIG_SUBDIRS(vector-animation-renderer) AC_CONFIG_SUBDIRS(color-controller) AC_CONFIG_SUBDIRS(web-engine-lwe) -AC_CONFIG_SUBDIRS(evas-plugin) +AC_CONFIG_SUBDIRS(dali-extension) devincludepath=${includedir} AC_SUBST(devincludepath) diff --git a/build/tizen/evas-plugin/Makefile.am b/build/tizen/dali-extension/Makefile.am similarity index 67% rename from build/tizen/evas-plugin/Makefile.am rename to build/tizen/dali-extension/Makefile.am index 5073ba6..89cee34 100755 --- a/build/tizen/evas-plugin/Makefile.am +++ b/build/tizen/dali-extension/Makefile.am @@ -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. @@ -14,13 +14,16 @@ # 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) diff --git a/build/tizen/evas-plugin/configure.ac b/build/tizen/dali-extension/configure.ac similarity index 87% rename from build/tizen/evas-plugin/configure.ac rename to build/tizen/dali-extension/configure.ac index 06b5c12..add46a1 100755 --- a/build/tizen/evas-plugin/configure.ac +++ b/build/tizen/dali-extension/configure.ac @@ -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) diff --git a/dali-extension/dali-extension.h b/dali-extension/dali-extension.h index 762dd96..d3f68ac 100644 --- a/dali-extension/dali-extension.h +++ b/dali-extension/dali-extension.h @@ -18,6 +18,7 @@ * */ +#include #include #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 index 0000000..b490abc --- /dev/null +++ b/dali-extension/devel-api/capture/capture.cpp @@ -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 +#include + +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(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 index 0000000..8a9998e --- /dev/null +++ b/dali-extension/devel-api/capture/capture.h @@ -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 + +// 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 index 0000000..ddd0f93 --- /dev/null +++ b/dali-extension/devel-api/capture/file.list @@ -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 diff --git a/dali-extension/devel-api/evas-plugin/file.list b/dali-extension/devel-api/evas-plugin/file.list index 6f1cafe..7796046 100644 --- a/dali-extension/devel-api/evas-plugin/file.list +++ b/dali-extension/devel-api/evas-plugin/file.list @@ -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 index 0000000..3f0ad18 --- /dev/null +++ b/dali-extension/internal/capture/capture-impl.cpp @@ -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 + +#include +#include + +#include +#include + +// INTERNAL INCLUDES +#include + +#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 index 0000000..5e8b073 --- /dev/null +++ b/dali-extension/internal/capture/capture-impl.h @@ -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 +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include + +namespace Dali +{ + +namespace Extension +{ + +namespace Internal +{ + +class Capture; +typedef IntrusivePtr 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(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(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 index 0000000..580ea95 --- /dev/null +++ b/dali-extension/internal/capture/file.list @@ -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 diff --git a/packaging/dali-extension.spec b/packaging/dali-extension.spec index 074ebd0..670fc38 100755 --- a/packaging/dali-extension.spec +++ b/packaging/dali-extension.spec @@ -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)