diff --git a/AudioFilter/build.sh b/AudioFilter/build.sh
index cb369853323208b85fd958af6054195e0753e483..91ee4ae97742a127ad18aa6dec221ce4b9c1692a 100755
--- a/AudioFilter/build.sh
+++ b/AudioFilter/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
@@ -21,13 +21,21 @@ JPL_FILE_NAME="${PLUGIN_NAME}.jpl"
 SO_FILE_NAME="lib${PLUGIN_NAME}.so"
 DAEMON_SRC="${DAEMON}/src"
 CONTRIB_PATH="${DAEMON}/contrib"
-PLUGINS_LIB="../lib"
+PLUGINS_LIB="./../lib"
 LIBS_DIR="./../contrib/Libs"
+PLATFORM=$(uname)
 
-if [ -z "${PLATFORM}" ]; then
+if [ "${PLATFORM}" = "Linux" ]; then
     PLATFORM="linux-gnu"
-    echo "PLATFORM not provided, building with ${PLATFORM}"
-    echo "Other options: redhat-linux"
+    CONTRIB_PLATFORM_CURT=${ARCH}
+    echo "Building with ${PLATFORM}"
+elif [ "${PLATFORM}" = "Darwin" ]; then
+    PLATFORM="darwin"
+    SO_FILE_NAME="lib${PLUGIN_NAME}.dylib"
+    alias nproc='sysctl -n hw.logicalcpu'
+    CONTRIB_PLATFORM_CURT=${ARCH}-apple
+    CONTRIB_PLATFORM_EXTRA=$(uname -r)
+    echo "Building with ${PLATFORM}"
 fi
 
 while getopts t:c:p OPT; do
@@ -46,7 +54,6 @@ while getopts t:c:p OPT; do
   esac
 done
 
-pwd
 cp -r ffmpeg ${CONTRIB_PATH}/src/
 
 if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
@@ -62,7 +69,6 @@ then
 
     python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
 
-    CONTRIB_PLATFORM_CURT=${ARCH}
     CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
 
     # Compile
@@ -91,7 +97,63 @@ then
     -l:libvpx.a \
     -l:libx264.a \
     -lva \
-    -o "build-local/jpl/lib/${CONTRIB_PLATFORM_CURT}-linux-gnu/${SO_FILE_NAME}"
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+elif [ "${PLATFORM}" = "darwin" ]
+then
+    if [ -f "${CONTRIB_PATH}/native/.ffmpeg" ]; then
+        rm "${CONTRIB_PATH}/native/.ffmpeg"
+    fi
+    WORKPATH=$(pwd)
+    cd "${CONTRIB_PATH}/native/"
+    make .ffmpeg -j$(nproc)
+    rm .ffmpeg
+    cd ${WORKPATH}
+
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+  
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+
+    # Compile
+    clang++ -std=c++17 -shared -fPIC \
+    -Wl,-no_compact_unwind -Wl,-framework,CoreFoundation \
+    -Wl,-framework,Security -Wl,-framework,VideoToolbox \
+    -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo \
+    -Wl,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-variable \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
+    -I"${PLUGINS_LIB}" \
+    ./../lib/frameFilter.cpp \
+    ./../lib/frameUtils.cpp \
+    FilterMediaHandler.cpp \
+    FilterAudioSubscriber.cpp \
+    main.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/" \
+    -lavfilter \
+    -lswscale \
+    -lswresample \
+    -lavformat \
+    -lavcodec \
+    -lavutil \
+    -lvpx -lx264 -lbz2 -liconv -lz \
+    "/usr/local/opt/speex/lib/libspeex.a" \
+    "/usr/local/opt/opus/lib/libopus.a" \
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+      ditto -c -k --rsrc "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}" "build-local/${SO_FILE_NAME}.zip"
+      LIBRARYNAME=${SO_FILE_NAME} sh ./../notarize.sh
+      ditto -x -k "build-local/${SO_FILE_NAME}.zip" "build-local/notarized"
+      cp "build-local/notarized/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
 
 elif [ "${PLATFORM}" = "android" ]
 then
diff --git a/AudioFilter/ffmpeg/rules.mak b/AudioFilter/ffmpeg/rules.mak
index f4e0ada4330e2646ec7e8920a1463a72cfe4acba..7a8eb4f6796a3ad2b542a5eacbf9fec45c47fb7d 100644
--- a/AudioFilter/ffmpeg/rules.mak
+++ b/AudioFilter/ffmpeg/rules.mak
@@ -168,16 +168,8 @@ FFMPEGCONF += \
 
 #filters
 FFMPEGCONF += \
-	--enable-filter=scale \
-	--enable-filter=overlay \
-	--enable-filter=amix \
-	--enable-filter=amerge \
 	--enable-filter=aresample \
-	--enable-filter=format \
 	--enable-filter=aformat \
-	--enable-filter=fps \
-	--enable-filter=transpose \
-	--enable-filter=pad \
     --enable-filter=afir
 
 #platform specific options
diff --git a/AutoAnswer/build.sh b/AutoAnswer/build.sh
index 12f6d35efe66662ec6405fd534e7f5535f50004e..c46b2270607d76639fbabc355bb806a17e172480 100755
--- a/AutoAnswer/build.sh
+++ b/AutoAnswer/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
@@ -21,13 +21,19 @@ JPL_FILE_NAME="${PLUGIN_NAME}.jpl"
 SO_FILE_NAME="lib${PLUGIN_NAME}.so"
 DAEMON_SRC="${DAEMON}/src"
 CONTRIB_PATH="${DAEMON}/contrib"
