Return captured results with PixelBuffer
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / common / capture-impl.cpp
index 253a3fd..1445ebb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
 #include <dali/internal/system/common/capture-impl.h>
 
 // EXTERNAL INCLUDES
-#include <fstream>
-#include <string.h>
-#include <dali/public-api/common/stage.h>
+#include <dali/integration-api/debug.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/render-tasks/render-task-list.h>
-#include <dali/integration-api/debug.h>
+#include <string.h>
+#include <fstream>
 
 // INTERNAL INCLUDES
-#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/devel-api/adaptor-framework/bitmap-saver.h>
 #include <dali/devel-api/adaptor-framework/native-image-source-devel.h>
-
-namespace
-{
-unsigned int TIME_OUT_DURATION = 1000;
-}
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
 
 namespace Dali
 {
-
 namespace Internal
 {
-
 namespace Adaptor
 {
+namespace
+{
+constexpr int32_t  GL_VERSION_NATIVE_IMAGE_SOURCE_AVAILABLE = 30;
+constexpr uint32_t TIME_OUT_DURATION                        = 1000;
+} // namespace
 
 Capture::Capture()
-: mQuality( DEFAULT_QUALITY ),
+: mQuality(DEFAULT_QUALITY),
   mTimer(),
   mPath(),
-  mNativeImageSourcePtr( NULL ),
-  mFileSave( false )
+  mNativeImageSourcePtr(NULL),
+  mFileSave(false)
 {
 }
 
-Capture::Capture( Dali::CameraActor cameraActor )
-: mQuality( DEFAULT_QUALITY ),
-  mCameraActor( cameraActor ),
+Capture::Capture(Dali::CameraActor cameraActor)
+: mQuality(DEFAULT_QUALITY),
+  mCameraActor(cameraActor),
   mTimer(),
   mPath(),
-  mNativeImageSourcePtr( NULL ),
-  mFileSave( false )
+  mNativeImageSourcePtr(NULL),
+  mFileSave(false)
 {
 }
 
 Capture::~Capture()
 {
   DeleteNativeImageSource();
+  mTexture.Reset();
 }
 
 CapturePtr Capture::New()
@@ -75,94 +77,105 @@ CapturePtr Capture::New()
   return pWorker;
 }
 
-CapturePtr Capture::New( Dali::CameraActor cameraActor )
+CapturePtr Capture::New(Dali::CameraActor cameraActor)
 {
-  CapturePtr pWorker = new Capture( cameraActor );
+  CapturePtr pWorker = new Capture(cameraActor);
 
   return pWorker;
 }
 
-void Capture::Start( Dali::Actor source, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor, const uint32_t quality )
+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)
 {
   mQuality = quality;
-  Start( source, size, path, clearColor );
+  Start(source, position, size, path, clearColor);
 }
 
-void Capture::Start( Dali::Actor source, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor )
+void Capture::Start(Dali::Actor source, const Dali::Vector2& position, const Dali::Vector2& size, const std::string& path, const Dali::Vector4& clearColor)
 {
-  DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
+  if(!source)
+  {
+    return;
+  }
 
   // Increase the reference count focely to avoid application mistake.
   Reference();
 
   mPath = path;
-  if( mPath.size() > 0 )
+  if(!mPath.empty())
   {
     mFileSave = true;
   }
 
-  DALI_ASSERT_ALWAYS(source && "Source is NULL.");
-
   UnsetResources();
-  SetupResources( size, clearColor, source );
+  SetupResources(position, size, clearColor, source);
 }
 
-Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
+void Capture::SetImageQuality(uint32_t quality)
 {
-  DALI_ASSERT_ALWAYS( mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL.");
+  mQuality = quality;
+}
 
+Dali::NativeImageSourcePtr Capture::GetNativeImageSource() const
+{
   return mNativeImageSourcePtr;
 }
 
-Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
+Dali::Devel::PixelBuffer Capture::GetCapturedBuffer()
 {
-  return mFinishedSignal;
+  if(!mPixelBuffer || (mPixelBuffer && !mPixelBuffer.GetBuffer()))
+  {
+    std::vector<uint8_t> buffer;
+    uint32_t             width, height;
+    Dali::Pixel::Format  pixelFormat;
+    if(!mNativeImageSourcePtr->GetPixels(buffer, width, height, pixelFormat))
+    {
+      return Dali::Devel::PixelBuffer();
+    }
+    mPixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
+    memcpy(mPixelBuffer.GetBuffer(), &buffer[0], width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat));
+  }
+  return mPixelBuffer;
 }
 
-void Capture::CreateNativeImageSource( const Vector2& size )
+Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
 {
-  Dali::Adaptor& adaptor = Dali::Adaptor::Get();
-
-  DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
-
-  DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
-
-  // create the NativeImageSource object with our surface
-  mNativeImageSourcePtr = Dali::NativeImageSource::New( size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT );
+  return mFinishedSignal;
 }
 
-void Capture::DeleteNativeImageSource()
+void Capture::CreateTexture(const Vector2& size)
 {
-  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
-
-  mNativeImageSourcePtr.Reset();
+  if(!mNativeImageSourcePtr)
+  {
+    mNativeImageSourcePtr = Dali::NativeImageSource::New(size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT);
+    mTexture              = Dali::Texture::New(*mNativeImageSourcePtr);
+  }
 }
 
-bool Capture::IsNativeImageSourceCreated()
+void Capture::DeleteNativeImageSource()
 {
-  return mNativeImageSourcePtr;
+  if(mNativeImageSourcePtr)
+  {
+    mNativeImageSourcePtr.Reset();
+  }
 }
 
 void Capture::CreateFrameBuffer()
 {
-  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
-
-  DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
-
-  mNativeTexture = Dali::Texture::New( *mNativeImageSourcePtr );
-
-  // Create a FrameBuffer object with depth attachments.
-  mFrameBuffer = Dali::FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH );
-  // Add a color attachment to the FrameBuffer object.
-  mFrameBuffer.AttachColorTexture( mNativeTexture );
+  if(!mFrameBuffer)
+  {
+    // Create a FrameBuffer object with depth attachments.
+    mFrameBuffer = Dali::FrameBuffer::New(mTexture.GetWidth(), mTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
+    // Add a color attachment to the FrameBuffer object.
+    mFrameBuffer.AttachColorTexture(mTexture);
+  }
 }
 
 void Capture::DeleteFrameBuffer()
 {
-  DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
-
-  mFrameBuffer.Reset();
-  mNativeTexture.Reset();
+  if(mFrameBuffer)
+  {
+    mFrameBuffer.Reset();
+  }
 }
 
 bool Capture::IsFrameBufferCreated()
@@ -170,79 +183,79 @@ bool Capture::IsFrameBufferCreated()
   return mFrameBuffer;
 }
 
