diff --git a/src/client/videomanager.cpp b/src/client/videomanager.cpp
index d07bd917fba801435150cd0c8192b36be36c5206..009e8130d51e3bfc1e23b545f613e24ce01a3010 100644
--- a/src/client/videomanager.cpp
+++ b/src/client/videomanager.cpp
@@ -138,28 +138,13 @@ hasCameraStarted()
     return videoManager.started;
 }
 
-template <class T>
-static void
-registerSinkTarget_(const std::string& sinkId, std::vector<unsigned char>& frameBuffer, T&& cb)
-{
-    if (auto sink = ring::Manager::instance().getSinkClient(sinkId))
-        sink->registerTarget(std::forward<T>(cb), frameBuffer);
-    else
-        RING_WARN("No sink found for id '%s'", sinkId.c_str());
-}
-
-void
-registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer,
-                   const std::function<void(int, int)>& cb)
-{
-    registerSinkTarget_(sinkId, frameBuffer, cb);
-}
-
 void
-registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer,
-                   std::function<void(int, int)>&& cb)
+registerSinkTarget(const std::string& sinkId, const SinkTarget& target)
 {
-    registerSinkTarget_(sinkId, frameBuffer, cb);
+   if (auto sink = ring::Manager::instance().getSinkClient(sinkId))
+       sink->registerTarget(target);
+   else
+       RING_WARN("No sink found for id '%s'", sinkId.c_str());
 }
 
 #ifdef __ANDROID__
diff --git a/src/dring/videomanager_interface.h b/src/dring/videomanager_interface.h
index 1827f33b848f909ce04c0bdb4c8b0cff414558cf..13eef20cfd5e58b2025eab47cd2e34d91a7cd68a 100644
--- a/src/dring/videomanager_interface.h
+++ b/src/dring/videomanager_interface.h
@@ -1,6 +1,8 @@
 /*
  *  Copyright (C) 2012-2015 Savoir-faire Linux Inc.
  *
+ *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 3 of the License, or
@@ -24,11 +26,29 @@
 #include <map>
 #include <string>
 #include <functional>
+#include <cstdint>
+#include <cstdlib>
 
 #include "dring.h"
 
 namespace DRing {
 
+/* FrameBuffer is a generic video frame container */
+struct FrameBuffer {
+    uint8_t* ptr {nullptr};     // data as a plain raw pointer
+    std::size_t ptrSize {0};      // size in byte of ptr array
+    int format {0};             // as listed by AVPixelFormat (avutils/pixfmt.h)
+    int width {0};              // frame width
+    int height {0};             // frame height
+    std::vector<uint8_t> storage;
+};
+
+struct SinkTarget {
+    using FrameBufferPtr = std::unique_ptr<FrameBuffer>;
+    std::function<FrameBufferPtr(std::size_t bytes)> pull;
+    std::function<void(FrameBufferPtr)> push;
+};
+
 using VideoCapabilities = std::map<std::string, std::map<std::string, std::vector<std::string>>>;
 
 void registerVideoHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
@@ -48,8 +68,8 @@ void stopCamera();
 bool hasCameraStarted();
 bool switchInput(const std::string& resource);
 bool switchToCamera();
-void registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer, const std::function<void(int, int)>& cb);
-void registerSinkTarget(const std::string& sinkId, std::vector<unsigned char>& frameBuffer, std::function<void(int, int)>&& cb);
+void registerSinkTarget(const std::string& sinkId, const SinkTarget& target);
+
 #ifdef __ANDROID__
 void addVideoDevice(const std::string &node);
 void removeVideoDevice(const std::string &node);
diff --git a/src/media/media_buffer.cpp b/src/media/media_buffer.cpp
index 589ed96e4c5cebc530f3db1f601b660fe6f1156f..ac8ded93017ccd74a0cb0ae98fd94b549e7007ce 100644
--- a/src/media/media_buffer.cpp
+++ b/src/media/media_buffer.cpp
@@ -20,6 +20,7 @@
 
 #include "libav_deps.h" // MUST BE INCLUDED FIRST
 #include "media_buffer.h"
+#include "dring/videomanager_interface.h"
 
 #include <new>
 #include <cstdlib>
@@ -107,7 +108,7 @@ VideoFrame::reserve(int format, int width, int height)
 }
 
 void