-PLUGINS_LIB="../lib"
+PLUGINS_LIB="./../lib"
 LIBS_DIR="./../contrib/Libs"
+PLATFORM=$(uname)
 
-if [ -z "${PLATFORM}" ]; then
+if [ "${PLATFORM}" = "Linux" ]; then
     PLATFORM="linux-gnu"
-    echo "PLATFORM not provided, building with ${PLATFORM}"
-    echo "Other options: redhat-linux"
+    CONTRIB_PLATFORM_CURT=${ARCH}
+    echo "Building with ${PLATFORM}"
+elif [ "${PLATFORM}" = "Darwin" ]; then
+    SO_FILE_NAME="lib${PLUGIN_NAME}.dylib"
+    CONTRIB_PLATFORM_CURT=${ARCH}-apple
+    CONTRIB_PLATFORM_EXTRA=$(uname -r)
+    echo "Building with ${PLATFORM}"
 fi
 
 while getopts t:c:p OPT; do
@@ -46,16 +52,19 @@ while getopts t:c:p OPT; do
   esac
 done
 
-if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
+if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ] || [ "${PLATFORM}" = "Darwin" ]
 then
     python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
 
-    CONTRIB_PLATFORM_CURT=${ARCH}
     CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+    OUTPUTFOLDER=${CONTRIB_PLATFORM}
+    if [ "${PLATFORM}" = "Darwin" ]; then
+      CONTRIB_PLATFORM=${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}
+    fi
 
     # Compile
     clang++ -std=c++17 -shared -fPIC \
-    -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \
+    -Wl,-rpath,"\${ORIGIN}" \
     -Wall -Wextra \
     -Wno-unused-variable \
     -Wno-unused-function \
@@ -68,7 +77,19 @@ then
     BotPeerChatSubscriber.cpp \
     main.cpp \
     -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/lib/" \
-    -o "build-local/jpl/lib/${CONTRIB_PLATFORM_CURT}-linux-gnu/${SO_FILE_NAME}"
+    -o "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}"
+
+    if [ "${PLATFORM}" = "Darwin" ]; then
+      install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}"
+    fi
+
+    if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}"
+      ditto -c -k --rsrc "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}" "build-local/${SO_FILE_NAME}.zip"
+      LIBRARYNAME=${SO_FILE_NAME} sh ./../notarize.sh
+      ditto -x -k "build-local/${SO_FILE_NAME}.zip" "build-local/notarized"
+      cp "build-local/notarized/${SO_FILE_NAME}" "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}"
+    fi
 
 elif [ "${PLATFORM}" = "android" ]
 then
diff --git a/GreenScreen/build.sh b/GreenScreen/build.sh
index a04f9e97c3562311c18a76d7c1317a9d28a09e63..5118613b1588c5a7ee339ee27aecf94f65185e02 100755
--- a/GreenScreen/build.sh
+++ b/GreenScreen/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
@@ -27,6 +27,20 @@ CONTRIB_PATH="${DAEMON}/contrib"
 PLUGINS_LIB="../lib"
 LIBS_DIR="./../contrib/Libs"
 PREFERENCESFILENAME="preferences"
+PLATFORM=$(uname)
+
+if [ "${PLATFORM}" = "Linux" ]; then
+    PLATFORM="linux-gnu"
+    CONTRIB_PLATFORM_CURT=${ARCH}
+    echo "Building with ${PLATFORM}"
+elif [ "${PLATFORM}" = "Darwin" ]; then
+    PLATFORM="darwin"
+    SO_FILE_NAME="lib${PLUGIN_NAME}.dylib"
+    alias nproc='sysctl -n hw.logicalcpu'
+    CONTRIB_PLATFORM_CURT=${ARCH}-apple
+    CONTRIB_PLATFORM_EXTRA=$(uname -r)
+    echo "Building with ${PLATFORM}"
+fi
 
 if [ "${PROCESSOR}" = "CPU" ]; then
     ONNX_LIBS="cpu"
@@ -36,8 +50,6 @@ elif [ "${PROCESSOR}" = "NVIDIA" ]; then
     PREFERENCESFILENAME="${PREFERENCESFILENAME}-accel"
 fi
 
-PLATFORM="linux-gnu"
-
 while getopts t:c:p OPT; do
   case "$OPT" in
     t)
@@ -58,7 +70,7 @@ done
 
 cp -r ffmpeg ${CONTRIB_PATH}/src/
 
-if [ "${PLATFORM}" = "linux-gnu" ]
+if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
 then
     if [ -f "${CONTRIB_PATH}/native/.ffmpeg" ]; then
         rm "${CONTRIB_PATH}/native/.ffmpeg"
@@ -68,9 +80,9 @@ then
     make .ffmpeg -j$(nproc)
     rm .ffmpeg
     cd ${WORKPATH}
+
     python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
 
-    CONTRIB_PLATFORM_CURT=${ARCH}
     CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
     ONNX_PATH=${EXTRALIBS_PATH}
     if [ -z "${EXTRALIBS_PATH}" ]
@@ -117,7 +129,6 @@ then
     -lonnxruntime \
     -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
 