-void Capture::SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearColor )
+void Capture::SetupRenderTask(const Dali::Vector2& position, const Dali::Vector2& size, Dali::Actor source, const Dali::Vector4& clearColor)
 {
-  DALI_ASSERT_ALWAYS(source && "Source is empty.");
-
-  mSource = source;
-
-  // Check the original parent about source.
-  mParent = mSource.GetParent();
-
-  Dali::Stage stage = Dali::Stage::GetCurrent();
-  Dali::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 );
+  if(!source)
+  {
+    DALI_LOG_ERROR("Source is empty\n");
+    return;
+  }
 
-  if( !mCameraActor )
+  Dali::Window window = DevelWindow::Get(source);
+  if(!window)
   {
-    mCameraActor = Dali::CameraActor::New( stageSize );
-    mCameraActor.SetProperty( Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
-    mCameraActor.SetProperty( Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
+    DALI_LOG_ERROR("The source is not added on the scene\n");
+    return;
   }
 
-  stage.Add( mCameraActor );
+  mSource = source;
 
-  DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
+  if(!mCameraActor)
+  {
+    mCameraActor = Dali::CameraActor::New(size);
+    // Because input position and size are for 2 dimentional area,
+    // default z-directional position of the camera is required to be used for the new camera position.
+    float   cameraDefaultZPosition = mCameraActor.GetProperty<float>(Dali::Actor::Property::POSITION_Z);
+    Vector2 positionTransition     = position + size / 2;
+    mCameraActor.SetProperty(Dali::Actor::Property::POSITION, Vector3(positionTransition.x, positionTransition.y, cameraDefaultZPosition));
+    mCameraActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+    mCameraActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  }
 
-  DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
+  window.Add(mCameraActor);
 
-  Dali::RenderTaskList taskList = stage.GetRenderTaskList();
-  mRenderTask = taskList.CreateTask();
-  mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
-  mRenderTask.SetSourceActor( source );
-  mRenderTask.SetCameraActor( mCameraActor );
-  mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
-  mRenderTask.SetFrameBuffer( mFrameBuffer );
-  mRenderTask.SetClearColor( clearColor );
-  mRenderTask.SetClearEnabled( true );
-  mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
-  mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
-  mRenderTask.GetCameraActor().SetInvertYAxis( true );
+  if(!mFrameBuffer)
+  {
+    DALI_LOG_ERROR("Frame buffer is not created.\n");
+    return;
+  }
 
-  mTimer = Dali::Timer::New( TIME_OUT_DURATION );
-  mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
+  Dali::RenderTaskList taskList = window.GetRenderTaskList();
+  mRenderTask                   = taskList.CreateTask();
+  mRenderTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
+  mRenderTask.SetSourceActor(source);
+  mRenderTask.SetCameraActor(mCameraActor);
+  mRenderTask.SetScreenToFrameBufferFunction(Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
+  mRenderTask.SetFrameBuffer(mFrameBuffer);
+  mRenderTask.SetClearColor(clearColor);
+  mRenderTask.SetClearEnabled(true);
+  mRenderTask.SetProperty(Dali::RenderTask::Property::REQUIRES_SYNC, true);
+  mRenderTask.FinishedSignal().Connect(this, &Capture::OnRenderFinished);
+  mRenderTask.GetCameraActor().SetInvertYAxis(true);
+
+  mTimer = Dali::Timer::New(TIME_OUT_DURATION);
+  mTimer.TickSignal().Connect(this, &Capture::OnTimeOut);
   mTimer.Start();
 }
 
 void Capture::UnsetRenderTask()
 {
-  DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
+  mTimer.Reset();
 
-  if( mParent )
+  if(mCameraActor)
   {
-    // Restore the parent of source.
-    mParent.Add( mSource );
-    mParent.Reset();
+    mCameraActor.Unparent();
+    mCameraActor.Reset();
   }
-  else
+
+  if(mRenderTask)
   {
-    mSource.Unparent();
+    Dali::Window         window   = DevelWindow::Get(mSource);
+    Dali::RenderTaskList taskList = window.GetRenderTaskList();
+    taskList.RemoveTask(mRenderTask);
+    mRenderTask.Reset();
   }
-
   mSource.Reset();
-
-  mTimer.Reset();
-
-  mCameraActor.Unparent();
-  mCameraActor.Reset();
-
-  DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
-
-  Dali::RenderTaskList taskList = Dali::Stage::GetCurrent().GetRenderTaskList();
-  taskList.RemoveTask( mRenderTask );
-  mRenderTask.Reset();
 }
 
 bool Capture::IsRenderTaskSetup()
@@ -250,45 +263,45 @@ bool Capture::IsRenderTaskSetup()
   return mCameraActor && mRenderTask;
 }
 
-void Capture::SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source )
+void Capture::SetupResources(const Dali::Vector2& position, const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source)
 {
-  CreateNativeImageSource( size );
+  CreateTexture(size);
 
   CreateFrameBuffer();
 
-  SetupRenderTask( source, clearColor );
+  SetupRenderTask(position, size, source, clearColor);
 }
 
 void Capture::UnsetResources()
 {
-  if( IsRenderTaskSetup() )
+  if(IsRenderTaskSetup())
   {
     UnsetRenderTask();
   }
 
-  if( IsFrameBufferCreated() )
+  if(IsFrameBufferCreated())
   {
     DeleteFrameBuffer();
   }
 }
 
