[Tizen] Return captured results with PixelBuffer
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / common / capture-impl.cpp
index 2724dd2..9dd3199 100644 (file)
@@ -21,7 +21,6 @@
 // EXTERNAL INCLUDES
 #include <fstream>
 #include <string.h>
-#include <dali/public-api/common/stage.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>
 // INTERNAL INCLUDES
 #include <dali/integration-api/adaptor-framework/adaptor.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/devel-api/adaptor-framework/bitmap-saver.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
 
 namespace Dali
 {
@@ -44,12 +42,19 @@ namespace Internal
 namespace Adaptor
 {
 
+namespace
+{
+constexpr int32_t VERSION_NATIVE_IMAGE_SOURCE = 30;
+constexpr uint32_t TIME_OUT_DURATION = 1000;
+}
+
 Capture::Capture()
 : mQuality( DEFAULT_QUALITY ),
   mTimer(),
   mPath(),
   mNativeImageSourcePtr( NULL ),
-  mFileSave( false )
+  mFileSave( false ),
+  mIsNativeImageSourcePossible(true)
 {
 }
 
@@ -59,13 +64,15 @@ Capture::Capture( Dali::CameraActor cameraActor )
   mTimer(),
   mPath(),
   mNativeImageSourcePtr( NULL ),
-  mFileSave( false )
+  mFileSave( false ),
+  mIsNativeImageSourcePossible(true)
 {
 }
 
 Capture::~Capture()
 {
   DeleteNativeImageSource();
+  mTexture.Reset();
 }
 
 CapturePtr Capture::New()
@@ -82,13 +89,13 @@ CapturePtr Capture::New( Dali::CameraActor 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.");
 
@@ -104,57 +111,95 @@ void Capture::Start( Dali::Actor source, const Dali::Vector2& size, const std::s
   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::Texture Capture::GetTexture()
 {
-  return mFinishedSignal;
+  return mTexture;
 }
 
-void Capture::CreateNativeImageSource( const Vector2& size )
+Dali::Devel::PixelBuffer Capture::GetCapturedBuffer()
 {
-  Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+  if(!mPixelBuffer || !mPixelBuffer.GetBuffer())
+  {
+    uint8_t* bufferPointer;
+    uint32_t             width, height;
+    Dali::Pixel::Format  pixelFormat;
+    if(mIsNativeImageSourcePossible)
+    {
+      std::vector<uint8_t> buffer;
+      if(!mNativeImageSourcePtr->GetPixels(buffer, width, height, pixelFormat))
+      {
+        return Dali::Devel::PixelBuffer();
+      }
+      bufferPointer = &buffer[0];
+    }
+    else
+    {
+      width = mTexture.GetWidth();
+      height = mTexture.GetHeight();
+      pixelFormat = Dali::Pixel::RGBA8888;
+      bufferPointer = mFrameBuffer.GetRenderedBuffer();
+    }
+    mPixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
 
-  DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
+    memcpy(mPixelBuffer.GetBuffer(), bufferPointer, width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat));
+  }
 
-  DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
+  return mPixelBuffer;
+}
 
-  // create the NativeImageSource object with our surface
-  mNativeImageSourcePtr = Dali::NativeImageSource::New( size.width, size.height, Dali::NativeImageSource::COLOR_DEPTH_DEFAULT );
+Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
+{
+  return mFinishedSignal;
 }
 
-void Capture::DeleteNativeImageSource()
+void Capture::CreateTexture(const Vector2& size)
 {
-  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
+  Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+
+  DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
 
-  mNativeImageSourcePtr.Reset();
+  if(mIsNativeImageSourcePossible)
+  {
+    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);
+    mTexture              = Dali::Texture::New(*mNativeImageSourcePtr);
+  }
+  else
+  {
+    mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(size.width), unsigned(size.height));
+  }
 }
 
-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 );
+  mFrameBuffer = Dali::FrameBuffer::New(mTexture.GetWidth(), mTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH);
   // Add a color attachment to the FrameBuffer object.
-  mFrameBuffer.AttachColorTexture( mNativeTexture );
+  mFrameBuffer.AttachColorTexture(mTexture);
 }
 
 void Capture::DeleteFrameBuffer()