-
     cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime.so" "build-local/jpl/lib/$CONTRIB_PLATFORM/libonnxruntime.so.1.6.0"
     if [ "${PROCESSOR}" = "NVIDIA" ]
     then
@@ -134,6 +145,90 @@ then
     cp "./modelSRC/mModel.onnx" "./build-local/jpl/data/model/mModel.onnx"
     cp "./${PREFERENCESFILENAME}.json" "./build-local/jpl/data/preferences.json"
 
+elif [ "${PLATFORM}" = "darwin" ]
+then  
+    if [ -f "${CONTRIB_PATH}/native/.ffmpeg" ]; then
+        rm "${CONTRIB_PATH}/native/.ffmpeg"
+    fi
+    WORKPATH=$(pwd)
+    cd "${CONTRIB_PATH}/native/"
+    make .ffmpeg -j$(nproc)
+    rm .ffmpeg
+    cd ${WORKPATH}
+
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+  
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+    ONNX_PATH=${EXTRALIBS_PATH}
+    if [ -z "${EXTRALIBS_PATH}" ]
+    then
+      ONNX_PATH="${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}"
+    fi
+
+    # Compile
+    clang++ -std=c++17 -shared -fPIC \
+    -Wl,-no_compact_unwind -Wl,-framework,CoreFoundation \
+    -Wl,-framework,Security -Wl,-framework,VideoToolbox \
+    -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo \
+    -Wl,-framework,OpenCl -Wl,-framework,Accelerate \
+    -Wl,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-variable \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -D${PROCESSOR} \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include/opencv4" \
+    -I"${ONNX_PATH}/include/onnxruntime/session" \
+    -I"${PLUGINS_LIB}" \
+    ./../lib/accel.cpp \
+    ./../lib/frameUtils.cpp \
+    ./../lib/frameFilter.cpp \
+    main.cpp \
+    videoSubscriber.cpp \
+    pluginMediaHandler.cpp \
+    pluginProcessor.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/" \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/opencv4/3rdparty/" \
+    -L"${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}" \
+    -lavfilter \
+    -lswscale \
+    -lavformat \
+    -lavcodec \
+    -lavutil \
+    -lvpx -lx264 -lbz2 -liconv -lz \
+    -lopencv_imgproc \
+    -lopencv_core \
+    -lonnxruntime \
+    "/usr/local/opt/speex/lib/libspeex.a" \
+    "/usr/local/opt/opus/lib/libopus.a" \
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime.dylib" "build-local/jpl/lib/${CONTRIB_PLATFORM}/libonnxruntime.dylib"
+    install_name_tool -id "@loader_path/libonnxruntime.1.6.0.dylib" "build-local/jpl/lib/${CONTRIB_PLATFORM}/libonnxruntime.dylib"
+    install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    install_name_tool -change "@rpath/libonnxruntime.1.6.0.dylib" "@loader_path/libonnxruntime.dylib" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    mkdir "./build-local/jpl/data/model"
+    cp "./modelSRC/mModel.onnx" "./build-local/jpl/data/model/mModel.onnx"
+    cp "./${PREFERENCESFILENAME}.json" "./build-local/jpl/data/preferences.json"
+
+    if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${CONTRIB_PLATFORM}/libonnxruntime.dylib"
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+      ditto -c -k --rsrc "build-local/jpl/lib/${CONTRIB_PLATFORM}/libonnxruntime.dylib" "build-local/libonnxruntime.dylib.zip"
+      LIBRARYNAME=libonnxruntime.dylib sh ./../notarize.sh
+      ditto -x -k "build-local/libonnxruntime.dylib.zip" "build-local/notarized0"
+      cp "build-local/notarized0/libonnxruntime.dylib" "build-local/jpl/lib/${CONTRIB_PLATFORM}/libonnxruntime.dylib"
+
+      ditto -c -k --rsrc "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}" "build-local/${SO_FILE_NAME}.zip"
+      LIBRARYNAME=${SO_FILE_NAME} sh ./../notarize.sh
+      ditto -x -k "build-local/${SO_FILE_NAME}.zip" "build-local/notarized1"
+      cp "build-local/notarized1/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
+
 elif [ "${PLATFORM}" = "android" ]
 then
     python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM}