-void Capture::OnRenderFinished( Dali::RenderTask& task )
+void Capture::OnRenderFinished(Dali::RenderTask& task)
 {
   Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
 
   mTimer.Stop();
 
-  if( mFileSave )
+  if(mFileSave)
   {
-    if( !SaveFile() )
+    if(!SaveFile())
     {
+      DALI_LOG_ERROR("Fail to Capture Path[%s]\n", mPath.c_str());
       state = Dali::Capture::FinishState::FAILED;
-      DALI_LOG_ERROR( "Fail to Capture Path[%s]", mPath.c_str() );
     }
   }
 
-  Dali::Capture handle( this );
-  mFinishedSignal.Emit( handle, state );
+  Dali::Capture handle(this);
+  mFinishedSignal.Emit(handle, state);
 
   UnsetResources();
 
@@ -300,8 +313,8 @@ bool Capture::OnTimeOut()
 {
   Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
 
-  Dali::Capture handle( this );
-  mFinishedSignal.Emit( handle, state );
+  Dali::Capture handle(this);
+  mFinishedSignal.Emit(handle, state);
 
   UnsetResources();
 
@@ -313,13 +326,15 @@ bool Capture::OnTimeOut()
 
 bool Capture::SaveFile()
 {
-  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
-
-  return Dali::DevelNativeImageSource::EncodeToFile( *mNativeImageSourcePtr, mPath, mQuality );
+  if(mNativeImageSourcePtr)
+  {
+    return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
+  }
+  return false;
 }
 
-}  // End of namespace Adaptor
+} // End of namespace Adaptor
 
-}  // End of namespace Internal
+} // End of namespace Internal
 
-}  // End of namespace Dali
+} // End of namespace Dali