diff --git a/configure.ac b/configure.ac
index f47b743b5640ccec6248be7ec3a6ae04612dbfb3..66c571ca796666edd0218cb4b53f48dedac55cb2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Jami - configure.ac
 
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ([2.69])
-AC_INIT([Jami Daemon],[12.0.0],[jami@gnu.org],[jami])
+AC_INIT([Jami Daemon],[13.0.0],[jami@gnu.org],[jami])
 
 dnl Clear the implicit flags that default to '-g -O2', otherwise they
 dnl take precedence over the values we set via the
diff --git a/meson.build b/meson.build
index 4c63bacb91d78440757865c862ed6ecbcd335929..de2282be5eb6127957d300bcb5ef06f22852bbf0 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
 project('jami-daemon', ['c', 'cpp'],
-        version: '11.0.2',
+        version: '13.0.0',
         license: 'GPL3+',
         default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'],
         meson_version:'>= 0.56'
diff --git a/src/client/videomanager.cpp b/src/client/videomanager.cpp
index f524b061cf890e50115716b96f280a687eb2ef1c..b486d138710e2dd473bd88184a56885c59f774f0 100644
--- a/src/client/videomanager.cpp
+++ b/src/client/videomanager.cpp
@@ -58,10 +58,7 @@ extern "C" {
 namespace DRing {
 
 MediaFrame::MediaFrame()
-    : frame_ {av_frame_alloc(),
-              [](AVFrame* frame) {
-                  av_frame_free(&frame);
-              }}
+    : frame_ {av_frame_alloc()}
     , packet_(nullptr, [](AVPacket* p) {
         if (p) {
             av_packet_unref(p);
@@ -526,11 +523,11 @@ stopLocalRecorder(const std::string& filepath)
 }
 
 void
-registerSinkTarget(const std::string& sinkId, const SinkTarget& target)
+registerSinkTarget(const std::string& sinkId, SinkTarget target)
 {
 #ifdef ENABLE_VIDEO
     if (auto sink = jami::Manager::instance().getSinkClient(sinkId))
-        sink->registerTarget(target);
+        sink->registerTarget(std::move(target));
     else
         JAMI_WARN("No sink found for id '%s'", sinkId.c_str());
 #endif
@@ -549,17 +546,6 @@ startShmSink(const std::string& sinkId, bool value)
 }
 #endif
 
-void
-registerAVSinkTarget(const std::string& sinkId, const AVSinkTarget& target)
-{
-#ifdef ENABLE_VIDEO
-    if (auto sink = jami::Manager::instance().getSinkClient(sinkId))
-        sink->registerAVTarget(target);
-    else
-        JAMI_WARN("No sink found for id '%s'", sinkId.c_str());
-#endif
-}
-
 std::map<std::string, std::string>
 getRenderer(const std::string& callId)
 {
diff --git a/src/jami/videomanager_interface.h b/src/jami/videomanager_interface.h
index a53cb16903af451100fc582949190db85c0a755d..372dfc031d7a1cc9eb8a7088eb2587bb72534d4b 100644
--- a/src/jami/videomanager_interface.h
+++ b/src/jami/videomanager_interface.h
@@ -56,6 +56,12 @@ namespace DRing {
 [[deprecated("Replaced by registerSignalHandlers")]] DRING_PUBLIC void registerVideoHandlers(
     const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
 
+struct DRING_PUBLIC AVFrame_deleter {
+    void operator()(AVFrame* frame) const { av_frame_free(&frame); }
+};
+
+typedef std::unique_ptr<AVFrame, AVFrame_deleter> FrameBuffer;
+
 class DRING_PUBLIC MediaFrame
 {
 public:
@@ -80,10 +86,10 @@ public:
     // Reset internal buffers (return to an empty MediaFrame)
     virtual void reset() noexcept;
 
-    std::unique_ptr<AVFrame, void (*)(AVFrame*)> getFrame() { return std::move(frame_); }
+    FrameBuffer getFrame() { return std::move(frame_); }
 
 protected:
-    std::unique_ptr<AVFrame, void (*)(AVFrame*)> frame_;
+    FrameBuffer frame_;
     std::unique_ptr<AVPacket, void (*)(AVPacket*)> packet_;
 };
 
@@ -157,21 +163,10 @@ private:
     void setGeometry(int format, int width, int height) noexcept;
 };
 
-struct DRING_PUBLIC AVFrame_deleter {
-    void operator()(AVFrame* frame) const { av_frame_free(&frame); }
-};
-
-typedef std::unique_ptr<AVFrame, AVFrame_deleter> FrameBuffer;
-
 struct DRING_PUBLIC SinkTarget
 {
     std::function<FrameBuffer()> pull;
     std::function<void(FrameBuffer)> push;
-};
-
-struct DRING_PUBLIC AVSinkTarget
-{
-    std::function<void(std::unique_ptr<VideoFrame>)> push;
     int /* AVPixelFormat */ preferredFormat {-1 /* AV_PIX_FMT_NONE */};
 };
 
@@ -199,8 +194,7 @@ DRING_PUBLIC bool mutePlayerAudio(const std::string& id, bool mute);
 DRING_PUBLIC bool playerSeekToTime(const std::string& id, int time);
 int64_t getPlayerPosition(const std::string& id);
 
-DRING_PUBLIC void registerSinkTarget(const std::string& sinkId, const SinkTarget& target);
-DRING_PUBLIC void registerAVSinkTarget(const std::string& sinkId, const AVSinkTarget& target);
+DRING_PUBLIC void registerSinkTarget(const std::string& sinkId, SinkTarget target);
 #if HAVE_SHM
 DRING_PUBLIC void startShmSink(const std::string& sinkId, bool value);
 #endif
diff --git a/src/media/video/sinkclient.cpp b/src/media/video/sinkclient.cpp
index 0195b4ed5eb1dc230bde0c757e3e8b81584fb3a9..21fa707d885a1aa71629f82c9bd055c6fb054e93 100644
--- a/src/media/video/sinkclient.cpp
+++ b/src/media/video/sinkclient.cpp
@@ -354,23 +354,23 @@ SinkClient::update(Observable<std::shared_ptr<MediaFrame>>* /*obs*/,
 #endif
 
     std::unique_lock<std::mutex> lock(mtx_);
-    if (avTarget_.push) {
-        auto outFrame = std::make_unique<VideoFrame>();
-        outFrame->copyFrom(*std::static_pointer_cast<VideoFrame>(frame_p));
+    if (target_.push and not target_.pull) {
+        VideoFrame outFrame;
+        outFrame.copyFrom(*std::static_pointer_cast<VideoFrame>(frame_p));
         if (crop_.w || crop_.h) {
-            outFrame->pointer()->crop_top = crop_.y;
-            outFrame->pointer()->crop_bottom = (size_t) outFrame->height() - crop_.y - crop_.h;
-            outFrame->pointer()->crop_left = crop_.x;
-            outFrame->pointer()->crop_right = (size_t) outFrame->width() - crop_.x - crop_.w;
-            av_frame_apply_cropping(outFrame->pointer(), AV_FRAME_CROP_UNALIGNED);
+            outFrame.pointer()->crop_top = crop_.y;
+            outFrame.pointer()->crop_bottom = (size_t) outFrame.height() - crop_.y - crop_.h;
+            outFrame.pointer()->crop_left = crop_.x;
+            outFrame.pointer()->crop_right = (size_t) outFrame.width() - crop_.x - crop_.w;
+            av_frame_apply_cropping(outFrame.pointer(), AV_FRAME_CROP_UNALIGNED);
         }
-        if (outFrame->height() != height_ || outFrame->width() != width_) {
+        if (outFrame.height() != height_ || outFrame.width() != width_) {
             setFrameSize(0, 0);
-            setFrameSize(outFrame->width(), outFrame->height());
+            setFrameSize(outFrame.width(), outFrame.height());
             return;
         }
         notify(std::static_pointer_cast<MediaFrame>(frame_p));
-        avTarget_.push(std::move(outFrame));
+        target_.push(outFrame.getFrame());
         return;
     }
 
diff --git a/src/media/video/sinkclient.h b/src/media/video/sinkclient.h
index f97b7fda9c3ea229d3b37feb7208405cc763fbeb..4eee5523a62f8787e47a31a1a9bcf867f7c840ef 100644
--- a/src/media/video/sinkclient.h
+++ b/src/media/video/sinkclient.h
@@ -63,7 +63,7 @@ public:
 
     AVPixelFormat getPreferredFormat() const noexcept
     {
-        return (AVPixelFormat) avTarget_.preferredFormat;
+        return (AVPixelFormat) target_.preferredFormat;
     }
 
     // as VideoFramePassiveReader
@@ -76,12 +76,11 @@ public:
     void setFrameSize(int width, int height);
     void setCrop(int x, int y, int w, int h);
 
-    void registerTarget(const DRing::SinkTarget& target) noexcept
+    void registerTarget(DRing::SinkTarget target) noexcept
     {
         std::lock_guard<std::mutex> lock(mtx_);
-        target_ = target;
+        target_ = std::move(target);
     }
-    void registerAVTarget(const DRing::AVSinkTarget& target) noexcept { avTarget_ = target; }
 
 #if HAVE_SHM
     void enableShm(bool value) { doShmTransfer_.store(value); }
@@ -103,7 +102,6 @@ private:
     bool started_ {false}; // used to arbitrate client's stop signal.
     int rotation_ {0};
     DRing::SinkTarget target_;
-    DRing::AVSinkTarget avTarget_;
     std::unique_ptr<VideoScaler> scaler_;
     std::unique_ptr<MediaFilter> filter_;
     std::mutex mtx_;