diff --git a/GreenScreen/pluginProcessor.cpp b/GreenScreen/pluginProcessor.cpp
index ff4955b8b40421862ecded8225ced4fef9dec9bc..1337f6fb2e8d5ce4927fbf6376e4eb2c60e8a319 100644
--- a/GreenScreen/pluginProcessor.cpp
+++ b/GreenScreen/pluginProcessor.cpp
@@ -242,7 +242,7 @@ PluginProcessor::drawMaskOnFrame(AVFrame* frame, AVFrame* frameReduced, int angl
     cv::Mat roiMaskImg = previousMasks_[0].clone() * 255.;
     roiMaskImg.convertTo(roiMaskImg, CV_8UC1);
 
-    gsFrame maskFrame = {av_frame_alloc(), frameFree};
+    uniqueFramePtr maskFrame = {av_frame_alloc(), frameFree};
     maskFrame->format = AV_PIX_FMT_GRAY8;
     maskFrame->width = roiMaskImg.cols;
     maskFrame->height = roiMaskImg.rows;
diff --git a/GreenScreen/pluginProcessor.h b/GreenScreen/pluginProcessor.h
index 36eaa78407c41e9c9d52a14b4d39b5a8a3dd3366..aec78eb5d1483c4aae4dfd60a98809605f29db66 100644
--- a/GreenScreen/pluginProcessor.h
+++ b/GreenScreen/pluginProcessor.h
@@ -46,8 +46,6 @@ extern "C" {
 
 namespace jami {
 
-using gsFrame = std::unique_ptr<AVFrame, decltype(&frameFree)>;
-
 static const char* modelInputNames[8] = {"image:0"};
 static const char* modelOutputNames[11] = {"Identity:0"};
 
diff --git a/GreenScreen/videoSubscriber.cpp b/GreenScreen/videoSubscriber.cpp
index 92147c889ec5754164ad8200c8997c750b67f85a..25e6ce4bec8a8557f0c77c6d58e4613c1d1b9587 100644
--- a/GreenScreen/videoSubscriber.cpp
+++ b/GreenScreen/videoSubscriber.cpp
@@ -24,6 +24,7 @@
 extern "C" {
 #include <libavutil/display.h>
 }
+#include <frameScaler.h>
 #include <accel.h>
 #include <mediaStream.h>
 #include <pluglog.h>
@@ -89,7 +90,8 @@ VideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pluginFrame
 
     //======================================================================================
     // GET RAW FRAME
-    gsFrame rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
+    uniqueFramePtr rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
     if (!rgbFrame.get())
         return;
     rgbFrame->pts = 1;
@@ -133,6 +135,7 @@ VideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pluginFrame
     pluginProcessor.drawMaskOnFrame(rgbFrame.get(), filteredFrame, angle_);
     frameFree(filteredFrame);
 
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
     moveFrom(pluginFrame, rgbFrame.get());
 }
 
diff --git a/GreenScreen/videoSubscriber.h b/GreenScreen/videoSubscriber.h
index 9841ec79ce9c3743b1ac3b21478d36a104b017e2..df7edd378601740c3350b26352c6671be97a4851 100644
--- a/GreenScreen/videoSubscriber.h
+++ b/GreenScreen/videoSubscriber.h
@@ -54,7 +54,7 @@ private:
     // Observer pattern
     Observable<AVFrame*>* observable_ {};
     int angle_ {0};
-    gsFrame inputFrame_ = {av_frame_alloc(), frameFree};
+    uniqueFramePtr inputFrame_ = {av_frame_alloc(), frameFree};
     FrameFilter inputFilter_;
     std::string inputFilterDescription_;
 
diff --git a/HelloWorld/CenterCircleVideoSubscriber.cpp b/HelloWorld/CenterCircleVideoSubscriber.cpp
index 62babd049318d91b0cb1fa4992116eb72b2a7e0b..1b96c23d279a131e644c8664a8aad07491f9511f 100644
--- a/HelloWorld/CenterCircleVideoSubscriber.cpp
+++ b/HelloWorld/CenterCircleVideoSubscriber.cpp
@@ -25,6 +25,7 @@ extern "C" {
 }
 #include <accel.h>
 #include <frameUtils.h>
+#include <frameScaler.h>
 #include <pluglog.h>
 #include <stdio.h>
 #include <opencv2/imgproc.hpp>
@@ -65,19 +66,15 @@ CenterCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const&
     // GET RAW FRAME
     // Use a non-const Frame
     // Convert input frame to RGB
-    int inputHeight = pluginFrame->height;
-    int inputWidth = pluginFrame->width;
-    AVFrame* temp = transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12);
-    AVFrame* bgrFrame = scaler.convertFormat(temp, AV_PIX_FMT_RGB24);
-    av_frame_unref(temp);
-    av_frame_free(&temp);
-    if (!bgrFrame)
+    uniqueFramePtr rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_RGB24));
+    if (!rgbFrame.get())
         return;
-    resultFrame = cv::Mat {bgrFrame->height,
-                           bgrFrame->width,
+    resultFrame = cv::Mat {rgbFrame->height,
+                           rgbFrame->width,
                            CV_8UC3,
-                           bgrFrame->data[0],
-                           static_cast<size_t>(bgrFrame->linesize[0])};
+                           rgbFrame->data[0],
+                           static_cast<size_t>(rgbFrame->linesize[0])};
 
     // First clone the frame as the original one is unusable because of
     // linespace
@@ -85,8 +82,8 @@ CenterCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const&
 
     if (firstRun) {
         // we set were the circle will be draw.
-        circlePos.y = static_cast<int>(inputHeight / 2);
-        circlePos.x = static_cast<int>(inputWidth / 2);
+        circlePos.y = static_cast<int>(pluginFrame->height / 2);
+        circlePos.x = static_cast<int>(pluginFrame->width / 2);
         int w = resultFrame.size().width;
         int h = resultFrame.size().height;
         radius = std::min(w, h) / 8;
@@ -94,23 +91,12 @@ CenterCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const&
     }
 
     drawCenterCircle();
-    copyByLine(bgrFrame->linesize[0]);
+    copyByLine(rgbFrame->linesize[0]);
 
     //======================================================================================
     // REPLACE AVFRAME DATA WITH FRAME DATA
-    if (bgrFrame->data[0]) {
-        uint8_t* frameData = bgrFrame->data[0];
-        if (angle == 90 || angle == -90) {
-            std::memmove(frameData,
-                         resultFrame.data,
-                         static_cast<size_t>(pluginFrame->width * pluginFrame->height * 3)
-                             * sizeof(uint8_t));
-        }
-
-        moveFrom(pluginFrame, bgrFrame);
-    }
-    av_frame_unref(bgrFrame);
-    av_frame_free(&bgrFrame);
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
+    moveFrom(pluginFrame, rgbFrame.get());
 }
 
 void