@@ -162,7 +207,6 @@ void Capture::DeleteFrameBuffer()
   DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
 
   mFrameBuffer.Reset();
-  mNativeTexture.Reset();
 }
 
 bool Capture::IsFrameBufferCreated()
@@ -170,35 +214,38 @@ 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();
+  Dali::Window window = DevelWindow::Get( source );
+  if( !window )
+  {
+    DALI_LOG_ERROR("The source is not added on the window\n");
+    return;
+  }
 
-  // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
-  stage.Add( mSource );
+  mSource = source;
 
   if( !mCameraActor )
   {
-    mCameraActor = Dali::CameraActor::New( stageSize );
-    mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
-    mCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
+    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 );
   }
 
-  stage.Add( mCameraActor );
+  window.Add( mCameraActor );
 
   DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
 
   DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
 
-  Dali::RenderTaskList taskList = stage.GetRenderTaskList();
+  Dali::RenderTaskList taskList = window.GetRenderTaskList();
   mRenderTask = taskList.CreateTask();
   mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
   mRenderTask.SetSourceActor( source );
@@ -210,6 +257,10 @@ void Capture::SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearCol
   mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
   mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
   mRenderTask.GetCameraActor().SetInvertYAxis( true );
+  if(!mIsNativeImageSourcePossible)
+  {
+    mFrameBuffer.CaptureRenderedResult();
+  }
 
   mTimer = Dali::Timer::New( TIME_OUT_DURATION );
   mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
@@ -220,19 +271,6 @@ void Capture::UnsetRenderTask()
 {
   DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
 
-  if( mParent )
-  {
-    // Restore the parent of source.
-    mParent.Add( mSource );
-    mParent.Reset();
-  }
-  else
-  {
-    mSource.Unparent();
-  }
-
-  mSource.Reset();
-
   mTimer.Reset();
 
   mCameraActor.Unparent();
@@ -240,9 +278,11 @@ void Capture::UnsetRenderTask()
 
   DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
 
-  Dali::RenderTaskList taskList = Dali::Stage::GetCurrent().GetRenderTaskList();
+  Dali::Window window = DevelWindow::Get( mSource );
+  Dali::RenderTaskList taskList = window.GetRenderTaskList();
   taskList.RemoveTask( mRenderTask );
   mRenderTask.Reset();
+  mSource.Reset();
 }
 
 bool Capture::IsRenderTaskSetup()
@@ -250,13 +290,22 @@ 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 );
+  Dali::Internal::Adaptor::Adaptor& adaptor     = Internal::Adaptor::Adaptor::GetImplementation(Internal::Adaptor::Adaptor::Get());
+  GraphicsInterface*                graphics    = &adaptor.GetGraphicsInterface();
+  auto                              eglGraphics = static_cast<EglGraphics*>(graphics);
+
+  if(eglGraphics->GetEglImplementation().GetGlesVersion() < VERSION_NATIVE_IMAGE_SOURCE)
+  {
+    mIsNativeImageSourcePossible = false;
+  }
+
+  CreateTexture(size);
 
   CreateFrameBuffer();
 
-  SetupRenderTask( source, clearColor );
+  SetupRenderTask( position, size, source, clearColor );
 }
 
 void Capture::UnsetResources()
@@ -313,9 +362,16 @@ bool Capture::OnTimeOut()
 
 bool Capture::SaveFile()
 {
-  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
-
-  return Dali::DevelNativeImageSource::EncodeToFile( *mNativeImageSourcePtr, mPath, mQuality );
+  if(mIsNativeImageSourcePossible)
+  {
+    DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
+    return Dali::DevelNativeImageSource::EncodeToFile(*mNativeImageSourcePtr, mPath, mQuality);
+  }
+  else
+  {
+    uint8_t* buffer = mFrameBuffer.GetRenderedBuffer();
+    return Dali::EncodeToFile(buffer, mPath, Dali::Pixel::RGBA8888, mTexture.GetWidth(), mTexture.GetHeight(), mQuality);
+  }
 }
 
 }  // End of namespace Adaptor