From 1bbc7cc2a5de65e03676a2f372be7c603df86887 Mon Sep 17 00:00:00 2001
From: agsantos <aline.gondimsantos@savoirfairelinux.com>
Date: Thu, 20 May 2021 16:43:35 -0400
Subject: [PATCH] macosx: add build option for macosx

Gitlab: #18
Change-Id: I1372c1881b894fd0cde76f5ad94067bd22192315
---
 AudioFilter/build.sh                       |  78 +++++++++++++--
 AudioFilter/ffmpeg/rules.mak               |   8 --
 AutoAnswer/build.sh                        |  39 ++++++--
 GreenScreen/build.sh                       | 107 +++++++++++++++++++--
 GreenScreen/pluginProcessor.cpp            |   2 +-
 GreenScreen/pluginProcessor.h              |   2 -
 GreenScreen/videoSubscriber.cpp            |   5 +-
 GreenScreen/videoSubscriber.h              |   2 +-
 HelloWorld/CenterCircleVideoSubscriber.cpp |  40 +++-----
 HelloWorld/CenterCircleVideoSubscriber.h   |   2 -
 HelloWorld/CoinCircleVideoSubscriber.cpp   |  36 +++----
 HelloWorld/CoinCircleVideoSubscriber.h     |   2 -
 HelloWorld/build.sh                        |  67 +++++++++++--
 SDK/Templates/videoUpdate.txt              |  15 +--
 SDK/jplManipulation.py                     |   6 +-
 WaterMark/WatermarkVideoSubscriber.cpp     |  10 +-
 WaterMark/WatermarkVideoSubscriber.h       |   4 +-
 WaterMark/build.sh                         |  77 +++++++++++++--
 build-plugin.py                            |   2 +-
 lib/frameUtils.h                           |   4 +
 notarize.sh                                |  34 +++++++
 21 files changed, 415 insertions(+), 127 deletions(-)
 create mode 100755 notarize.sh

diff --git a/AudioFilter/build.sh b/AudioFilter/build.sh
index cb36985..91ee4ae 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 f4e0ada..7a8eb4f 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 12f6d35..c46b227 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 a04f9e9..5118613 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 ff4955b..1337f6f 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 36eaa78..aec78eb 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 92147c8..25e6ce4 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 9841ec7..df7edd3 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 62babd0..1b96c23 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 e13713f..29481f7 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 46e8b8c..b3e7720 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 be1d466..373f0b8 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 953f7a3..75f14c1 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 e6f86f2..775e69a 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 dbcdc71..bcb3eb5 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 5989090..2ab0d16 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 69fd440..5e26f5c 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 314cbe7..3cc3abf 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 4c6e5de..36a70ef 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 64b0c6f..a49bfdb 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 0000000..f282f5a
--- /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
-- 
GitLab