diff --git a/HelloWorld/CenterCircleVideoSubscriber.h b/HelloWorld/CenterCircleVideoSubscriber.h
index e13713ff8cb9569eb045fc957494366a14029f75..29481f776cd36cbe2348a61ee34835b77b535683 100644
--- a/HelloWorld/CenterCircleVideoSubscriber.h
+++ b/HelloWorld/CenterCircleVideoSubscriber.h
@@ -24,7 +24,6 @@ extern "C" {
 #include <libavutil/frame.h>
 }
 #include <observer.h>
-#include <frameScaler.h>
 #include <opencv2/core.hpp>
 
 namespace jami {
@@ -49,7 +48,6 @@ private:
 
     // Data
     std::string path_;
-    FrameScaler scaler;
 
     // Status variables of the processing
     bool firstRun {true};
diff --git a/HelloWorld/CoinCircleVideoSubscriber.cpp b/HelloWorld/CoinCircleVideoSubscriber.cpp
index 46e8b8c38efa00f4d5b2efc5f2b4107ebd854233..b3e77208738180faf5699885983cc09291bae937 100644
--- a/HelloWorld/CoinCircleVideoSubscriber.cpp
+++ b/HelloWorld/CoinCircleVideoSubscriber.cpp
@@ -25,6 +25,7 @@ extern "C" {
 }
 #include <accel.h>
 #include <frameUtils.h>
+#include <frameScaler.h>
 #include <pluglog.h>
 #include <stdio.h>
 #include <opencv2/imgproc.hpp>
@@ -65,19 +66,15 @@ CoinCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& p
     // GET RAW FRAME
     // Use a non-const Frame
     // Convert input frame to RGB
-    int inputHeight = pluginFrame->height;
-    int inputWidth = pluginFrame->width;
-    AVFrame* temp = transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12);
-    AVFrame* bgrFrame = scaler.convertFormat(temp, AV_PIX_FMT_RGB24);
-    av_frame_unref(temp);
-    av_frame_free(&temp);
-    if (!bgrFrame)
+    uniqueFramePtr rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_RGB24));
+    if (!rgbFrame.get())
         return;
-    resultFrame = cv::Mat {bgrFrame->height,
-                           bgrFrame->width,
+    resultFrame = cv::Mat {rgbFrame->height,
+                           rgbFrame->width,
                            CV_8UC3,
-                           bgrFrame->data[0],
-                           static_cast<size_t>(bgrFrame->linesize[0])};
+                           rgbFrame->data[0],
+                           static_cast<size_t>(rgbFrame->linesize[0])};
 
     // First clone the frame as the original one is unusable because of
     // linespace
@@ -94,23 +91,12 @@ CoinCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& p
     }
 
     drawCoinCircle(angle);
-    copyByLine(bgrFrame->linesize[0]);
+    copyByLine(rgbFrame->linesize[0]);
 
     //======================================================================================
     // REPLACE AVFRAME DATA WITH FRAME DATA
-    if (bgrFrame->data[0]) {
-        uint8_t* frameData = bgrFrame->data[0];
-        if (angle == 90 || angle == -90) {
-            std::memmove(frameData,
-                         resultFrame.data,
-                         static_cast<size_t>(pluginFrame->width * pluginFrame->height * 3)
-                             * sizeof(uint8_t));
-        }
-
-        moveFrom(pluginFrame, bgrFrame);
-    }
-    av_frame_unref(bgrFrame);
-    av_frame_free(&bgrFrame);
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
+    moveFrom(pluginFrame, rgbFrame.get());
 }
 
 void
diff --git a/HelloWorld/CoinCircleVideoSubscriber.h b/HelloWorld/CoinCircleVideoSubscriber.h
index be1d466b7e472ab2062500bc4137796b66e92dcc..373f0b8007f7a0ac42022021584ce67b0d2c2045 100644
--- a/HelloWorld/CoinCircleVideoSubscriber.h
+++ b/HelloWorld/CoinCircleVideoSubscriber.h
@@ -24,7 +24,6 @@ extern "C" {
 #include <libavutil/frame.h>
 }
 #include <observer.h>