-VideoFrame::setFromMemory(void* ptr, int format, int width, int height) noexcept
+VideoFrame::setFromMemory(uint8_t* ptr, int format, int width, int height)
 {
     reset();
     setGeometry(format, width, height);
diff --git a/src/media/media_buffer.h b/src/media/media_buffer.h
index 359cd2583ff0c68cad18a617e5b0dbfa0b9bc599..106597cc00aadccf87c5d1e8942f1daf22bb9057 100644
--- a/src/media/media_buffer.h
+++ b/src/media/media_buffer.h
@@ -26,6 +26,10 @@
 
 class AVFrame;
 
+namespace DRing {
+class FrameBuffer; //  from dring/videomanager_interface.h
+}
+
 namespace ring {
 
 class MediaFrame {
@@ -74,7 +78,7 @@ class VideoFrame: public MediaFrame {
 
         // Set internal pixel buffers on given memory buffer
         // This buffer must follow given specifications.
-        void setFromMemory(void* ptr, int format, int width, int height) noexcept;
+        void setFromMemory(uint8_t* data, int format, int width, int height);
 
         void noise();
 
diff --git a/src/media/video/shm_header.h b/src/media/video/shm_header.h
index 594913d1fe2da96db3c671e697f40d20ef517196..9811a17a17f082af4c611612cd1eda582ecea02f 100644
--- a/src/media/video/shm_header.h
+++ b/src/media/video/shm_header.h
@@ -21,6 +21,7 @@
 #ifndef SHM_HEADER_H_
 #define SHM_HEADER_H_
 
+#include <cstdint>
 #include <semaphore.h>
 
 // Implementation note: double-buffering
@@ -37,7 +38,7 @@ struct SHMHeader {
     unsigned mapSize;           // size to map if you need to see all data
     unsigned readOffset;        // offset of readable frame in data
     unsigned writeOffset;       // offset of writable frame in data
-    char data[];                // the whole shared memory
+    uint8_t data[];             // the whole shared memory
 };
 
 #endif
diff --git a/src/media/video/sinkclient.cpp b/src/media/video/sinkclient.cpp
index 84d13c78a7f4f4d686ac5cfa0ec51573ecd08f63..0b9e5842905c7e5696665c94af62866d9147360f 100644
--- a/src/media/video/sinkclient.cpp
+++ b/src/media/video/sinkclient.cpp
@@ -3,6 +3,7 @@
  *
  *  Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
  *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -35,6 +36,7 @@
 #include "noncopyable.h"
 #include "client/ring_signal.h"
 #include "dring/videomanager_interface.h"
+#include "libav_utils.h"
 
 #ifndef _WIN32
 #include <sys/mman.h>
@@ -323,7 +325,7 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/,
     shm_->renderFrame(*f.get());
 #endif
 
-    if (targetData_) {
+    if (target_.pull) {
         VideoFrame dst;
         VideoScaler scaler;
         const int width = f->width();
@@ -336,12 +338,14 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/,
         const auto bytes = videoFrameSize(format, width, height);
 
         if (bytes > 0) {
-          targetData_->resize(bytes);
-          auto data = targetData_->data();
-
-          dst.setFromMemory(data, format, width, height);
-          scaler.scale(*f, dst);
-          target_(width, height);
+            if (auto buffer_ptr = target_.pull(bytes)) {
+                buffer_ptr->format = libav_utils::libav_pixel_format(format);
+                buffer_ptr->width = width;
+                buffer_ptr->height = height;
+                dst.setFromMemory(buffer_ptr->ptr, format, width, height);
+                scaler.scale(*f, dst);
+                target_.push(std::move(buffer_ptr));
+            }
         }
     }
 }
diff --git a/src/media/video/sinkclient.h b/src/media/video/sinkclient.h
index b446422fa9900c6d0cfddc1907df9f8c6abafddb..91168a238c1ef494a30a1fd0bd7c5df3a37a665e 100644
--- a/src/media/video/sinkclient.h
+++ b/src/media/video/sinkclient.h
@@ -2,6 +2,8 @@
  *  Copyright (C) 2012-2015 Savoir-faire Linux Inc.
  *
  *  Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
+ *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -25,6 +27,7 @@
 #endif
 
 #include "video_base.h"
+#include <videomanager_interface.h>
 
 #include <string>
 #include <vector>
@@ -56,18 +59,15 @@ class SinkClient : public VideoFramePassiveReader
 
         void setFrameSize(int width, int height);
 
-        template <class T>
-        void registerTarget(T&& cb, std::vector<unsigned char>& frameBuffer) noexcept {
-            target_ = std::forward<T>(cb);
-            targetData_ = &frameBuffer;
+        void registerTarget(const DRing::SinkTarget& target) noexcept {
+            target_ = target;
         }
 
     private:
         const std::string id_;
         const bool mixer_;
         bool started_ {false}; // used to arbitrate client's stop signal.
-        std::function<void(int, int)> target_;
-        std::vector<unsigned char>* targetData_ {nullptr}; // filled by registerTarget, user owned
+        DRing::SinkTarget target_;
 
 #ifdef DEBUG_FPS
         unsigned frameCount_;