-#include <frameScaler.h>
 #include <opencv2/core.hpp>
 
 namespace jami {
@@ -49,7 +48,6 @@ private:
 
     // Data
     std::string path_;
-    FrameScaler scaler;
 
     // Status variables of the processing
     bool firstRun {true};
diff --git a/HelloWorld/build.sh b/HelloWorld/build.sh
index 953f7a3a178823e6fcb6db258e72ffab92ac385e..75f14c11d4ccd85d102a9be9499fc3f8e307932f 100755
--- a/HelloWorld/build.sh
+++ b/HelloWorld/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
@@ -23,11 +23,19 @@ DAEMON_SRC="${DAEMON}/src"
 CONTRIB_PATH="${DAEMON}/contrib"
 PLUGINS_LIB="../lib"
 LIBS_DIR="./../contrib/Libs"
+PLATFORM=$(uname)
 
-if [ -z "${PLATFORM}" ]; then
+if [ "${PLATFORM}" = "Linux" ]; then
     PLATFORM="linux-gnu"
-    echo "PLATFORM not provided, building with ${PLATFORM}"
-    echo "Other options: redhat-linux"
+    CONTRIB_PLATFORM_CURT=${ARCH}
+    echo "Building with ${PLATFORM}"
+elif [ "${PLATFORM}" = "Darwin" ]; then
+    PLATFORM="darwin"
+    SO_FILE_NAME="lib${PLUGIN_NAME}.dylib"
+    alias nproc='sysctl -n hw.logicalcpu'
+    CONTRIB_PLATFORM_CURT=${ARCH}-apple
+    CONTRIB_PLATFORM_EXTRA=$(uname -r)
+    echo "Building with ${PLATFORM}"
 fi
 
 while getopts t:c:p OPT; do
@@ -50,7 +58,6 @@ if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
 then
     python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
 
-    CONTRIB_PLATFORM_CURT=${ARCH}
     CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
 
     # Compile
@@ -78,7 +85,55 @@ then
     -lopencv_imgproc \
     -lopencv_core \
     -lva \
-    -o "build-local/jpl/lib/${CONTRIB_PLATFORM_CURT}-linux-gnu/${SO_FILE_NAME}"
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+elif [ "${PLATFORM}" = "darwin" ]
+then
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+
+    # Compile
+    clang++ -std=c++17 -shared -fPIC \
+    -Wl,-no_compact_unwind -Wl,-framework,CoreFoundation \
+    -Wl,-framework,Security -Wl,-framework,VideoToolbox \
+    -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo \
+    -Wl,-framework,OpenCl -Wl,-framework,Accelerate \
+    -Wl,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-variable \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include/opencv4" \
+    -I"${PLUGINS_LIB}" \
+    ./../lib/accel.cpp \
+    ./../lib/frameUtils.cpp \
+    CoinCircleMediaHandler.cpp \
+    CenterCircleVideoSubscriber.cpp \
+    CenterCircleMediaHandler.cpp \
+    CoinCircleVideoSubscriber.cpp \
+    main.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/" \
+    -lswscale \
+    -lavutil \
+    -lopencv_imgproc \
+    -lopencv_core \
+    -lvpx -lx264 -lbz2 -liconv -lz -lspeex -lopus \
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+      ditto -c -k --rsrc "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}" "build-local/${SO_FILE_NAME}.zip"
+      LIBRARYNAME=${PLUGIN_NAME} sh ./../notarize.sh
+      cd ..
+      ditto -x -k "build-local/${SO_FILE_NAME}.zip" "build-local/notarized"
+      cp "build-local/notarized/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
 
 elif [ "${PLATFORM}" = "android" ]
 then
diff --git a/SDK/Templates/videoUpdate.txt b/SDK/Templates/videoUpdate.txt
index e6f86f216d17b26ef81f9d68663dd258dcc76c9e..775e69a3a872cd9ae54ebd1f65c715bb0e546902 100644
--- a/SDK/Templates/videoUpdate.txt
+++ b/SDK/Templates/videoUpdate.txt
@@ -36,16 +36,9 @@
 
     //======================================================================================
     // REPLACE AVFRAME DATA WITH FRAME DATA
-    if (bgrFrame->data[0]) {
-        uint8_t* frameData = bgrFrame->data[0];
-        if (angle == 90 || angle == -90) {
-            std::memmove(frameData,
-                         frameData, // PUT HERE YOUR PROCESSED FRAME VARIABLE DATA!
-                         static_cast<size_t>(pluginFrame->width * pluginFrame->height * 3)
-                             * sizeof(uint8_t));
-        }
-
-        moveFrom(pluginFrame, bgrFrame);
-    }
+    temp = scaler.convertFormat(bgrFrame, AV_PIX_FMT_YUV420P);
+    moveFrom(pluginFrame, temp);
+    av_frame_unref(temp);
+    av_frame_free(&temp);
     av_frame_unref(bgrFrame);
     av_frame_free(&bgrFrame);
\ No newline at end of file
diff --git a/SDK/jplManipulation.py b/SDK/jplManipulation.py
index dbcdc71da14b25e04d76f5fb6d955cdf5a222f01..bcb3eb53974182e5e5cdd7093f583325e05f52c9 100644
--- a/SDK/jplManipulation.py
+++ b/SDK/jplManipulation.py
@@ -37,7 +37,7 @@ def getSystem():
     if system == "linux" or system == "linux2":
         return OS_IDS["Linux"]
     elif system == "darwin":
-        sys.exit("Plugins not supported on MacOS and IOS")
+        return OS_IDS["Darwin"]
     elif system == "windows":
         return OS_IDS["Windows"]
     sys.exit("Plugins SDK not supported on this system")
@@ -123,7 +123,7 @@ def preAssemble(pluginName, distribution=''):
         if (distribution != 'android'):
             distribution = "x86_64-linux-gnu"
     elif localSystem == OS_IDS["Darwin"]:
-        sys.exit("Plugins not supported on MacOS and IOS")
+        distribution = "x86_64-apple-Darwin"
     elif localSystem == OS_IDS["Windows"]:
         distribution = "x64-windows"
         osBuildPath = "msvc"
@@ -168,7 +168,7 @@ def assemble(pluginName, extraPath='', distribution=''):
         if (distribution != 'android'):
             distribution = "x86_64-linux-gnu"
     elif localSystem == OS_IDS["Darwin"]:
-        sys.exit("Plugins not supported on MacOS and IOS")
+        distribution = "x86_64-apple-Darwin"
     elif localSystem == OS_IDS["Windows"]:
         distribution = "x64-windows"
         osBuildPath = 'msvc'
diff --git a/WaterMark/WatermarkVideoSubscriber.cpp b/WaterMark/WatermarkVideoSubscriber.cpp
index 5989090785a462bb8556bba3411fd63dae8ffb83..2ab0d161abf692006feebd9b7826ecb612fac72d 100644
--- a/WaterMark/WatermarkVideoSubscriber.cpp
+++ b/WaterMark/WatermarkVideoSubscriber.cpp
@@ -316,7 +316,7 @@ WatermarkVideoSubscriber::setFilterDescription()
     else if (infosposition_ == "4")
         infosDescription_ = baseInfosDescription + std::to_string(points_[1].first)
                             + "-text_w:y=" + std::to_string(points_[1].second) + "-text_h";
-    infosDescription_ += ",rotate=" + rotation[-angle_] + rotateSides + ",format=rgb24";
+    infosDescription_ += ",rotate=" + rotation[-angle_] + rotateSides + ",format=yuv420p";
 
     Plog::log(Plog::LogPriority::INFO, TAG, infosDescription_);
     Plog::log(Plog::LogPriority::INFO, TAG, pluginFilterDescription_);
@@ -382,8 +382,8 @@ WatermarkVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pl
 
     //======================================================================================
     // GET RAW FRAME
-    wmFrame rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
-    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_RGB24));
+    uniqueFramePtr rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
     if (!rgbFrame.get())
         return;
     rgbFrame->pts = 1;
@@ -428,14 +428,14 @@ WatermarkVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pl
 
     if (showLogo_) {
         if (pluginFilter_.feedInput(rgbFrame.get(), "input") == 0) {
-            wmFrame filteredFrame = {pluginFilter_.readOutput(), frameFree};
+            uniqueFramePtr filteredFrame = {pluginFilter_.readOutput(), frameFree};
             if (filteredFrame.get())
                 moveFrom(rgbFrame.get(), filteredFrame.get());
         }
     }
     if (showInfos_) {
         if (infosFilter_.feedInput(rgbFrame.get(), "input") == 0) {
-            wmFrame filteredFrame = {infosFilter_.readOutput(), frameFree};
+            uniqueFramePtr filteredFrame = {infosFilter_.readOutput(), frameFree};
             if (filteredFrame.get())
                 moveFrom(rgbFrame.get(), filteredFrame.get());
         }
diff --git a/WaterMark/WatermarkVideoSubscriber.h b/WaterMark/WatermarkVideoSubscriber.h
index 69fd440630a6a054c98940c432970bf8a9e96b5e..5e26f5c35de6616d6aaa93dee1c45de5567b7118 100644
--- a/WaterMark/WatermarkVideoSubscriber.h
+++ b/WaterMark/WatermarkVideoSubscriber.h
@@ -31,8 +31,6 @@ extern "C" {
 
 namespace jami {
 
-using wmFrame = std::unique_ptr<AVFrame, decltype(&frameFree)>;
-
 enum Parameter {
     TIME,
     DATE,
@@ -107,7 +105,7 @@ private:
     FrameFilter logoFilter_;
     MediaStream logoStream_;
     std::string logoDescription_;
-    wmFrame mark_ = {av_frame_alloc(), frameFree};
+    uniqueFramePtr mark_ = {av_frame_alloc(), frameFree};
 
     FrameFilter infosFilter_;
     std::string infosDescription_;
diff --git a/WaterMark/build.sh b/WaterMark/build.sh
index 314cbe7229bde3233d6a4fe8bdfcee7c519d21fa..3cc3abf9842d8bd48659b34baf381c29b98940a3 100755
--- a/WaterMark/build.sh
+++ b/WaterMark/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
@@ -23,11 +23,19 @@ DAEMON_SRC="${DAEMON}/src"
 CONTRIB_PATH="${DAEMON}/contrib"
 PLUGINS_LIB="../lib"
 LIBS_DIR="./../contrib/Libs"
+PLATFORM=$(uname)
 
-if [ -z "${PLATFORM}" ]; then
+if [ "${PLATFORM}" = "Linux" ]; then
     PLATFORM="linux-gnu"
-    echo "PLATFORM not provided, building with ${PLATFORM}"
-    echo "Other options: redhat-linux"
+    CONTRIB_PLATFORM_CURT=${ARCH}
+    echo "Building with ${PLATFORM}"
+elif [ "${PLATFORM}" = "Darwin" ]; then
+    PLATFORM="darwin"
+    SO_FILE_NAME="lib${PLUGIN_NAME}.dylib"
+    alias nproc="sysctl -n hw.logicalcpu"
+    CONTRIB_PLATFORM_CURT=${ARCH}-apple
+    CONTRIB_PLATFORM_EXTRA=$(uname -r)
+    echo "Building with ${PLATFORM}"
 fi
 
 while getopts t:c:p OPT; do
@@ -61,7 +69,6 @@ then
 
     python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
 
-    CONTRIB_PLATFORM_CURT=${ARCH}
     CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
 
     # Compile
@@ -91,7 +98,65 @@ then
     -l:libx264.a \
     -lfreetype \
     -lva \
-    -o "build-local/jpl/lib/${CONTRIB_PLATFORM_CURT}-linux-gnu/${SO_FILE_NAME}"
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+elif [ "${PLATFORM}" = "darwin" ]
+then
+    if [ -f "${CONTRIB_PATH}/native/.ffmpeg" ]; then
+        rm "${CONTRIB_PATH}/native/.ffmpeg"
+    fi
+    WORKPATH=$(pwd)
+    cd "${CONTRIB_PATH}/native"
+    make .ffmpeg -j$(nproc)
+    rm .ffmpeg
+    cd ${WORKPATH}
+
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+
+    # Compile
+    clang++ -std=c++17 -shared -fPIC \
+    -Wl,-no_compact_unwind -Wl,-framework,CoreFoundation \
+    -Wl,-framework,Security -Wl,-framework,VideoToolbox \
+    -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo \
+    -Wl,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-variable \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
+    -I"${PLUGINS_LIB}" \
+    ./../lib/accel.cpp \
+    ./../lib/frameUtils.cpp \
+    ./../lib/frameFilter.cpp \
+    WatermarkVideoSubscriber.cpp \
+    main.cpp \
+    WatermarkMediaHandler.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/" \
+    -lavfilter \
+    -lswscale \
+    -lavformat \
+    -lavcodec \
+    -lavutil \
+    -lvpx -lx264 -lbz2 -liconv -lz \
+    "/usr/local/opt/libpng/lib/libpng.a" \
+    "/usr/local/opt/speex/lib/libspeex.a" \
+    "/usr/local/opt/opus/lib/libopus.a" \
+    "/usr/local/opt/freetype/lib/libfreetype.a" \
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+      ditto -c -k --rsrc "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}" "build-local/${SO_FILE_NAME}.zip"
+      LIBRARYNAME=${SO_FILE_NAME} sh ./../notarize.sh
+      ditto -x -k "build-local/${SO_FILE_NAME}.zip" "build-local/notarized"
+      cp "build-local/notarized/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
 
 elif [ "${PLATFORM}" = "android" ]
 then
diff --git a/build-plugin.py b/build-plugin.py
index 4c6e5de2b8183ec0c015061e610ff8ad1ea720cd..36a70efe38cc7f3caf205c9ee1b116162d2d614a 100644
--- a/build-plugin.py
+++ b/build-plugin.py
@@ -87,7 +87,7 @@ def validate_args(parsed_args):
     # Filter unsupported distributions.
     supported_distros = [
         ANDROID_DISTRIBUTION_NAME, UBUNTU_DISTRIBUTION_NAME,
-        WIN32_DISTRIBUTION_NAME
+        WIN32_DISTRIBUTION_NAME, OSX_DISTRIBUTION_NAME
     ]
 
     if parsed_args.distribution not in supported_distros:
diff --git a/lib/frameUtils.h b/lib/frameUtils.h
index 64b0c6fc9f867ed804bad3be2e1ae981a5ec759a..a49bfdbcc960bec3843a350067c8e498d85982ad 100644
--- a/lib/frameUtils.h
+++ b/lib/frameUtils.h
@@ -24,6 +24,7 @@
 extern "C" {
 #include <libavutil/frame.h>
 }
+#include <memory>
 
 /**
  * @brief moveFrom
@@ -38,4 +39,7 @@ void moveFrom(AVFrame* dst, AVFrame* src);
  * @param frame
  */
 void frameFree(AVFrame* frame);
+
+using uniqueFramePtr = std::unique_ptr<AVFrame, decltype(&frameFree)>;
+
 #endif // FRAMEUTILS_H
diff --git a/notarize.sh b/notarize.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f282f5aca9b73966cf6abd60e2d01b73b3ddf77e
--- /dev/null
+++ b/notarize.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+cd build-local
+/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework/Versions/A/Support/altool --notarize-app -t osx -f ${LIBRARYNAME}.zip --primary-bundle-id ${BUNDLE_ID} -u ${APPLE_ACCOUNT} -p ${APPLE_PASSWORD} --output-format xml -itc_provider ${TEAM_ID} > UploadInfo.plist
+REQUESTID=$(xmllint --xpath "/plist/dict[key='notarization-upload']/dict/key[.='RequestUUID']/following-sibling::string[1]/node()" UploadInfo.plist)
+echo "file uploaded for notarization"
+echo ${REQUESTID}
+sleep 60
+x=1
+while [ $x -le 15 ];
+do
+/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework/Versions/A/Support/altool --notarization-info ${REQUESTID} -u ${APPLE_ACCOUNT}  -p ${APPLE_PASSWORD}  --output-format xml > RequestedInfo.plist
+ANSWER=$(xmllint --xpath "/plist/dict[key='notarization-info']/dict/key[.='Status']/following-sibling::string[1]/node()" RequestedInfo.plist)
+if [ "$ANSWER" == "in progress" ];
+then
+echo  "notarization in progress"
+sleep 60
+x=$(( $x + 1 ))
+elif [ "$ANSWER" == "success" ]
+then
+echo  "notarization success"
+break
+else
+echo "notarization failed"
+break
+exit 1
+fi
+done
+ANSWER=$(xmllint --xpath "/plist/dict[key='notarization-info']/dict/key[.='Status']/following-sibling::string[1]/node()" RequestedInfo.plist)
+if [ "$ANSWER" != "success" ];
+then
+echo "notarization failed"
+exit 1
+fi