Whisper: create base plugin

GitLab: #576
Change-Id: Icae9e8b0653aa7aa7987774cea80d1720673edc0
diff --git a/.tx/config b/.tx/config
index 3be6740..db52030 100755
--- a/.tx/config
+++ b/.tx/config
@@ -25,3 +25,9 @@
 type         = KEYVALUEJSON
 minimum_perc = 0
 
+[o:savoirfairelinux:p:jami:r:plugin_whispertranscript]
+file_filter  = WhisperTranscript/data/locale/WhisperTranscript_<lang>.json
+source_file  = WhisperTranscript/data/locale/WhisperTranscript_en.json
+type         = KEYVALUEJSON
+minimum_perc = 0
+
diff --git a/AudioFilter/FilterMediaHandler.cpp b/AudioFilter/FilterMediaHandler.cpp
index 02a0e06..cb18408 100644
--- a/AudioFilter/FilterMediaHandler.cpp
+++ b/AudioFilter/FilterMediaHandler.cpp
@@ -57,12 +57,12 @@
     oss << "preferredStreamDirection " << preferredStreamDirection << std::endl;
     if (data.type == StreamType::audio && !data.direction
         && data.direction == preferredStreamDirection) {
-        subject->attach(mAS_.get()); // your image
+        subject->attach(mAS_.get()); // your audio
         oss << "got my sent audio attached" << std::endl;
         attached_ = '1';
     } else if (data.type == StreamType::audio && data.direction
                && data.direction == preferredStreamDirection) {
-        subject->attach(mAS_.get()); // the image you receive from others on the call
+        subject->attach(mAS_.get()); // the audio you receive from others on the call
         oss << "got received audio attached" << std::endl;
         attached_ = '1';
     }
diff --git a/GreenScreen/CMakeLists.txt b/GreenScreen/CMakeLists.txt
index d4677ed..6401be9 100644
--- a/GreenScreen/CMakeLists.txt
+++ b/GreenScreen/CMakeLists.txt
@@ -118,6 +118,7 @@
     COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/zlib ${CONTRIB_PATH}/src/zlib
     COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/ffmpeg/ ${CONTRIB_PATH}/src/ffmpeg
     COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/../contrib/yaml-cpp ${CONTRIB_PATH}/src/yaml-cpp
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/../contrib/mp3lame ${CONTRIB_PATH}/src/mp3lame
     COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb yaml-cpp
     COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb zlib
     COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb ffmpeg
@@ -130,6 +131,7 @@
         PRE_BUILD
         COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/testPreferences.yml ${PROJECT_BINARY_DIR}/
         COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/sample.mp4 ${PROJECT_BINARY_DIR}/
+        COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/Debug
         COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime.lib ${PROJECT_BINARY_DIR}/Debug
         COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime.dll ${PROJECT_BINARY_DIR}/Debug
         COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/data/model
diff --git a/GreenScreen/videoSubscriber.h b/GreenScreen/videoSubscriber.h
index df7edd3..ba8f485 100644
--- a/GreenScreen/videoSubscriber.h
+++ b/GreenScreen/videoSubscriber.h
@@ -33,15 +33,15 @@
 
 namespace jami {
 
-class VideoSubscriber : public jami::Observer<AVFrame*>
+class VideoSubscriber : public Observer<AVFrame*>
 {
 public:
     VideoSubscriber(const std::string& model, bool acc = false);
     ~VideoSubscriber();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override;
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
     void stop();
diff --git a/HelloWorld/CenterCircleVideoSubscriber.h b/HelloWorld/CenterCircleVideoSubscriber.h
index 29481f7..f8f11a5 100644
--- a/HelloWorld/CenterCircleVideoSubscriber.h
+++ b/HelloWorld/CenterCircleVideoSubscriber.h
@@ -28,15 +28,15 @@
 
 namespace jami {
 
-class CenterCircleVideoSubscriber : public jami::Observer<AVFrame*>
+class CenterCircleVideoSubscriber : public Observer<AVFrame*>
 {
 public:
     CenterCircleVideoSubscriber(const std::string& dataPath);
     ~CenterCircleVideoSubscriber();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override;
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
 
diff --git a/HelloWorld/CoinCircleVideoSubscriber.h b/HelloWorld/CoinCircleVideoSubscriber.h
index 373f0b8..c355cab 100644
--- a/HelloWorld/CoinCircleVideoSubscriber.h
+++ b/HelloWorld/CoinCircleVideoSubscriber.h
@@ -28,15 +28,15 @@
 
 namespace jami {
 
-class CoinCircleVideoSubscriber : public jami::Observer<AVFrame*>
+class CoinCircleVideoSubscriber : public Observer<AVFrame*>
 {
 public:
     CoinCircleVideoSubscriber(const std::string& dataPath);
     ~CoinCircleVideoSubscriber();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override;
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
 
diff --git a/SDK/Templates/build.sh b/SDK/Templates/build.sh
index 6c23c16..7f61802 100644
--- a/SDK/Templates/build.sh
+++ b/SDK/Templates/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
@@ -48,17 +48,24 @@
 
 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}
 
+    if [ ${DEBUG} ]; then
+      OUTPUT="${PLUGIN_NAME}"
+      CLANG_OPTS="-g -fsanitize=address"
+      EXTRA_DEBUG_LIBRARIES="-lyaml-cpp"
+      EXTRA_DEFINES="-D__DEBUG__"
+    else
+      python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+      CLANG_OPTS="-O3 -shared"
+      OUTPUT="build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
+
     # Compile
-    clang++ -std=c++17 -shared -fPIC \
+    clang++ -std=c++17 -fPIC ${CLANG_OPTS} \
     -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \
     -Wall -Wextra \
-    -Wno-unused-variable \
-    -Wno-unused-function \
     -Wno-unused-parameter \
     -I"." \
     -I"${DAEMON_SRC}" \
diff --git a/SDK/Templates/genericMediaHandler.cpp b/SDK/Templates/genericMediaHandler.cpp
index 109ec71..825cb1c 100644
--- a/SDK/Templates/genericMediaHandler.cpp
+++ b/SDK/Templates/genericMediaHandler.cpp
@@ -32,12 +32,12 @@
     oss << "preferredStreamDirection " << preferredStreamDirection << std::endl;
     if (data.type == StreamType::DataType && !data.direction
         && data.direction == preferredStreamDirection) {
-        subject->attach(mediaSubscriber_.get()); // your image
+        subject->attach(mediaSubscriber_.get()); // your media
         oss << "got my sent image attached" << std::endl;
         attached_ = "1";
     } else if (data.type == StreamType::DataType && data.direction
                && data.direction == preferredStreamDirection) {
-        subject->attach(mediaSubscriber_.get()); // the image you receive from others on the call
+        subject->attach(mediaSubscriber_.get()); // the media you receive from others on the call
         oss << "got received image attached" << std::endl;
         attached_ = "1";
     }
diff --git a/SDK/Templates/genericMediaHandler.h b/SDK/Templates/genericMediaHandler.h
index 2e806b9..50409a7 100644
--- a/SDK/Templates/genericMediaHandler.h
+++ b/SDK/Templates/genericMediaHandler.h
@@ -7,11 +7,11 @@
 #include "plugin/jamiplugin.h"
 #include "plugin/mediahandler.h"
 
-using avSubjectPtr = std::weak_ptr<jami::Observable<AVFrame*>>;
-
 namespace jami {
 
-class GENERICMediaHandler : public jami::CallMediaHandler
+using avSubjectPtr = std::weak_ptr<Observable<AVFrame*>>;
+
+class GENERICMediaHandler : public CallMediaHandler
 {
 public:
     GENERICMediaHandler(std::map<std::string, std::string>&& preferences, std::string&& dataPath);
diff --git a/SDK/Templates/genericMediaSubscriber.h b/SDK/Templates/genericMediaSubscriber.h
index c716844..2e86975 100644
--- a/SDK/Templates/genericMediaSubscriber.h
+++ b/SDK/Templates/genericMediaSubscriber.h
@@ -11,15 +11,15 @@
 
 namespace jami {
 
-class GENERICDATATYPESubscriber : public jami::Observer<AVFrame*>
+class GENERICDATATYPESubscriber : public Observer<AVFrame*>
 {
 public:
     GENERICDATATYPESubscriber(const std::string& dataPath);
     ~GENERICDATATYPESubscriber();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override;
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
 
diff --git a/SDK/Templates/main.cpp b/SDK/Templates/main.cpp
index abca25b..436601e 100644
--- a/SDK/Templates/main.cpp
+++ b/SDK/Templates/main.cpp
@@ -8,6 +8,14 @@
 ----------------
 #include "INCLUDESAPI.h"----------------
 
+
+#ifdef __DEBUG__
+#include <common.h>
+#include <assert.h>
+#include <yaml-cpp/yaml.h>
+#include <fstream>
+#endif
+
 #ifdef WIN32
 #define EXPORT_PLUGIN __declspec(dllexport)
 #else
@@ -49,3 +57,41 @@
     return pluginExit;
 }
 }
+
+#ifdef __DEBUG__
+
+int
+main ()
+{
+    std::cout << "*******************************" << std::endl;
+    std::cout << "**  PLUGINNAME Debug Version  **" << std::endl;
+    std::cout << "*******************************" << std::endl;
+    std::cout << "Version " << PLUGINNAME_VERSION_MAJOR << "." << PLUGINNAME_VERSION_MINOR << "."
+              << PLUGINNAME_VERSION_PATCH << std::endl << std::endl;
+
+    std::ifstream file;
+    file_utils::openStream(file, "testPreferences.yml");
+
+    assert(file.is_open());
+    YAML::Node node = YAML::Load(file);
+
+    assert(node.IsMap());
+    std::map<std::string, std::map<std::string, std::string>> preferences;
+    preferences["default"] = {};
+    for (const auto& kv : node) {
+        preferences["default"][kv.first.as<std::string>()] = kv.second.as<std::string>();
+        std::cout << "Key: " << kv.first.as<std::string>() << "; Value: " << kv.second.as<std::string>() << std::endl;
+    }
+
+#ifdef _WIN32
+    std::string dataPath = "../data";
+#else
+    std::string dataPath = "data";
+#endif
+
+
+
+    return 0;
+}
+
+#endif
diff --git a/TensorflowSegmentation/build.sh b/TensorflowSegmentation/build.sh
index ddeb354..1c35673 100755
--- a/TensorflowSegmentation/build.sh
+++ b/TensorflowSegmentation/build.sh
@@ -2,7 +2,7 @@
 # Build the plugin for the project
 set -e
 export OSTYPE
-ARCH=$(arch)
+ARCH=$(uname -m)
 EXTRAPATH=''
 # Flags:
 
diff --git a/TensorflowSegmentation/videoSubscriber.h b/TensorflowSegmentation/videoSubscriber.h
index 8f37c54..51949f2 100644
--- a/TensorflowSegmentation/videoSubscriber.h
+++ b/TensorflowSegmentation/videoSubscriber.h
@@ -51,15 +51,15 @@
     cv::Mat predictionsResizedFrameRGB;
 };
 
-class VideoSubscriber : public jami::Observer<AVFrame*>
+class VideoSubscriber : public Observer<AVFrame*>
 {
 public:
     VideoSubscriber(const std::string& dataPath);
     ~VideoSubscriber();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override;
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
     void stop();
diff --git a/TestSuite/VideoSubscriberTester.h b/TestSuite/VideoSubscriberTester.h
index 49d5ca7..794637e 100644
--- a/TestSuite/VideoSubscriberTester.h
+++ b/TestSuite/VideoSubscriberTester.h
@@ -27,15 +27,15 @@
 
 namespace jami {
 
-class VideoSubscriberTester : public jami::Observer<AVFrame*>
+class VideoSubscriberTester : public Observer<AVFrame*>
 {
 public:
     VideoSubscriberTester() {}
     ~VideoSubscriberTester();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override {}
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override {}
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
 
diff --git a/WaterMark/CMakeLists.txt b/WaterMark/CMakeLists.txt
index aff84f7..1071671 100644
--- a/WaterMark/CMakeLists.txt
+++ b/WaterMark/CMakeLists.txt
@@ -99,6 +99,7 @@
     PRE_BUILD
     COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/zlib ${CONTRIB_PATH}/src/zlib
     COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/../contrib/freetype ${CONTRIB_PATH}/src/freetype
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/../contrib/mp3lame ${CONTRIB_PATH}/src/mp3lame
     COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/ffmpeg/ ${CONTRIB_PATH}/src/ffmpeg
     COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb zlib
     COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb freetype
diff --git a/WaterMark/WatermarkVideoSubscriber.h b/WaterMark/WatermarkVideoSubscriber.h
index 311d933..db0417a 100644
--- a/WaterMark/WatermarkVideoSubscriber.h
+++ b/WaterMark/WatermarkVideoSubscriber.h
@@ -48,15 +48,15 @@
     SHOWINFOS,
 };
 
-class WatermarkVideoSubscriber : public jami::Observer<AVFrame*>
+class WatermarkVideoSubscriber : public Observer<AVFrame*>
 {
 public:
     WatermarkVideoSubscriber(const std::string& dataPath);
     ~WatermarkVideoSubscriber();
 
-    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override;
-    virtual void attached(jami::Observable<AVFrame*>*) override;
-    virtual void detached(jami::Observable<AVFrame*>*) override;
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
 
     void detach();
 
diff --git a/WhisperTranscript/.gitignore b/WhisperTranscript/.gitignore
new file mode 100644
index 0000000..5a3f926
--- /dev/null
+++ b/WhisperTranscript/.gitignore
@@ -0,0 +1,5 @@
+*.mp3
+/WhisperTranscript*
+libonnxruntime.so*
+/libonnxruntime.dylib
+/processed.mp4
diff --git a/WhisperTranscript/CMakeLists.txt b/WhisperTranscript/CMakeLists.txt
new file mode 100644
index 0000000..db5f416
--- /dev/null
+++ b/WhisperTranscript/CMakeLists.txt
@@ -0,0 +1,171 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+set (ProjectName WhisperTranscript)
+set (Version 0.0.0)
+
+project(${ProjectName} VERSION ${Version})
+
+set (DAEMON ${PROJECT_SOURCE_DIR}/../../daemon)
+set (JPL_FILE_NAME ${ProjectName}.jpl)
+set (DAEMON_SRC ${DAEMON}/src)
+set (CONTRIB_PATH ${DAEMON}/contrib)
+set (PLUGINS_LIB ${PROJECT_SOURCE_DIR}/../lib)
+set (JPL_DIRECTORY ${PROJECT_BINARY_DIR}/jpl)
+set (LIBS_DIR ${PROJECT_SOURCE_DIR}/../contrib/Libs)
+set (ONNX_DIR $ENV{PLUGIN_ENV}/onnxruntime)
+
+if(WIN32)
+    message(OS:\  WINDOWS\ ${CMAKE_SYSTEM_PROCESSOR})
+    if (NOT ${CMAKE_CL_64})
+        message( FATAL_ERROR "\nUse CMake only for x64 Windows" )
+    endif()
+    set (CONTRIB_PLATFORM_CURT x64)
+    set (CONTRIB_PLATFORM ${CONTRIB_PLATFORM_CURT}-windows)
+    set (LIBRARY_FILE_NAME ${ProjectName}.dll)
+    set (FFMPEG ${CONTRIB_PATH}/build/ffmpeg/Build/win32/x64)
+else()
+    message( FATAL_ERROR "\nUse CMake only for Windows! For linux or Android (linux host), use our bash scripts." )
+endif()
+
+message(Building:\   ${ProjectName}\   ${Version})
+message(Build\ path:\ ${PROJECT_BINARY_DIR})
+message(JPL\ assembling\ path:\ ${JPL_DIRECTORY})
+message(JPL\ path:\ ${JPL_DIRECTORY}/../../../build/${ProjectName}/${JPL_FILE_NAME})
+
+if(NVIDIA)
+add_definitions(-DNVIDIA)
+set(ONNX_DIR ${ONNX_DIR}/nvidia-gpu)
+message(Provider:\ NVIDIA)
+set(EXTRA_PATH nvidia-gpu)
+else()
+set(ONNX_DIR ${ONNX_DIR}/cpu)
+message(Provider:\ NONE)
+set(EXTRA_PATH cpu)
+endif()
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+
+if(TESTPROCESS)
+    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D__DEBUG__ /MT")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /D__DEBUG__ /MT")
+else()
+    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MT")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+endif()
+
+set(plugin_SRC main.cpp
+               TranscriptMediaHandler.cpp
+               TranscriptAudioSubscriber.cpp
+               TranscriptVideoSubscriber.cpp
+               Preprocess.cpp
+               ModelProcessor.cpp
+               ./../lib/accel.cpp
+               ./../lib/frameUtils.cpp
+               ./../lib/frameFilter.cpp
+               ./../lib/common.cpp
+               )
+
+set(plugin_HDR TranscriptAudioSubscriber.h
+               TranscriptVideoSubscriber.h
+               TranscriptMediaHandler.h
+               Preprocess.h
+               ModelProcessor.h
+               ./../lib/frameUtils.h
+               ./../lib/frameFilter.h
+               ./../lib/common.h
+               ./../lib/pluglog.h
+               ./../lib/mediaStream.h
+               ./../lib/audioFormat.h
+               )
+
+if(TESTPROCESS)
+    add_executable(${ProjectName} ${plugin_SRC}
+                                    ${plugin_HDR}
+                                    )
+else()
+    add_library(${ProjectName} SHARED ${plugin_SRC}
+                                        ${plugin_HDR}
+                                        )
+endif()
+
+target_include_directories(${ProjectName} PUBLIC ${PROJECT_BINARY_DIR}
+                                                 ${PROJECT_SOURCE_DIR}
+                                                 ${PLUGINS_LIB}
+                                                 ${DAEMON_SRC}
+                                                 ${CONTRIB_PATH}
+                                                 ${CONTRIB_PATH}/build/fmt/include
+                                                 ${FFMPEG}/include
+                                                 ${ONNX_DIR}/../include/session
+                                                 ${ONNX_DIR}/../include/providers/cuda
+                                                 ${CONTRIB_PATH}/build/yaml-cpp/include
+                                                 )
+target_link_directories(${ProjectName} PUBLIC ${CONTRIB_PATH}
+                                              ${CONTRIB_PATH}/build/fmt/msvc/Release
+                                              ${FFMPEG}/lib
+                                              ${ONNX_DIR}
+                                              ${CONTRIB_PATH}/msvc/lib/x64
+                                              ${CONTRIB_PATH}/build/fmt/msvc/Release
+                                              ${CONTRIB_PATH}/build/yaml-cpp/msvc/Release
+                                              )
+
+target_link_libraries(${ProjectName} PUBLIC libyaml-cppmd libavfilter libswscale libswresample libavformat
+                                            libavcodec libavutil libvpx libx264 libopus libmfx
+                                            libzlib ws2_32 Bcrypt Secur32  onnxruntime msvcrt)
+
+add_custom_command(
+    TARGET ${ProjectName}
+    PRE_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/zlib ${CONTRIB_PATH}/src/zlib
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/ffmpeg/ ${CONTRIB_PATH}/src/ffmpeg
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/../contrib/yaml-cpp ${CONTRIB_PATH}/src/yaml-cpp
+    COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb yaml-cpp
+    COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb zlib
+    COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb ffmpeg
+    COMMAND cd ${CONTRIB_PATH}/src/
+    COMMAND git checkout *
+)
+
+
+if(TESTPROCESS)
+    add_custom_command(
+        TARGET ${ProjectName}
+        PRE_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/testPreferences.yml ${PROJECT_BINARY_DIR}/
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/jfk.wav ${PROJECT_BINARY_DIR}/
+        COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime.lib ${PROJECT_BINARY_DIR}/Debug
+        COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime.dll ${PROJECT_BINARY_DIR}/Debug
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/modelSRC/mModelEncoder.onnx ${PROJECT_SOURCE_DIR}/data/assets
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/modelSRC/mModelDecoder.onnx ${PROJECT_SOURCE_DIR}/data/assets
+    )
+else()
+    add_custom_command(
+        TARGET ${ProjectName}
+        PRE_BUILD
+        COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --preassemble --plugin=${ProjectName}
+        COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+        COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime.dll ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/modelSRC/mModelEncoder.onnx ${JPL_DIRECTORY}/data/assets
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/modelSRC/mModelDecoder.onnx ${JPL_DIRECTORY}/data/assets
+        COMMENT "Assembling Plugin files"
+    )
+    if(NVIDIA)
+        add_custom_command(
+            TARGET ${ProjectName}
+            PRE_BUILD
+            COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime_providers_shared.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+            COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime_providers_shared.dll ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+            COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime_providers_cuda.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+            COMMAND ${CMAKE_COMMAND} -E copy ${ONNX_DIR}/onnxruntime_providers_cuda.dll ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+        )
+    endif()
+    add_custom_command(
+        TARGET ${ProjectName}
+        POST_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${ProjectName}.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+        COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${LIBRARY_FILE_NAME} ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+        COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --assemble --plugin=${ProjectName} --extraPath=${EXTRA_PATH}
+        COMMENT "Generating JPL archive"
+    )
+endif()
diff --git a/WhisperTranscript/ModelProcessor.cpp b/WhisperTranscript/ModelProcessor.cpp
new file mode 100644
index 0000000..6c0a7b8
--- /dev/null
+++ b/WhisperTranscript/ModelProcessor.cpp
@@ -0,0 +1,323 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ * USA.
+ */
+
+#include "ModelProcessor.h"
+
+#include <pluglog.h>
+#include <common.h>
+
+const char sep = separator();
+
+const std::string TAG = "Transcript";
+
+namespace jami {
+
+ModelProcessor::ModelProcessor(const std::string& path, bool acc)
+{
+    loadTokens(path + "/assets/tokenizer.bin", vocab_);
+
+#ifdef __ANDROID__
+    initModels(path + "/assets/mModelEncoder.ort", path + "/assets/mModelDecoder.ort", path + "/assets/mLogSoftMax.ort", acc);
+#else
+    initModels(path + "/assets/mModelEncoder.onnx", path + "/assets/mModelDecoder.onnx", path + "/assets/mLogSoftMax.onnx", acc);
+#endif
+}
+
+ModelProcessor::~ModelProcessor()
+{
+    endModels();
+    Plog::log(Plog::LogPriority::INFO, TAG, "~ModelProcessor");
+}
+
+void
+ModelProcessor::endModels()
+{
+    if (encoderSession_) {
+        delete encoderSession_;
+        encoderSession_ = nullptr;
+    }
+    if (decoderSession_) {
+        delete decoderSession_;
+        decoderSession_ = nullptr;
+    }
+    if (logSoftMaxSession_) {
+        delete logSoftMaxSession_;
+        logSoftMaxSession_ = nullptr;
+    }
+    if (env_)
+        env_.release();
+    env_ = NULL;
+}
+
+void
+ModelProcessor::initModels(const std::string& encoderModelPath, const std::string& decoderModelPath, const std::string& logSoftMaxModelPath, bool activateAcc)
+{
+    try {
+        sessOpt_ = Ort::SessionOptions();
+
+#ifdef NVIDIA
+        if (activateAcc)
+            Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(sessOpt_, 0));
+#endif
+#ifdef __ANDROID__
+        if (activateAcc)
+            Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_Nnapi(sessOpt_, 0));
+#endif
+
+        sessOpt_.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
+#ifdef WIN32
+        encoderSession_ = new Ort::Session(env_, string_utils::to_wstring(encoderModelPath).c_str(), sessOpt_);
+        decoderSession_ = new Ort::Session(env_, string_utils::to_wstring(decoderModelPath).c_str(), sessOpt_);
+        logSoftMaxSession_ = new Ort::Session(env_, string_utils::to_wstring(logSoftMaxModelPath).c_str(), sessOpt_);
+#else
+        encoderSession_ = new Ort::Session(env_, encoderModelPath.c_str(), sessOpt_);
+        decoderSession_ = new Ort::Session(env_, decoderModelPath.c_str(), sessOpt_);
+        logSoftMaxSession_ = new Ort::Session(env_, logSoftMaxModelPath.c_str(), sessOpt_);
+#endif
+        isAllocated_ = true;
+        Plog::log(Plog::LogPriority::INFO, TAG, "Model is allocated");
+    } catch (std::exception& e) {
+        Plog::log(Plog::LogPriority::ERR, TAG, e.what());
+    }
+}
+
+/* from whisper.cpp */
+// the most basic sampling scheme - select the top token
+whisperTokenData
+ModelProcessor::whisper_sample_best(const float * probs)
+{
+    whisperTokenData result = {
+        0, 0, 0.0f, 0.0f, 0.0f, -1, -1, 0.0f,
+    };
+
+    int n_logits = vocab_.id_to_token.size();
+
+    std::vector<std::pair<double, int64_t>> probs_id;
+    probs_id.reserve(n_logits);
+
+    for (int i = 0; i < n_logits; i++) {
+        probs_id.push_back(std::make_pair(probs[i], i));
+    }
+
+    {
+        double sum_ts =  0.0;
+        double max_ts = -1.0;
+        double max_tx = -1.0;
+
+        for (int i = 0; i < vocab_.token_beg; i++) {
+            max_tx = std::max(max_tx, probs_id[i].first);
+        }
+
+        for (int i = vocab_.token_beg; i < n_logits; i++) {
+            sum_ts += probs_id[i].first;
+            if  (probs_id[i].first > max_ts) {
+                max_ts = probs_id[i].first;
+                result.tid = probs_id[i].second;
+            }
+        }
+
+        // if the probability sum of all timestamp tokens is higher than the max probability of the text tokens - sample a
+        // timestamp token
+        if (sum_ts > max_tx) {
+            // ref: https://github.com/openai/whisper/blob/0b1ba3d46ebf7fe6f953acfd8cad62a4f851b49f/whisper/decoding.py#L430-L438
+            for (int i = 0; i < vocab_.token_beg; i++) {
+                probs_id[i].first = -__INT_MAX__;
+            }
+        }
+
+        result.pt = max_ts/(sum_ts + 1e-10);
+        result.ptsum = sum_ts;
+    }
+
+    // find the top K tokens
+    const int top_k = 4;
+
+    std::partial_sort(
+            probs_id.begin(),
+            probs_id.begin() + top_k, probs_id.end(),
+            [](const std::pair<double, int64_t> & a, const std::pair<double, int64_t> & b) {
+        return a.first > b.first;
+    });
+
+    probs_id.resize(top_k);
+
+    int res = 0;
+    while ((probs_id[res].second == vocab_.token_sot ||
+            probs_id[res].second == vocab_.token_solm ||
+            probs_id[res].second == vocab_.token_beg) &&
+            res < (int) probs_id.size() - 1) {
+        res++;
+    }
+
+    result.id = probs_id[res].second;
+    result.p  = probs_id[res].first;
+
+    return result;
+}
+
+whisperTokenData
+ModelProcessor::getToken(std::vector<float>& logits)
+{
+    std::vector<Ort::Value> logSoftMaxInputs;
+    logSoftMaxInputs.push_back(Ort::Value::CreateTensor<float>(allocatorInfo_,
+                                                            logits.data(),
+                                                            logits.size(),
+                                                            logitsShape_.data(),
+                                                            logitsShape_.size()));
+
+    auto softmaxOutputs = logSoftMaxSession_->Run(Ort::RunOptions {nullptr},
+                                                logSoftMaxInputNames.data(),
+                                                logSoftMaxInputs.data(),
+                                                logSoftMaxInputNames.size(),
+                                                logSoftMaxOutputNames.data(),
+                                                logSoftMaxOutputNames.size());
+
+    float* probs = softmaxOutputs[1].GetTensorMutableData<float>();
+    return whisper_sample_best(probs);
+}
+
+std::string
+ModelProcessor::getText()
+{
+    std::ostringstream oss;
+    for (auto token : tokensOutput_) {
+        if (token < vocab_.token_eot)
+           oss << vocab_.id_to_token[token];
+    }
+
+    tokensOutput_.clear();
+    return oss.str();
+}
+
+void
+ModelProcessor::feedInput(std::vector<float>& melInput)
+{
+    try {
+        Ort::Value melInputTensor = Ort::Value::CreateTensor<float>(allocatorInfo_,
+                                                                    melInput.data(),
+                                                                    melInput.size(),
+                                                                    melInputShape_.data(),
+                                                                    melInputShape_.size());
+        audioFeaturesTensor_ = Ort::Value::CreateTensor<float>(allocatorInfo_,
+                                                               audioFeatures_.data(),
+                                                               audioFeatures_.size(),
+                                                               audioFeaturesShape_.data(),
+                                                               audioFeaturesShape_.size());
+        // Run the encoder graph
+        encoderSession_->Run(Ort::RunOptions {nullptr},
+                        encoderInputNames,
+                        &melInputTensor,
+                        1,
+                        encoderOutputNames,
+                        &audioFeaturesTensor_,
+                        1);
+    } catch(Ort::Exception e) {
+        Plog::log(Plog::LogPriority::ERR, TAG, e.what());
+        return;
+    } catch (...) {
+        return;
+    }
+
+    try {
+        std::vector<int64_t> currentTokens;
+        currentTokens.emplace_back(vocab_.token_sot);
+        std::vector<float> currentKVCache(12 * 1 * 1 * 512, 0.0f);
+        std::array<int64_t, 1> offsetShape {1};
+        std::array<int64_t, 2> tokenShape {1, 1};
+
+        for (auto i = 0; i < sampleLen; i++) {
+            int64_t offset = i;
+            std::array<int64_t, 4> kvCacheShape { 12, 1, (i + 1), 512 };
+
+            std::vector<int64_t> token = { currentTokens.back() };
+
+            // Run the decoder graph
+            std::vector<Ort::Value> inputsVector; // {audioFeaturesTensor_, tokensTensor_, kvCacheTensor_, offsetTensor_};
+            inputsVector.push_back(Ort::Value::CreateTensor<float>(allocatorInfo_,
+                                                                   audioFeatures_.data(),
+                                                                   audioFeatures_.size(),
+                                                                   audioFeaturesShape_.data(),
+                                                                   audioFeaturesShape_.size()));
+
+            inputsVector.emplace_back(Ort::Value::CreateTensor<int64_t>(allocatorInfo_,
+                                                                        token.data(),
+                                                                        token.size(),
+                                                                        tokenShape.data(),
+                                                                        tokenShape.size()));
+
+            inputsVector.emplace_back(Ort::Value::CreateTensor<float>(allocatorInfo_,
+                                                                      currentKVCache.data(),
+                                                                      currentKVCache.size(),
+                                                                      kvCacheShape.data(),
+                                                                      kvCacheShape.size()));
+
+            inputsVector.emplace_back(Ort::Value::CreateTensor<int64_t>(allocatorInfo_,
+                                                                        &offset,
+                                                                        1,
+                                                                        offsetShape.data(),
+                                                                        0));
+
+            auto outputs = decoderSession_->Run(Ort::RunOptions {nullptr},
+                                                decoderInputNames.data(),
+                                                inputsVector.data(),
+                                                decoderInputNames.size(),
+                                                decoderOutputNames.data(),
+                                                decoderOutputNames.size());
+
+            auto logitsTensorInfo = outputs[0].GetTensorTypeAndShapeInfo();
+            auto logitsData = outputs[0].GetTensorMutableData<float>();
+
+            {
+                std::vector<float>logits(logitsData, logitsData + logitsTensorInfo.GetElementCount());
+                auto tokenData = getToken(logits);
+                currentTokens.push_back(tokenData.id);
+            }
+
+            // Grab kvCache for next iteration
+            auto kvCacheTensorInfo = outputs[1].GetTensorTypeAndShapeInfo();
+            auto nextKVCacheData = outputs[1].GetTensorMutableData<float>();
+
+            std::vector<float> nextKVCache;
+            std::vector<float> zeros(512, 0.0f);
+            int delta = (i + 1) * 512;
+            for (int currentKVIdx = 0; currentKVIdx < 12; currentKVIdx++) {
+                nextKVCache.insert(nextKVCache.end(),
+                                   nextKVCacheData + (currentKVIdx * delta),
+                                   nextKVCacheData + ((currentKVIdx + 1) * delta));
+                nextKVCache.insert(nextKVCache.end(), zeros.begin(), zeros.end());
+            }
+            std::swap(currentKVCache, nextKVCache);
+
+            if (currentTokens.back() == vocab_.token_eot)
+                break;
+        }
+
+        std::swap(currentTokens, tokensOutput_);
+    } catch(Ort::Exception e) {
+        Plog::log(Plog::LogPriority::ERR, TAG, e.what());
+        return;
+    } catch (...) {
+        return;
+    }
+
+    modelInit_ = false;
+}
+} // namespace jami
diff --git a/WhisperTranscript/ModelProcessor.h b/WhisperTranscript/ModelProcessor.h
new file mode 100644
index 0000000..4a2ad17
--- /dev/null
+++ b/WhisperTranscript/ModelProcessor.h
@@ -0,0 +1,120 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ * USA.
+ */
+
+#pragma once
+
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include <onnxruntime_cxx_api.h>
+#ifdef __ANDROID__
+#include <nnapi_provider_factory.h>
+#endif
+
+#include <functional>
+
+#include "Preprocess.h"
+
+namespace jami {
+
+static const char* encoderInputNames[4] = {"mel"};
+static const char* encoderOutputNames[4] = {"903"};
+
+static const std::vector<const char*> decoderInputNames = {"audio_features", "tokens", "kv_cache", "offset"};
+static const std::vector<const char*> decoderOutputNames = {"logits", "output_kv_cache"};
+
+static const std::vector<const char *> logSoftMaxInputNames = {"logits"};
+static const std::vector<const char *> logSoftMaxOutputNames = {"token_ids", "probs"};
+
+typedef struct whisperTokenData {
+    int64_t id;  // token id
+    int64_t tid; // forced timestamp token id
+
+    float p;     // probability of the token
+    float pt;    // probability of the timestamp token
+    float ptsum; // sum of probabilities of all timestamp tokens
+
+    // token-level timestamp data
+    // do not use if you haven't computed token-level timestamps
+    int64_t t0; // start time of the token
+    int64_t t1; //   end time of the token
+
+    float vlen; // voice length of the token
+} whisperTokenData;
+
+class ModelProcessor
+{
+public:
+    ModelProcessor(const std::string& path, bool acc);
+    ~ModelProcessor();
+
+    void initModels(const std::string& encoderModelPath, const std::string& decoderModelPath, const std::string& logSoftMaxModelPath, bool activateAcc);
+    void endModels();
+
+    whisperTokenData whisper_sample_best(const float * probs);
+
+    /**
+     * @brief feedInput
+     * Takes a frame and feeds it to the model storage for predictions
+     * @param frame
+     */
+    void feedInput(std::vector<float>& input);
+
+    bool isAllocated() { return isAllocated_; }
+
+    std::string getText();
+
+private:
+    bool modelInit_ = true;
+
+    // Tokens
+    whisperVocab vocab_;
+
+    whisperTokenData getToken(std::vector<float>& logits);
+
+    // onnx related
+    Ort::MemoryInfo allocatorInfo_ = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
+    bool isAllocated_ {false};
+    Ort::Env env_ {ORT_LOGGING_LEVEL_WARNING, "whisperTest"};
+    Ort::Session* encoderSession_ {};
+    Ort::Session* decoderSession_ {};
+    Ort::Session* logSoftMaxSession_ {};
+    Ort::SessionOptions sessOpt_;
+
+    // Encoder tensors. 1 input and 1 output
+    std::vector<int64_t> melInputShape_ {1, 80, 3000}; // Input Data Type: 1 (float), Input Shape: [1, 80, 3000]
+    Ort::Value audioFeaturesTensor_ {nullptr};
+    std::vector<int64_t> audioFeaturesShape_ {1, 1500, 512}; // Output Data Type: 1 (float), Output Shape: [1, 1500, 512]
+    std::array<float, 1500 * 512> audioFeatures_ {};
+
+    std::vector<float> output_;
+
+    // Decoder tensors. 4 inputs and 2 outputs
+    std::vector<int64_t> tokensOutput_ { };
+
+    // LogProb check
+    std::array<int64_t, 3> logitsShape_ {1, 1, 51864};
+
+    int sampleLen = 50;
+
+};
+} // namespace jami
diff --git a/WhisperTranscript/PluginPreferenceHandler.cpp b/WhisperTranscript/PluginPreferenceHandler.cpp
new file mode 100644
index 0000000..202f70d
--- /dev/null
+++ b/WhisperTranscript/PluginPreferenceHandler.cpp
@@ -0,0 +1,109 @@
+/**
+ *  Copyright (C) 2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "PluginPreferenceHandler.h"
+
+#include "TranscriptMediaHandler.h"
+#include "pluglog.h"
+
+const char sep = separator();
+const std::string TAG = "TranscriptAcc";
+
+#define NAME "TranscriptAcc"
+
+namespace jami {
+
+PluginPreferenceHandler::PluginPreferenceHandler(
+    const JAMI_PluginAPI* api,
+    std::map<std::string, std::map<std::string, std::string>>&& preferences,
+    const std::string& dataPath)
+    : api_ {api}
+    , datapath_ {dataPath}
+{
+    preferences_ = preferences;
+    setId(datapath_);
+};
+
+std::map<std::string, std::string>
+PluginPreferenceHandler::getHandlerDetails()
+{
+    return {{"name", NAME}, {"iconPath", datapath_ + sep + "icon.svg"}, {"pluginId", id()}};
+}
+
+void
+PluginPreferenceHandler::setPreferenceAttribute(const std::string& accountId,
+                                             const std::string& key,
+                                             const std::string& value)
+{
+    if (accountId.empty()) {
+        for (auto& prefMap : preferences_) {
+            auto it = prefMap.second.find(key);
+            if (it != prefMap.second.end() && it->second != value) {
+                it->second = value;
+            }
+        }
+    } else {
+        auto accIt = preferences_.find("default");
+        accIt = preferences_.emplace(accountId, preferences_["default"]).first;
+        auto it = accIt->second.find(key);
+        if (it != accIt->second.end() && it->second != value) {
+            it->second = value;
+        }
+    }
+
+    tmh_->setParameters(accountId);
+}
+
+void
+PluginPreferenceHandler::resetPreferenceAttributes(const std::string& accountId)
+{
+    std::lock_guard<std::mutex> lk(mtx_);
+    if (accountId.empty()) {
+        preferences_.clear();
+        api_->invokeService(api_, "getPluginAccPreferences", &preferences_);
+    } else
+        preferences_[accountId] = preferences_["default"];
+    tmh_->setParameters(accountId);
+}
+
+bool
+PluginPreferenceHandler::preferenceMapHasKey(const std::string& key)
+{
+    return (key == "background" || key == "position" || key == "fontsize");
+}
+
+std::map<std::string, std::string>
+PluginPreferenceHandler::getPreferences(const std::string& accountId)
+{
+    std::lock_guard<std::mutex> lk(mtx_);
+    return preferences_.emplace(accountId, preferences_["default"]).first->second;
+}
+
+PluginPreferenceHandler::~PluginPreferenceHandler()
+{
+    preferences_.clear();
+}
+
+void
+PluginPreferenceHandler::setTranscriptHandler(TranscriptMediaHandler* handler)
+{
+    tmh_ = handler;
+}
+} // namespace jami
diff --git a/WhisperTranscript/PluginPreferenceHandler.h b/WhisperTranscript/PluginPreferenceHandler.h
new file mode 100644
index 0000000..a45e12b
--- /dev/null
+++ b/WhisperTranscript/PluginPreferenceHandler.h
@@ -0,0 +1,60 @@
+/**
+ *  Copyright (C) 2021 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "plugin/jamiplugin.h"
+#include "plugin/preferencehandler.h"
+
+#include <string>
+#include <map>
+#include <memory>
+#include <set>
+#include <mutex>
+
+namespace jami {
+class TranscriptMediaHandler;
+
+class PluginPreferenceHandler : public jami::PreferenceHandler
+{
+public:
+    PluginPreferenceHandler(const JAMI_PluginAPI* api,
+                            std::map<std::string, std::map<std::string, std::string>>&& preferences,
+                            const std::string& dataPath);
+    ~PluginPreferenceHandler();
+
+    std::map<std::string, std::string> getHandlerDetails() override;
+    bool preferenceMapHasKey(const std::string& key) override;
+    void setPreferenceAttribute(const std::string& accountId,
+                                const std::string& key,
+                                const std::string& value) override;
+    void resetPreferenceAttributes(const std::string& accountId) override;
+
+    std::map<std::string, std::string> getPreferences(const std::string& accountId);
+    void setTranscriptHandler(TranscriptMediaHandler* handler);
+
+private:
+    const JAMI_PluginAPI* api_;
+    TranscriptMediaHandler* tmh_;
+    const std::string datapath_;
+    std::map<std::string, std::map<std::string, std::string>> preferences_;
+    std::mutex mtx_;
+};
+} // namespace jami
diff --git a/WhisperTranscript/Preprocess.cpp b/WhisperTranscript/Preprocess.cpp
new file mode 100644
index 0000000..706c44f
--- /dev/null
+++ b/WhisperTranscript/Preprocess.cpp
@@ -0,0 +1,310 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "Preprocess.h"
+
+#ifdef WIN32
+#define _USE_MATH_DEFINES
+#endif
+
+#include <thread>
+#include <math.h>
+#include <fstream>
+#include <iostream>
+
+// ref: https://github.com/openai/whisper/blob/main/whisper/audio.py#L92-L124
+bool logMelSpectrogram(
+    const float *samples,
+    const int n_samples,
+    const int n_threads,
+    const whisperFilters &filters,
+    whisperMel &mel) {
+
+    // const int sample_rate = WHISPER_SAMPLE_RATE;
+    const int fft_size = WHISPER_N_FFT;
+    const int fft_step = WHISPER_HOP_LENGTH;
+    const int n_mel = WHISPER_N_MEL;
+
+    // Hanning window
+    std::vector<float> hann;
+    hann.resize(fft_size);
+    for (int i = 0; i < fft_size; i++) {
+        hann[i] = 0.5*(1.0 - cos((2.0*M_PI*i)/(fft_size)));
+    }
+
+    mel.n_mel = n_mel;
+    mel.n_len = (n_samples)/fft_step;
+    mel.data.resize(mel.n_mel*mel.n_len);
+
+    const int n_fft = 1 + fft_size/2;
+
+    std::vector<std::thread> workers(n_threads);
+    for (int iw = 0; iw < n_threads; ++iw) {
+        workers[iw] = std::thread([&](int ith) {
+            std::vector<float> fft_in;
+            fft_in.resize(fft_size);
+            for (int i = 0; i < fft_size; i++) {
+                fft_in[i] = 0.0;
+            }
+
+            std::vector<float> fft_out;
+            fft_out.resize(2*fft_size);
+
+            for (int i = ith; i < mel.n_len; i += n_threads) {
+                const int offset = i*fft_step;
+
+                // apply Hanning window
+                for (int j = 0; j < fft_size; j++) {
+                    if (offset + j < n_samples) {
+                        fft_in[j] = hann[j]*samples[offset + j];
+                    } else {
+                        fft_in[j] = 0.0;
+                    }
+                }
+
+                // FFT -> mag^2
+                fft(fft_in, fft_out);
+
+                for (int j = 0; j < fft_size; j++) {
+                    fft_out[j] = (fft_out[2*j + 0]*fft_out[2*j + 0] + fft_out[2*j + 1]*fft_out[2*j + 1]);
+                }
+                for (int j = 1; j < fft_size/2; j++) {
+                    fft_out[j] += fft_out[fft_size - j];
+                }
+
+                // mel spectrogram
+                for (int j = 0; j < mel.n_mel; j++) {
+                    double sum = 0.0;
+
+                    for (int k = 0; k < n_fft; k++) {
+                        sum += fft_out[k]*filters.data[j*n_fft + k];
+                    }
+                    if (sum < 1e-10) {
+                        sum = 1e-10;
+                    }
+
+                    sum = log10(sum);
+
+                    mel.data[j*mel.n_len + i] = sum;
+                }
+            }
+        }, iw);
+    }
+
+    for (int iw = 0; iw < n_threads; ++iw) {
+        workers[iw].join();
+    }
+
+    // clamping and normalization
+    double mmax = -1e20;
+    for (int i = 0; i < mel.n_mel*mel.n_len; i++) {
+        if (mel.data[i] > mmax) {
+            mmax = mel.data[i];
+        }
+    }
+
+    mmax -= 8.0;
+
+    for (int i = 0; i < mel.n_mel*mel.n_len; i++) {
+        if (mel.data[i] < mmax) {
+            mel.data[i] = mmax;
+        }
+
+        mel.data[i] = (mel.data[i] + 4.0)/4.0;
+    }
+
+    return true;
+}
+
+// Cooley-Tukey FFT
+// poor man's implementation - use something better
+// input is real-valued
+// output is complex-valued
+void fft(const std::vector<float> & in, std::vector<float> & out) {
+    out.resize(in.size()*2);
+
+    int N = in.size();
+
+    if (N == 1) {
+        out[0] = in[0];
+        out[1] = 0;
+        return;
+    }
+
+    if (N%2 == 1) {
+        dft(in, out);
+        return;
+    }
+
+    std::vector<float> even;
+    std::vector<float> odd;
+
+    for (int i = 0; i < N; i++) {
+        if (i % 2 == 0) {
+            even.push_back(in[i]);
+        } else {
+            odd.push_back(in[i]);
+        }
+    }
+
+    std::vector<float> even_fft;
+    std::vector<float> odd_fft;
+
+    fft(even, even_fft);
+    fft(odd, odd_fft);
+
+    for (int k = 0; k < N/2; k++) {
+        float theta = 2*M_PI*k/N;
+
+        float re = cos(theta);
+        float im = -sin(theta);
+
+        float re_odd = odd_fft[2*k + 0];
+        float im_odd = odd_fft[2*k + 1];
+
+        out[2*k + 0] = even_fft[2*k + 0] + re*re_odd - im*im_odd;
+        out[2*k + 1] = even_fft[2*k + 1] + re*im_odd + im*re_odd;
+
+        out[2*(k + N/2) + 0] = even_fft[2*k + 0] - re*re_odd + im*im_odd;
+        out[2*(k + N/2) + 1] = even_fft[2*k + 1] - re*im_odd - im*re_odd;
+    }
+}
+
+// naive Discrete Fourier Transform
+// input is real-valued
+// output is complex-valued
+void dft(const std::vector<float> & in, std::vector<float> & out) {
+    int N = in.size();
+
+    out.resize(N*2);
+
+    for (int k = 0; k < N; k++) {
+        float re = 0;
+        float im = 0;
+
+        for (int n = 0; n < N; n++) {
+            float angle = 2*M_PI*k*n/N;
+            re += in[n]*cos(angle);
+            im -= in[n]*sin(angle);
+        }
+
+        out[k*2 + 0] = re;
+        out[k*2 + 1] = im;
+    }
+}
+
+
+void loadMelFilters(const std::string& fileName, whisperFilters& filters) {
+    auto fin = std::ifstream(fileName, std::ios::binary);
+    if (!fin) {
+        fprintf(stderr, "%s: failed to open '%s'\n", __func__, fileName.c_str());
+        return;
+    }
+
+    fin.read((char *) &filters.n_mel, sizeof(filters.n_mel));
+    fin.read((char *) &filters.n_fft, sizeof(filters.n_fft));
+
+    filters.data.resize(filters.n_mel * filters.n_fft);
+    fin.read((char *) filters.data.data(), filters.data.size() * sizeof(float));
+}
+
+void loadTokens(const std::string& fileName, whisperVocab& vocab) {
+    auto fin = std::ifstream(fileName, std::ios::binary);
+    if (!fin) {
+        fprintf(stderr, "%s: failed to open '%s'\n", __func__, fileName.c_str());
+        return;
+    }
+
+    int32_t modelNVocab = 0;
+    fin.read((char *) &modelNVocab, sizeof(modelNVocab));
+
+    int32_t tokensNVocab = 0;
+    fin.read((char *) &tokensNVocab, sizeof(tokensNVocab));
+
+    std::string word;
+    for (int i = 0; i < tokensNVocab; i++) {
+        uint32_t len;
+        fin.read((char *) &len, sizeof(len));
+
+        word.resize(len);
+        fin.read((char *) word.data(), len);
+
+        vocab.token_to_id[word] = i;
+        vocab.id_to_token[i] = word;
+    }
+
+    vocab.n_vocab = modelNVocab;
+    if (vocab.is_multilingual()) {
+        vocab.token_eot++;
+        vocab.token_sot++;
+        vocab.token_prev++;
+        vocab.token_solm++;
+        vocab.token_not++;
+        vocab.token_beg++;
+    }
+
+    if (tokensNVocab < modelNVocab) {
+        fprintf(stderr, "%s: adding %d extra tokens\n", __func__, modelNVocab - tokensNVocab);
+        for (int i = tokensNVocab; i < modelNVocab; i++) {
+            if (i > vocab.token_beg) {
+                word = "[_TT_" + std::to_string(i - vocab.token_beg) + "]";
+            } else if (i == vocab.token_eot) {
+                word = "[_EOT_]";
+            } else if (i == vocab.token_sot) {
+                word = "[_SOT_]";
+            } else if (i == vocab.token_prev) {
+                word = "[_PREV_]";
+            } else if (i == vocab.token_not) {
+                word = "[_NOT_]";
+            } else if (i == vocab.token_beg) {
+                word = "[_BEG_]";
+            } else {
+                word = "[_extra_token_" + std::to_string(i) + "]";
+            }
+            vocab.token_to_id[word] = i;
+            vocab.id_to_token[i] = word;
+        }
+    }
+}
+
+void
+inputPadTrim(whisperMel &mel)
+{
+    if (mel.n_len == ENCODER_INPUT_LEN)
+        return;
+    std::vector<float> data;
+    std::vector<float> partialData;
+    int seek = 0;
+    auto dataLimit = std::min(mel.n_len, ENCODER_INPUT_LEN);
+    for (auto j = 0; j < mel.n_mel; j++) {
+        seek = j * mel.n_len;
+        for (auto i = seek; i < (j + 1) * dataLimit; i++) {
+            partialData.emplace_back(mel.data[i]);
+        }
+        if (mel.n_len < ENCODER_INPUT_LEN) {
+            for (auto i = mel.n_len; i < ENCODER_INPUT_LEN; i++) {
+                partialData.emplace_back(0.0f);
+            }
+        }
+        data.insert(data.end(), partialData.begin(), partialData.end());
+        partialData.clear();
+    }
+    std::swap(mel.data, data);
+}
diff --git a/WhisperTranscript/Preprocess.h b/WhisperTranscript/Preprocess.h
new file mode 100644
index 0000000..455a96e
--- /dev/null
+++ b/WhisperTranscript/Preprocess.h
@@ -0,0 +1,91 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include <vector>
+#include <cstdint>
+#include <string>
+#include <map>
+
+
+// Those are model defined
+// Check paper page 3 (https://cdn.openai.com/papers/whisper.pdf)
+#define WHISPER_SAMPLE_RATE 16000
+#define WHISPER_N_FFT       400
+#define WHISPER_N_MEL       80
+#define WHISPER_HOP_LENGTH  160
+#define WHISPER_CHUNK_SIZE  30
+#define ENCODER_INPUT_LEN   3000
+
+struct whisperMel {
+    int n_len;
+    int n_mel;
+
+    std::vector<float> data;
+};
+
+struct whisperFilters {
+    int32_t n_mel;
+    int32_t n_fft;
+
+    std::vector<float> data;
+};
+
+struct whisperVocab {
+    int n_vocab = 51864;
+
+    std::map<std::string, int32_t> token_to_id;
+    std::map<int32_t, std::string> id_to_token;
+
+    int32_t token_eot  = 50256;
+    int32_t token_sot  = 50257;
+    int32_t token_prev = 50360;
+    int32_t token_solm = 50361; // no speech
+    int32_t token_not  = 50362; // no timestamps
+    int32_t token_beg  = 50363; // timestamp begin
+
+    // available tasks
+    static const int32_t token_translate  = 50358;
+    static const int32_t token_transcribe = 50359;
+
+    bool is_multilingual() const {
+        return n_vocab == 51865;
+    }
+
+    std::vector<std::vector<int>> filters;
+};
+
+bool logMelSpectrogram(
+    const float * samples,
+    const int n_samples,
+    const int n_threads,
+    const whisperFilters & filters,
+    whisperMel &mel);
+
+void fft(const std::vector<float> & in, std::vector<float> & out);
+
+void dft(const std::vector<float> & in, std::vector<float> & out);
+
+void loadMelFilters(const std::string& fileName, whisperFilters& filters);
+
+void loadTokens(const std::string& fileName, whisperVocab& vocab);
+
+void inputPadTrim(whisperMel &mel);
diff --git a/WhisperTranscript/TranscriptAudioSubscriber.cpp b/WhisperTranscript/TranscriptAudioSubscriber.cpp
new file mode 100644
index 0000000..d341671
--- /dev/null
+++ b/WhisperTranscript/TranscriptAudioSubscriber.cpp
@@ -0,0 +1,168 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "TranscriptAudioSubscriber.h"
+
+#include <pluglog.h>
+#include <frameUtils.h>
+#include <bitset>
+#include <iostream>
+
+const std::string TAG = "Transcript";
+const char sep = separator();
+
+namespace jami {
+
+TranscriptAudioSubscriber::TranscriptAudioSubscriber(const std::string& dataPath, TranscriptVideoSubscriber* videoSubscriber, bool acc)
+    : path_ {dataPath}
+    , modelProcessor_ {dataPath, acc}
+    , mVS_ {videoSubscriber}
+{
+    loadMelFilters(path_ + "/assets/mel_filters.bin", modelFilters_);
+
+    /**
+     * Waits for audio samples and then process them
+     **/
+    processFrameThread = std::thread([this] {
+        while (running) {
+            std::unique_lock<std::mutex> l(inputLock);
+            inputCv.wait(l, [this] { return not running or newFrame; });
+            if (not running) {
+                break;
+            }
+
+            logMelSpectrogram(currentModelInput_.data(), currentModelInput_.size(), 8, modelFilters_, melSpectrogram_);
+            inputPadTrim(melSpectrogram_);
+            newFrame = false;
+
+            currentModelInput_.clear();
+#ifndef __DEBUG__
+            /** Unlock the mutex, this way we let the other thread
+             *  copy new data while we are processing the old one
+             **/
+            l.unlock();
+#endif
+            modelProcessor_.feedInput(melSpectrogram_.data);
+            auto text = modelProcessor_.getText();
+            mVS_->setText(text);
+        }
+    });
+}
+
+TranscriptAudioSubscriber::~TranscriptAudioSubscriber()
+{
+    modelProcessor_.endModels();
+    formatFilter_.clean();
+    stop();
+    processFrameThread.join();
+    Plog::log(Plog::LogPriority::INFO, TAG, "~TranscriptMediaProcessor");
+}
+
+void
+TranscriptAudioSubscriber::stop()
+{
+    running = false;
+    inputCv.notify_all();
+}
+
+void
+TranscriptAudioSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pluginFrame)
+{
+    if (!pluginFrame || modelFilters_.data.empty())
+        return;
+
+    if (firstRun) {
+        modelProcessor_.getText();
+        count_ = 0;
+        pastModelInput_.clear();
+        currentModelInput_.clear();
+        futureModelInput_.clear();
+        formatFilter_.clean();
+        AudioFormat afmt = AudioFormat(pluginFrame->sample_rate,
+                                        pluginFrame->channels,
+                                        static_cast<AVSampleFormat>(pluginFrame->format));
+        MediaStream ms = MediaStream("input", afmt);
+        formatFilter_.initialize(filterDescription_, {ms});
+        firstRun = false;
+    }
+
+    if (!formatFilter_.initialized_)
+        return;
+
+    if (formatFilter_.feedInput(pluginFrame, "input") == 0) {
+        uniqueFramePtr filteredFrame = {formatFilter_.readOutput(), frameFree};
+        if (filteredFrame) {
+            for (size_t i = 0; i < filteredFrame->buf[0]->size; i += 2) {
+                std::lock_guard<std::mutex> l(inputLock);
+                int16_t rawValue = (filteredFrame->buf[0]->data[i+1] << 8) | filteredFrame->buf[0]->data[i];
+
+                // If not a positive value, perform the 2's complement math on the value
+                if ((rawValue & 0x8000) != 0) {
+                    rawValue = (~(rawValue - 0x0001)) * -1;
+                }
+                futureModelInput_.emplace_back(float(rawValue)/32768.0f);
+                if (count_++ > WHISPER_STREAM_SAMPLES_CHUNK_STEP)
+                    overlapInput_.emplace_back(float(rawValue)/32768.0f);
+                count_++;
+
+                // Trigger transcription when we have enough samples
+                if (futureModelInput_.size() == WHISPER_STREAM_SAMPLES_CHUNK && !newFrame) {
+                    pastModelInput_.clear();
+                    std::swap(pastModelInput_, currentModelInput_);
+                    std::swap(currentModelInput_, futureModelInput_);
+                    std::swap(futureModelInput_, overlapInput_);
+                    count_ = 0;
+                    overlapInput_.clear();
+                    newFrame = true;
+                    inputCv.notify_all();
+                }
+            }
+        }
+    }
+    // audio returns as is
+}
+
+void
+TranscriptAudioSubscriber::attached(jami::Observable<AVFrame*>* observable)
+{
+    Plog::log(Plog::LogPriority::INFO, TAG, "::Attached ! ");
+    observable_ = observable;
+}
+
+void
+TranscriptAudioSubscriber::detached(jami::Observable<AVFrame*>*)
+{
+    modelProcessor_.getText();
+    firstRun = true;
+    observable_ = nullptr;
+    Plog::log(Plog::LogPriority::INFO, TAG, "::Detached()");
+}
+
+void
+TranscriptAudioSubscriber::detach()
+{
+    if (observable_) {
+        firstRun = true;
+        std::ostringstream oss;
+        Plog::log(Plog::LogPriority::INFO, TAG, "::Calling detach()");
+        observable_->detach(this);
+    }
+}
+} // namespace jami
diff --git a/WhisperTranscript/TranscriptAudioSubscriber.h b/WhisperTranscript/TranscriptAudioSubscriber.h
new file mode 100644
index 0000000..b9b717e
--- /dev/null
+++ b/WhisperTranscript/TranscriptAudioSubscriber.h
@@ -0,0 +1,93 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+extern "C" {
+#include <libavutil/frame.h>
+}
+#include <observer.h>
+
+#include <frameFilter.h>
+
+#include "Preprocess.h"
+#include "ModelProcessor.h"
+#include "TranscriptVideoSubscriber.h"
+
+#include <thread>
+#include <condition_variable>
+
+namespace jami {
+
+#define WHISPER_STREAM_SAMPLES_CHUNK 16000 * 4 // 16 KHz * 4 seconds
+#define WHISPER_STREAM_SAMPLES_CHUNK_STEP 16000 * 3 // 16KHz * 3 second
+
+class TranscriptAudioSubscriber : public Observer<AVFrame*>
+{
+public:
+    TranscriptAudioSubscriber(const std::string& dataPath, TranscriptVideoSubscriber* videoSubscriber, bool acc = false);
+    ~TranscriptAudioSubscriber();
+
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
+
+    void detach();
+
+private:
+    // Mel spectrogram filters
+    whisperFilters modelFilters_;
+    whisperMel melSpectrogram_;
+
+    // Observer pattern
+    Observable<AVFrame*>* observable_{};
+
+    // Filter for audio formatting
+    const std::string filterDescription_ = "[input]aresample=16000,aformat=sample_fmts=s16:channel_layouts=mono";
+    FrameFilter formatFilter_;
+    std::vector<float> currentModelInput_{};
+    std::vector<float> futureModelInput_{};
+    std::vector<float> pastModelInput_{};
+    std::vector<float> overlapInput_{};
+
+    // Data
+    std::string path_;
+
+    // Status variables of the processing
+    bool firstRun {true};
+    bool running {true};
+    bool newFrame {false};
+
+    // Stream count
+    int count_;
+
+    // Model
+    ModelProcessor modelProcessor_;
+
+    // Threading
+    std::thread processFrameThread;
+    std::mutex inputLock;
+    std::condition_variable inputCv;
+    void stop();
+
+    // Video processor
+    TranscriptVideoSubscriber* mVS_{};
+};
+} // namespace jami
diff --git a/WhisperTranscript/TranscriptMediaHandler.cpp b/WhisperTranscript/TranscriptMediaHandler.cpp
new file mode 100644
index 0000000..3e30733
--- /dev/null
+++ b/WhisperTranscript/TranscriptMediaHandler.cpp
@@ -0,0 +1,133 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "TranscriptMediaHandler.h"
+
+#include "pluglog.h"
+#include <string_view>
+
+const char sep = separator();
+const std::string TAG = "Transcript";
+
+#define NAME "Transcript"
+
+namespace jami {
+
+TranscriptMediaHandler::TranscriptMediaHandler(std::string&& datapath, PluginPreferenceHandler* prefHandler)
+    : datapath_ {datapath}
+{
+    aph_ = prefHandler;
+    setId(datapath_);
+    videoSubscriber_ = std::make_shared<TranscriptVideoSubscriber>(datapath_);
+    audioSubscriber_ = std::make_shared<TranscriptAudioSubscriber>(datapath_, videoSubscriber_.get());
+    setParameters("default");
+#ifdef __DEBUG__
+    auto preferences = aph_->getPreferences("default");
+    auto it = preferences.find("subtitle");
+    if (it != preferences.end())
+        videoSubscriber_->setText(it->second);
+#endif
+}
+
+void
+TranscriptMediaHandler::notifyAVFrameSubject(const StreamData& data, jami::avSubjectPtr subject)
+{
+    std::ostringstream oss;
+    std::string_view direction = data.direction ? "Receive" : "Preview";
+    oss << "NEW SUBJECT: [" << data.id << "," << direction << "]" << std::endl;
+
+    accountId_ = data.source;
+    auto preferences = aph_->getPreferences(accountId_);
+
+    bool preferredStreamDirection = false; // false for output; true for input
+    auto it = preferences.find("avstream");
+    if (it != preferences.end()) {
+        preferredStreamDirection = it->second == "in";
+    }
+
+    oss << "preferredStreamDirection " << preferredStreamDirection << std::endl;
+    if (data.type == StreamType::audio && !data.direction
+        && data.direction == preferredStreamDirection) {
+        subject->attach(audioSubscriber_.get()); // your audio
+        oss << "got my sent audio attached" << std::endl;
+        attached_[0] = true ;
+    } else if (data.type == StreamType::audio && data.direction
+               && data.direction == preferredStreamDirection) {
+        subject->attach(audioSubscriber_.get()); // the audio you receive from others on the call
+        oss << "got received audio attached" << std::endl;
+        attached_[0] = true;
+    }
+
+    if (data.type == StreamType::video && !data.direction
+        && data.direction == preferredStreamDirection) {
+        subject->attach(videoSubscriber_.get()); // your video
+        oss << "got my sent video attached" << std::endl;
+        attached_[1] = true;
+    } else if (data.type == StreamType::video && data.direction
+               && data.direction == preferredStreamDirection) {
+        subject->attach(videoSubscriber_.get()); // the video you receive from others on the call
+        oss << "got received video attached" << std::endl;
+        attached_[1] = true;
+    }
+
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+TranscriptMediaHandler::setParameters(const std::string& accountId)
+{
+    if (!accountId.empty() && accountId != accountId_)
+        return;
+    auto preferences = aph_->getPreferences(accountId_);
+    try {
+        videoSubscriber_->setParameter(preferences["fontsize"], Parameter::FONTSIZE);
+        videoSubscriber_->setParameter(preferences["background"], Parameter::BACKGROUND);
+        videoSubscriber_->setParameter(preferences["position"], Parameter::POSITION);
+    } catch (std::exception& e) {
+        Plog::log(Plog::LogPriority::ERR, TAG, e.what());
+    }
+}
+
+std::map<std::string, std::string>
+TranscriptMediaHandler::getCallMediaHandlerDetails()
+{
+    return {{"name", NAME},
+            {"iconPath", datapath_ + sep + "icon.svg"},
+            {"pluginId", id()},
+            {"attached", attached_[0] && attached_[1] ? "1" : "0"},
+            {"dataType", "1"}};
+}
+
+void
+TranscriptMediaHandler::detach()
+{
+    attached_ = {false, false};
+    videoSubscriber_->detach();
+    audioSubscriber_->detach();
+}
+
+TranscriptMediaHandler::~TranscriptMediaHandler()
+{
+    std::ostringstream oss;
+    oss << " ~TranscriptMediaHandler from WhisperTranscript Plugin" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+    detach();
+}
+} // namespace jami
diff --git a/WhisperTranscript/TranscriptMediaHandler.h b/WhisperTranscript/TranscriptMediaHandler.h
new file mode 100644
index 0000000..9191dff
--- /dev/null
+++ b/WhisperTranscript/TranscriptMediaHandler.h
@@ -0,0 +1,57 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "TranscriptAudioSubscriber.h"
+#include "TranscriptVideoSubscriber.h"
+
+#include "PluginPreferenceHandler.h"
+
+#include "plugin/jamiplugin.h"
+#include "plugin/mediahandler.h"
+
+namespace jami {
+
+class TranscriptMediaHandler : public CallMediaHandler
+{
+public:
+    TranscriptMediaHandler(std::string&& dataPath, PluginPreferenceHandler* prefHandler);
+    ~TranscriptMediaHandler();
+
+    virtual void notifyAVFrameSubject(const StreamData& data, avSubjectPtr subject) override;
+    virtual std::map<std::string, std::string> getCallMediaHandlerDetails() override;
+
+    virtual void detach() override;
+    virtual void setPreferenceAttribute(const std::string& key, const std::string& value) override {}
+    virtual bool preferenceMapHasKey(const std::string& key) override { return false; }
+
+    void setParameters(const std::string& accountId);
+
+    std::shared_ptr<TranscriptAudioSubscriber> audioSubscriber_;
+    std::shared_ptr<TranscriptVideoSubscriber> videoSubscriber_;
+
+private:
+    std::vector<bool> attached_ = {false, false};
+    std::string accountId_ {"default"};
+    const std::string datapath_;
+    PluginPreferenceHandler* aph_;
+};
+} // namespace jami
diff --git a/WhisperTranscript/TranscriptVideoSubscriber.cpp b/WhisperTranscript/TranscriptVideoSubscriber.cpp
new file mode 100644
index 0000000..d17bc2b
--- /dev/null
+++ b/WhisperTranscript/TranscriptVideoSubscriber.cpp
@@ -0,0 +1,224 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "TranscriptVideoSubscriber.h"
+
+extern "C" {
+#include <libavutil/display.h>
+}
+
+#include <pluglog.h>
+#include <mediaStream.h>
+#include <frameScaler.h>
+#include <accel.h>
+#include <common.h>
+#include <frameUtils.h>
+
+#include <bitset>
+
+const std::string TAG = "Transcript";
+const char sep = separator();
+
+namespace jami {
+
+TranscriptVideoSubscriber::TranscriptVideoSubscriber(const std::string& dataPath, bool acc)
+    : path_ {dataPath}
+{
+    fontFile_ = string_utils::ffmpegFormatString(dataPath + sep + "Muli-Light.ttf");
+}
+
+TranscriptVideoSubscriber::~TranscriptVideoSubscriber()
+{
+    filter_.clean();
+    Plog::log(Plog::LogPriority::INFO, TAG, "~TranscriptMediaProcessor");
+}
+
+void
+TranscriptVideoSubscriber::setText(const std::string& text)
+{
+    subtitle_ = string_utils::ffmpegScapeString(text);
+#ifdef __DEBUG__
+    Plog::log(Plog::LogPriority::INFO, TAG, subtitle_);
+#endif
+    firstRun = true;
+}
+
+void
+TranscriptVideoSubscriber::setParameter(std::string& parameter, Parameter type)
+{
+    switch (type) {
+    case (Parameter::FONTSIZE):
+        fontSize_ = parameter;
+        break;
+    case (Parameter::BACKGROUND):
+        background_ = parameter;
+        if (background_.find("black") == std::string::npos) {
+            fontColor_ = "black";
+            fontBackground_ = "white@0.5";
+        } else {
+            fontColor_ = "white";
+            fontBackground_ = "black@0.5";
+        }
+        break;
+    case (Parameter::POSITION):
+        position_ = parameter;
+        break;
+    default:
+        return;
+    }
+
+    firstRun = true;
+}
+
+void
+TranscriptVideoSubscriber::setFilterDescription()
+{
+    if (pluginFrameSize_.first == 0 || pluginFrameSize_.second == 0)
+        return;
+
+    // 1, 2, 3, and 4 are cartesian positions
+    int margin = 10;
+    if (position_ == "1") {
+        points_[1] = {pluginFrameSize_.first - margin, margin};
+    } else if (position_ == "2") {
+        points_[1] = {margin, margin};
+    } else if (position_ == "3") {
+        points_[1] = {margin, pluginFrameSize_.second - margin};
+    } else if (position_ == "4") {
+        points_[1] = {pluginFrameSize_.first - margin, pluginFrameSize_.second - margin};
+    }
+
+    std::string rotateSides = "";
+
+    if (std::abs(angle_) == 90)
+        rotateSides = ":out_w=ih:out_h=iw";
+
+    auto baseInfosDescription = "[input]rotate=" + rotation[angle_] + rotateSides
+                                + ",drawtext=fontcolor=" + fontColor_
+                                + ":fontsize=" + fontSize_
+                                + ":fontfile=\\'" + fontFile_
+                                + "\\':expansion=none:text='" + subtitle_
+                                + "':box=1:boxcolor=" + fontBackground_ + ":boxborderw=5:x=";
+    if (position_ == "1")
+        filterDescription_ = baseInfosDescription + std::to_string(points_[1].first)
+                            + "-text_w:y=" + std::to_string(points_[1].second);
+    else if (position_ == "2")
+        filterDescription_ = baseInfosDescription + std::to_string(points_[1].first)
+                            + ":y=" + std::to_string(points_[1].second);
+    else if (position_ == "3")
+        filterDescription_ = baseInfosDescription + std::to_string(points_[1].first)
+                            + ":y=" + std::to_string(points_[1].second) + "-text_h";
+    else if (position_ == "4")
+        filterDescription_ = baseInfosDescription + std::to_string(points_[1].first)
+                            + "-text_w:y=" + std::to_string(points_[1].second) + "-text_h";
+    filterDescription_ += ",rotate=" + rotation[-angle_] + rotateSides + ",format=yuv420p";
+
+#ifdef __DEBUG__
+    Plog::log(Plog::LogPriority::INFO, TAG, filterDescription_);
+#endif
+}
+
+void
+TranscriptVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pluginFrame)
+{
+    if (!observable_ || !pluginFrame || subtitle_.empty())
+        return;
+
+    AVFrameSideData* side_data = av_frame_get_side_data(pluginFrame, AV_FRAME_DATA_DISPLAYMATRIX);
+    int newAngle {0};
+    if (side_data) {
+        auto matrix_rotation = reinterpret_cast<int32_t*>(side_data->data);
+        newAngle = static_cast<int>(av_display_rotation_get(matrix_rotation));
+    }
+    if (newAngle != angle_) {
+        angle_ = newAngle;
+        firstRun = true;
+    }
+
+    //======================================================================================
+    // GET RAW FRAME
+    uniqueFramePtr rgbFrame = {transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12), frameFree};
+    rgbFrame.reset(FrameScaler::convertFormat(rgbFrame.get(), AV_PIX_FMT_YUV420P));
+    if (!rgbFrame.get())
+        return;
+
+    if (sourceTimeBase_.num != pluginFrame->time_base.num || sourceTimeBase_.den != pluginFrame->time_base.den)
+        firstRun = true;
+
+    rgbFrame->pts = pluginFrame->pts;
+    rgbFrame->time_base = pluginFrame->time_base;
+    sourceTimeBase_ = pluginFrame->time_base;
+
+    if (firstRun) {
+        filter_.clean();
+        pluginFrameSize_ = {rgbFrame->width, rgbFrame->height};
+        if (std::abs(angle_) == 90)
+            pluginFrameSize_ = {rgbFrame->height, rgbFrame->width};
+        setFilterDescription();
+
+        rational<int> fr(sourceTimeBase_.den, sourceTimeBase_.num);
+        auto ms = MediaStream("input",
+                              rgbFrame->format,
+                              1 / fr,
+                              rgbFrame->width,
+                              rgbFrame->height,
+                              0,
+                              fr);
+        filter_.initialize(filterDescription_, {ms});
+        firstRun = false;
+    }
+
+    if (!filter_.initialized_)
+        return;
+
+    if (filter_.feedInput(rgbFrame.get(), "input") == 0) {
+        uniqueFramePtr filteredFrame = {filter_.readOutput(), frameFree};
+        if (filteredFrame) {
+            moveFrom(pluginFrame, filteredFrame.get());
+        }
+    }
+}
+
+void
+TranscriptVideoSubscriber::attached(jami::Observable<AVFrame*>* observable)
+{
+    Plog::log(Plog::LogPriority::INFO, TAG, "::Attached ! ");
+    observable_ = observable;
+}
+
+void
+TranscriptVideoSubscriber::detached(jami::Observable<AVFrame*>*)
+{
+    firstRun = true;
+    observable_ = nullptr;
+    Plog::log(Plog::LogPriority::INFO, TAG, "::Detached()");
+}
+
+void
+TranscriptVideoSubscriber::detach()
+{
+    if (observable_) {
+        firstRun = true;
+        std::ostringstream oss;
+        Plog::log(Plog::LogPriority::INFO, TAG, "::Calling detach()");
+        observable_->detach(this);
+    }
+}
+} // namespace jami
diff --git a/WhisperTranscript/TranscriptVideoSubscriber.h b/WhisperTranscript/TranscriptVideoSubscriber.h
new file mode 100644
index 0000000..4d9087c
--- /dev/null
+++ b/WhisperTranscript/TranscriptVideoSubscriber.h
@@ -0,0 +1,82 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+extern "C" {
+#include <libavutil/frame.h>
+}
+#include <observer.h>
+
+#include <frameFilter.h>
+
+namespace jami {
+
+enum Parameter {
+    POSITION,
+    BACKGROUND,
+    FONTSIZE,
+};
+
+class TranscriptVideoSubscriber : public Observer<AVFrame*>
+{
+public:
+    TranscriptVideoSubscriber(const std::string& dataPath, bool acc = false);
+    ~TranscriptVideoSubscriber();
+
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override;
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
+
+    void detach();
+
+    void setText(const std::string& text);
+    void setFilterDescription();
+
+    void setParameter(std::string& parameter, Parameter type);
+
+private:
+    // Observer pattern
+    Observable<AVFrame*>* observable_{};
+
+    // Filter for video formatting
+    std::string filterDescription_;
+    FrameFilter filter_;
+    std::string subtitle_ {"No subtitle fetched."};
+    std::string fontFile_;
+    AVRational sourceTimeBase_;
+    int angle_ {0};
+    std::map<int, std::string> rotation = {{-90, "-PI/2"},
+                                           {90, "PI/2"},
+                                           {-180, "-PI"},
+                                           {180, "PI"},
+                                           {0, "0"}};
+
+    // Data
+    std::string path_;
+
+    // Status variables of the processing
+    bool firstRun {true};
+
+    std::pair<int, int> pluginFrameSize_ {0, 0};
+    std::array<std::pair<int, int>, 2> points_;
+    std::string fontSize_, background_, fontColor_, fontBackground_, position_;
+};
+} // namespace jami
diff --git a/WhisperTranscript/build.sh b/WhisperTranscript/build.sh
new file mode 100755
index 0000000..8acf280
--- /dev/null
+++ b/WhisperTranscript/build.sh
@@ -0,0 +1,419 @@
+#! /bin/bash
+# Build the plugin for the project
+set -e
+export OSTYPE
+ARCH=$(uname -m)
+EXTRAPATH=''
+# Flags:
+
+# -p: number of processors to use.
+# -c: Runtime plugin cpu/gpu setting.
+# -t: target platform.
+# -d: debug program.
+
+if [ -z "${DAEMON}" ]; then
+    DAEMON="./../../daemon"
+    echo "DAEMON not provided, building with ${DAEMON}"
+fi
+if [ -z "${PROCESSOR}" ]; then
+    PROCESSOR="CPU"
+    echo "PROCESSOR not provided, building with ${PROCESSOR}"
+fi
+
+PLUGIN_NAME="WhisperTranscript"
+JPL_FILE_NAME="${PLUGIN_NAME}.jpl"
+SO_FILE_NAME="lib${PLUGIN_NAME}.so"
+DAEMON_SRC="${DAEMON}/src"
+CONTRIB_PATH="${DAEMON}/contrib"
+PLUGINS_LIB="../lib"
+LIBS_DIR="./../contrib/Libs"
+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"
+elif [ "${PROCESSOR}" = "NVIDIA" ]; then
+    ONNX_LIBS="nvidia-gpu"
+    CUBLASLT="-lcublasLt"
+fi
+
+while getopts t:c:p:d OPT; do
+  case "$OPT" in
+    d)
+      DEBUG=true
+      export __DEBUG__=true
+    ;;
+    t)
+      PLATFORM="${OPTARG}"
+    ;;
+    c)
+      PROCESSOR="${OPTARG}"
+    ;;
+    p)
+    ;;
+    \?)
+      exit 1
+    ;;
+  esac
+done
+
+cp -r ffmpeg ${CONTRIB_PATH}/src/
+cp -r ../contrib/rav1e ${CONTRIB_PATH}/src/
+
+if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
+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}
+
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+    ONNX_PATH=${EXTRALIBS_PATH}
+    if [ -z "${EXTRALIBS_PATH}" ]
+    then
+      ONNX_PATH="${CONTRIB_PATH}/${CONTRIB_PLATFORM}"
+    fi
+
+    if [ ${DEBUG} ]; then
+      OUTPUT="${PLUGIN_NAME}"
+      CLANG_OPTS="-g -fsanitize=address"
+      EXTRA_DEBUG_LIBRARIES="-lyaml-cpp -lvdpau -lX11 -lva-drm -lva-x11 -lrav1e"
+      EXTRA_DEFINES="-D__DEBUG__"
+    else
+      python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+      CLANG_OPTS="-O3 -shared"
+      OUTPUT="build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
+
+    # Compile
+    clang++ -std=c++17 -fPIC ${CLANG_OPTS} \
+    -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-parameter \
+    ${EXTRA_DEFINES} \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include" \
+    -I"${ONNX_PATH}/include/onnxruntime/session" \
+    -I"${ONNX_PATH}/include/onnxruntime/providers/cuda" \
+    -I"${PLUGINS_LIB}" \
+    ./../lib/common.cpp \
+    ./../lib/accel.cpp \
+    ./../lib/frameFilter.cpp \
+    ./../lib/frameUtils.cpp \
+    main.cpp \
+    TranscriptMediaHandler.cpp \
+    TranscriptAudioSubscriber.cpp \
+    TranscriptVideoSubscriber.cpp \
+    PluginPreferenceHandler.cpp \
+    Preprocess.cpp \
+    ModelProcessor.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/lib/" \
+    -L"${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}" \
+    -L"${CUDA_HOME}/lib64/" \
+    -l:libavfilter.a \
+    -l:libswscale.a \
+    -l:libswresample.a \
+    -l:libavformat.a \
+    -l:libavcodec.a \
+    -l:libavutil.a \
+    -lfreetype \
+    -lvpx \
+    -lx264 \
+    -lspeex \
+    -lopus \
+    -lz \
+    -lva \
+    ${CUBLASLT} -lonnxruntime \
+    ${EXTRA_DEBUG_LIBRARIES} \
+    -o "${OUTPUT}"
+
+    if [ ${DEBUG} ]; then
+      cp "./modelSRC/mModelEncoder.onnx" "./data/assets/mModelEncoder.onnx"
+      cp "./modelSRC/mModelDecoder.onnx" "./data/assets/mModelDecoder.onnx"
+      cp "./modelSRC/mLogSoftMax.onnx" "./data/assets/mLogSoftMax.onnx"
+      cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime.so" "libonnxruntime.so.1.12.0"
+    else
+      cp "./modelSRC/mModelEncoder.onnx" "./build-local/jpl/data/assets/mModelEncoder.onnx"
+      cp "./modelSRC/mModelDecoder.onnx" "./build-local/jpl/data/assets/mModelDecoder.onnx"
+      cp "./modelSRC/mLogSoftMax.onnx" "./build-local/jpl/data/assets/mLogSoftMax.onnx"
+      cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime.so" "build-local/jpl/lib/$CONTRIB_PLATFORM/libonnxruntime.so.1.12.0"
+    fi
+    if [ "${PROCESSOR}" = "NVIDIA" ]
+    then
+      cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime_providers_shared.so" "build-local/jpl/lib/$CONTRIB_PLATFORM/libonnxruntime_providers_shared.so"
+      cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime_providers_cuda.so" "build-local/jpl/lib/$CONTRIB_PLATFORM/libonnxruntime_providers_cuda.so"
+    fi
+
+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}
+
+    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
+
+    if [ ${DEBUG} ]; then
+      OUTPUT="${PLUGIN_NAME}"
+      CLANG_OPTS="-g -fsanitize=address"
+      EXTRA_DEBUG_LIBRARIES="-lyaml-cpp -lrav1e"
+      EXTRA_DEFINES="-D__DEBUG__"
+    else
+      python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+      CLANG_OPTS="-O3 -shared"
+      OUTPUT="build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
+
+    # Compile
+    clang++ -std=c++17 -fPIC ${CLANG_OPTS} \
+    -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-parameter \
+    ${EXTRA_DEFINES} \
+    -D${PROCESSOR} \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
+    -I"${ONNX_PATH}/include/onnxruntime/session" \
+    -I"${PLUGINS_LIB}" \
+    ./../lib/common.cpp \
+    ./../lib/accel.cpp \
+    ./../lib/frameFilter.cpp \
+    ./../lib/frameUtils.cpp \
+    main.cpp \
+    TranscriptMediaHandler.cpp \
+    TranscriptAudioSubscriber.cpp \
+    TranscriptVideoSubscriber.cpp \
+    PluginPreferenceHandler.cpp \
+    Preprocess.cpp \
+    ModelProcessor.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/" \
+    -L"${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}" \
+    -lavfilter \
+    -lswscale \
+    -lswresample \
+    -lavformat \
+    -lavcodec \
+    -lavutil \
+    -lvpx -lx264 -lbz2 -liconv -lz \
+    -lonnxruntime \
+    -lspeex \
+    -lopus \
+    ${EXTRA_DEBUG_LIBRARIES} \
+    -o "${OUTPUT}"
+
+    if [ ${DEBUG} ]; then
+      cp "${ONNX_PATH}/lib/onnxruntime/${ONNX_LIBS}/libonnxruntime.dylib" "libonnxruntime.dylib"
+      cp "./modelSRC/mModelEncoder.onnx" "./data/assets/mModelEncoder.onnx"
+      cp "./modelSRC/mModelDecoder.onnx" "./data/assets/mModelDecoder.onnx"
+      cp "./modelSRC/mLogSoftMax.onnx" "./data/assets/mLogSoftMax.onnx"
+      install_name_tool -id "@loader_path/libonnxruntime.1.12.0.dylib" "libonnxruntime.dylib"
+      install_name_tool -id "@loader_path/${PLUGIN_NAME}" "${OUTPUT}"
+    else
+      cp "./modelSRC/mModelEncoder.onnx" "./build-local/jpl/data/assets/mModelEncoder.onnx"
+      cp "./modelSRC/mModelDecoder.onnx" "./build-local/jpl/data/assets/mModelDecoder.onnx"
+      cp "./modelSRC/mLogSoftMax.onnx" "./build-local/jpl/data/assets/mLogSoftMax.onnx"
+      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.12.0.dylib" "build-local/jpl/lib/${CONTRIB_PLATFORM}/libonnxruntime.dylib"
+      install_name_tool -id "@loader_path/${SO_FILE_NAME}" "${OUTPUT}"
+    fi
+    install_name_tool -change "@rpath/libonnxruntime.1.12.0.dylib" "@loader_path/libonnxruntime.dylib" "${OUTPUT}"
+
+    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}
+
+    if [ -z "$ANDROID_NDK" ]; then
+            ANDROID_NDK="/home/${USER}/Android/Sdk/ndk/21.1.6352462"
+        echo "ANDROID_NDK not provided, building with ${ANDROID_NDK}"
+    fi
+
+    #=========================================================
+    #    Check if the ANDROID_ABI was provided
+    #    if not, set default
+    #=========================================================
+    if [ -z "$ANDROID_ABI" ]; then
+        ANDROID_ABI="armeabi-v7a arm64-v8a x86_64"
+        echo "ANDROID_ABI not provided, building for ${ANDROID_ABI}"
+    fi
+
+    buildlib() {
+        echo "$CURRENT_ABI"
+
+        #=========================================================
+        #    ANDROID TOOLS
+        #=========================================================
+        export HOST_TAG=linux-x86_64
+        export TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG
+        export AR=$TOOLCHAIN/bin/llvm-ar
+        export AS=$TOOLCHAIN/bin/llvm-as
+        export LD=$TOOLCHAIN/bin/ld
+        export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
+        export STRIP=$TOOLCHAIN/bin/llvm-strip
+        export ANDROID_SYSROOT=$TOOLCHAIN/sysroot
+
+        if [ "$CURRENT_ABI" = armeabi-v7a ]
+        then
+        export CC=$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang
+        export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang++
+
+        elif [ "$CURRENT_ABI" = arm64-v8a ]
+        then
+        export CC=$TOOLCHAIN/bin/aarch64-linux-android21-clang
+        export CXX=$TOOLCHAIN/bin/aarch64-linux-android21-clang++
+
+        elif [ "$CURRENT_ABI" = x86_64 ]
+        then
+        export CC=$TOOLCHAIN/bin/x86_64-linux-android21-clang
+        export CXX=$TOOLCHAIN/bin/x86_64-linux-android21-clang++
+
+        else
+        echo "ABI NOT OK" >&2
+        exit 1
+        fi
+
+        #=========================================================
+        #    CONTRIBS
+        #=========================================================
+        if [ "$CURRENT_ABI" = armeabi-v7a ]
+        then
+        CONTRIB_PLATFORM=arm-linux-androideabi
+
+        elif [ "$CURRENT_ABI" = arm64-v8a ]
+        then
+        CONTRIB_PLATFORM=aarch64-linux-android
+
+        elif [ "$CURRENT_ABI" = x86_64 ]
+        then
+        CONTRIB_PLATFORM=x86_64-linux-android
+        fi
+
+        if [ -f "${CONTRIB_PATH}/native-${CONTRIB_PLATFORM}/.ffmpeg" ]; then
+            rm "${CONTRIB_PATH}/native-${CONTRIB_PLATFORM}/.ffmpeg"
+        fi
+
+        WORKPATH=$(pwd)
+        cd "${CONTRIB_PATH}/native-${CONTRIB_PLATFORM}/"
+        make .ffmpeg -j$(nproc)
+        rm .ffmpeg
+        cd ${WORKPATH}
+
+        #=========================================================
+        #    Compile the plugin
+        #=========================================================
+
+        ONNX_PATH="${EXTRALIBS_PATH}/${CURRENT_ABI}"
+        if [ -z ${EXTRALIBS_PATH} ]
+        then
+          ONNX_PATH="${CONTRIB_PATH}/${CONTRIB_PLATFORM}"
+        fi
+
+        # Create so destination folder
+        $CXX --std=c++17 -O3 -fPIC \
+        -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \
+        -shared \
+        -Wall -Wextra \
+        -Wno-unused-parameter \
+        -DANDROID \
+        -I"." \
+        -I"${DAEMON_SRC}" \
+        -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include" \
+        -I"${ONNX_PATH}/include/onnxruntime/session" \
+        -I"${ONNX_PATH}/include/onnxruntime/providers/nnapi" \
+        -I"${ONNX_PATH}/../include/onnxruntime/session" \
+        -I"${ONNX_PATH}/../include/onnxruntime/providers/nnapi" \
+        -I"${PLUGINS_LIB}" \
+        ./../lib/common.cpp \
+        ./../lib/accel.cpp \
+        ./../lib/frameFilter.cpp \
+        ./../lib/frameUtils.cpp \
+        main.cpp \
+        TranscriptMediaHandler.cpp \
+        TranscriptAudioSubscriber.cpp \
+        TranscriptVideoSubscriber.cpp \
+        PluginPreferenceHandler.cpp \
+        Preprocess.cpp \
+        ModelProcessor.cpp \
+        -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/lib/" \
+        -L"${ONNX_PATH}/lib/" \
+        -lavfilter \
+        -lswscale \
+        -lswresample \
+        -lavformat \
+        -lavcodec \
+        -lavutil \
+        -lvpx \
+        -lx264 \
+        -lspeex \
+        -lopus \
+        -llog -lz \
+        -lonnxruntime \
+        --sysroot=$ANDROID_SYSROOT \
+        -o "build-local/jpl/lib/$CURRENT_ABI/${SO_FILE_NAME}"
+
+        cp "${ONNX_PATH}/lib/libonnxruntime.so" "build-local/jpl/lib/${CURRENT_ABI}/libonnxruntime.so"
+    }
+
+    # Build the so
+    for i in ${ANDROID_ABI}; do
+        CURRENT_ABI=$i
+        buildlib
+    done
+
+    cp "./modelSRC/mModelEncoder.ort" "./build-local/jpl/data/assets/mModelEncoder.ort"
+    cp "./modelSRC/mModelDecoder.ort" "./build-local/jpl/data/assets/mModelDecoder.ort"
+    cp "./modelSRC/mLogSoftMax.ort" "./build-local/jpl/data/assets/mLogSoftMax.ort"
+fi
+
+if [ ! ${DEBUG} ]; then
+  python3 ./../SDK/jplManipulation.py --assemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM} --extraPath=${EXTRAPATH}
+fi
+
+cd ${CONTRIB_PATH}/src/ffmpeg/
+# ffmpeg build configuration files were changed during plugin build
+# this git checkout will remove these changes
+git checkout -- .
diff --git a/WhisperTranscript/data/Muli-Light.ttf b/WhisperTranscript/data/Muli-Light.ttf
new file mode 100644
index 0000000..0ffcfba
--- /dev/null
+++ b/WhisperTranscript/data/Muli-Light.ttf
Binary files differ
diff --git a/WhisperTranscript/data/accountpreferences.json b/WhisperTranscript/data/accountpreferences.json
new file mode 100644
index 0000000..a5a6a36
--- /dev/null
+++ b/WhisperTranscript/data/accountpreferences.json
@@ -0,0 +1,10 @@
+[
+    {
+        "type": "Switch",
+        "key": "TranscriptAlways",
+        "title": "{{TranscriptAlways_title}}",
+        "summary": "{{TranscriptAlways_summary}}",
+        "defaultValue": "1",
+        "scope": "plugin"
+    }
+]
\ No newline at end of file
diff --git a/WhisperTranscript/data/assets/.gitignore b/WhisperTranscript/data/assets/.gitignore
new file mode 100644
index 0000000..e1a699a
--- /dev/null
+++ b/WhisperTranscript/data/assets/.gitignore
@@ -0,0 +1 @@
+*.onnx
diff --git a/WhisperTranscript/data/assets/mel_filters.bin b/WhisperTranscript/data/assets/mel_filters.bin
new file mode 100644
index 0000000..9e3c32b
--- /dev/null
+++ b/WhisperTranscript/data/assets/mel_filters.bin
Binary files differ
diff --git a/WhisperTranscript/data/assets/tokenizer.bin b/WhisperTranscript/data/assets/tokenizer.bin
new file mode 100644
index 0000000..e858463
--- /dev/null
+++ b/WhisperTranscript/data/assets/tokenizer.bin
Binary files differ
diff --git a/WhisperTranscript/data/icon.svg b/WhisperTranscript/data/icon.svg
new file mode 100644
index 0000000..326b0fe
--- /dev/null
+++ b/WhisperTranscript/data/icon.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="300px" height="300px" viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>P</title>
+    <defs>
+        <linearGradient x1="-0.0143679903%" y1="50%" x2="99.9840558%" y2="50%" id="linearGradient-1">
+            <stop stop-color="#181844" offset="0%"></stop>
+            <stop stop-color="#1E1E4C" offset="2.84%"></stop>
+            <stop stop-color="#283261" offset="13.53%"></stop>
+            <stop stop-color="#2D4172" offset="24.68%"></stop>
+            <stop stop-color="#2E4A7C" offset="36.47%"></stop>
+            <stop stop-color="#2E4D7F" offset="50%"></stop>
+            <stop stop-color="#2D4576" offset="61.77%"></stop>
+            <stop stop-color="#273160" offset="81.25%"></stop>
+            <stop stop-color="#181844" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="-0.0143775661%" y1="50.0132404%" x2="99.9808363%" y2="50.0132404%" id="linearGradient-2">
+            <stop stop-color="#2867A2" offset="0%"></stop>
+            <stop stop-color="#2174B1" offset="3.82%"></stop>
+            <stop stop-color="#0B86C4" offset="11.77%"></stop>
+            <stop stop-color="#0A94D2" offset="20.81%"></stop>
+            <stop stop-color="#0C9BDB" offset="31.77%"></stop>
+            <stop stop-color="#109EDE" offset="50%"></stop>
+            <stop stop-color="#0C9BDB" offset="68.23%"></stop>
+            <stop stop-color="#0A94D2" offset="79.19%"></stop>
+            <stop stop-color="#0B86C4" offset="88.23%"></stop>
+            <stop stop-color="#2174B1" offset="96.18%"></stop>
+            <stop stop-color="#2867A2" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="P" transform="translate(34.000000, 0.000000)">
+            <path d="M115.654206,0.0700934579 C51.7990654,0.0700934579 0.0700934579,51.8691589 0.0700934579,115.724299 L0.0700934579,299.929907 L80.3971963,299.929907 L80.3971963,225.841121 C91.5420561,229.415888 103.38785,231.378505 115.724299,231.378505 C179.579439,231.378505 231.308411,179.649533 231.308411,115.794393 C231.238318,51.8691589 179.509346,0.0700934579 115.654206,0.0700934579 Z M115.654206,151.051402 C96.1682243,151.051402 80.3271028,135.21028 80.3271028,115.724299 C80.3271028,96.2383178 96.1682243,80.3971963 115.654206,80.3971963 C135.140187,80.3971963 150.981308,96.2383178 150.981308,115.724299 C150.981308,135.21028 135.140187,151.051402 115.654206,151.051402 Z" id="Shape" fill="url(#linearGradient-1)"></path>
+            <path d="M133.247664,1.40186916 C133.247664,1.40186916 198.785047,18.9252336 193.808411,80.3971963 C188.831776,141.799065 137.663551,149.299065 105.490654,150.981308 C73.317757,152.663551 0.0700934579,159.462617 0.0700934579,242.803738 C0.0700934579,242.803738 29.8598131,210.490654 80.3971963,225.771028 C126.168224,239.579439 174.462617,225 202.219626,192.336449 C228.85514,160.934579 238.037383,123.014019 225.841121,80.3271028 C213.785047,38.4813084 173.971963,6.93925234 133.247664,1.40186916 Z" id="Path" fill="url(#linearGradient-2)"></path>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/WhisperTranscript/data/locale/WhisperTranscript_en.json b/WhisperTranscript/data/locale/WhisperTranscript_en.json
new file mode 100644
index 0000000..b6beff2
--- /dev/null
+++ b/WhisperTranscript/data/locale/WhisperTranscript_en.json
@@ -0,0 +1,20 @@
+{
+    "avstream_title": "Stream",
+    "avstream_summary": "Select the stream to process the transcription",
+    "avstream_entries_1": "Sent",
+    "avstream_entries_2": "Received",
+    "TranscriptAlways_title": "Automatically activate transcription",
+    "TranscriptAlways_summary": "Activate transcription when a call starts.",
+    "background_title": "Add background color",
+    "background_summary": "Add a partial transparency to the subtitle background if it isn't visible enough",
+    "background_entries_1": "None",
+    "background_entries_2": "Black",
+    "background_entries_3": "White",
+    "position_title": "Transcription position",
+    "position_entries_1": "Top right",
+    "position_entries_2": "Top left",
+    "position_entries_3": "Bottom left",
+    "position_entries_4": "Bottom right",
+    "fontsize_title": "Font size"
+
+}
\ No newline at end of file
diff --git a/WhisperTranscript/data/preferences.json b/WhisperTranscript/data/preferences.json
new file mode 100644
index 0000000..e5fd3d5
--- /dev/null
+++ b/WhisperTranscript/data/preferences.json
@@ -0,0 +1,82 @@
+[
+    {
+        "type": "List",
+        "key": "background",
+        "title": "{{background_title}}",
+        "summary": "{{background_summary}}",
+        "defaultValue": "black@0.0",
+        "scope": "plugin,Transcript",
+        "entryValues": [
+            "black@0.0",
+            "black@0.5",
+            "white@0.5"
+        ],
+        "entries": [
+            "{{background_entries_1}}",
+            "{{background_entries_2}}",
+            "{{background_entries_3}}"
+        ]
+    },
+    {
+        "type": "List",
+        "key": "position",
+        "title": "{{position_title}}",
+        "defaultValue": "2",
+        "scope": "plugin,Transcript",
+        "entryValues": [
+            "1",
+            "2",
+            "3",
+            "4"
+        ],
+        "entries": [
+            "{{position_entries_1}}",
+            "{{position_entries_2}}",
+            "{{position_entries_3}}",
+            "{{position_entries_4}}"
+        ]
+    },
+    {
+        "type": "List",
+        "key": "fontsize",
+        "title": "{{fontsize_title}}",
+        "defaultValue": "14",
+        "scope": "plugin,Transcript",
+        "entryValues": [
+            "10",
+            "12",
+            "14",
+            "16",
+            "18",
+            "24",
+            "36",
+            "72"
+        ],
+        "entries": [
+            "10",
+            "12",
+            "14",
+            "16",
+            "18",
+            "24",
+            "36",
+            "72"
+        ]
+    },
+    {
+        "type": "List",
+        "key": "avstream",
+        "title": "{{avstream_title}}",
+        "summary": "{{avstream_summary}}",
+        "defaultValue": "in",
+        "scope": "plugin",
+        "entryValues": [
+            "out",
+            "in"
+        ],
+        "entries": [
+            "{{avstream_entries_1}}",
+            "{{avstream_entries_2}}"
+        ]
+    }
+]
\ No newline at end of file
diff --git a/WhisperTranscript/ffmpeg/package.json b/WhisperTranscript/ffmpeg/package.json
new file mode 100644
index 0000000..69c2a52
--- /dev/null
+++ b/WhisperTranscript/ffmpeg/package.json
@@ -0,0 +1,33 @@
+{
+    "name": "ffmpeg",
+    "version": "n5.0",
+    "url": "https://git.ffmpeg.org/gitweb/ffmpeg.git/snapshot/__VERSION__.tar.gz",
+    "deps": [
+        "vpx",
+        "x264",
+        "opus",
+        "ffnvcodec",
+        "media-sdk"
+    ],
+    "patches": [
+        "change-RTCP-ratio.patch",
+        "rtp_ext_abs_send_time.patch",
+        "libopusenc-reload-packet-loss-at-encode.patch",
+        "libopusdec-enable-FEC.patch",
+        "windows-configure.patch",
+        "windows-configure-ffnvcodec.patch",
+        "windows-configure-libmfx.patch"
+    ],
+    "win_patches": [
+    ],
+    "project_paths": [],
+    "with_env" : "10.0.16299.0",
+    "custom_scripts": {
+        "pre_build": [],
+        "build": [
+            "call \"%CONTRIB_SRC_DIR%\\ffmpeg\\build_ffmpeg.bat\"",
+            "cd Build/win32/x64/lib & ren *.a *.lib"
+        ],
+        "post_build": []
+    }
+}
diff --git a/WhisperTranscript/ffmpeg/rules.mak b/WhisperTranscript/ffmpeg/rules.mak
new file mode 100644
index 0000000..7b5c554
--- /dev/null
+++ b/WhisperTranscript/ffmpeg/rules.mak
@@ -0,0 +1,365 @@
+FFMPEG_HASH := n5.0
+FFMPEG_URL := https://git.ffmpeg.org/gitweb/ffmpeg.git/snapshot/$(FFMPEG_HASH).tar.gz
+
+PKGS+=ffmpeg
+
+ifdef HAVE_ANDROID
+DEPS_ffmpeg = iconv zlib vpx opus speex x264 freetype
+else
+ifdef __DEBUG__
+DEPS_ffmpeg = iconv zlib vpx opus speex x264 rav1e
+else
+DEPS_ffmpeg = iconv zlib vpx opus speex x264
+endif
+endif
+
+FFMPEGCONF = \
+	--cc="$(CC)" \
+	--pkg-config="$(PKG_CONFIG)"
+
+#disable everything
+FFMPEGCONF += \
+	--disable-everything \
+	--enable-zlib \
+	--enable-gpl \
+	--enable-swscale \
+	--enable-bsfs \
+	--disable-filters \
+	--disable-programs \
+	--disable-postproc
+
+FFMPEGCONF += \
+	--disable-protocols \
+	--enable-protocol=crypto \
+	--enable-protocol=file \
+	--enable-protocol=rtp \
+	--enable-protocol=srtp \
+	--enable-protocol=tcp \
+	--enable-protocol=udp \
+	--enable-protocol=unix \
+	--enable-protocol=pipe
+
+#enable muxers/demuxers
+FFMPEGCONF += \
+	--disable-demuxers \
+	--disable-muxers \
+	--enable-muxer=rtp \
+	--enable-muxer=g722 \
+	--enable-muxer=h263 \
+	--enable-muxer=h264 \
+	--enable-muxer=hevc \
+	--enable-muxer=webm \
+	--enable-muxer=ogg \
+	--enable-muxer=pcm_s16be \
+	--enable-muxer=pcm_s16le \
+	--enable-muxer=wav \
+	--enable-muxer=w64 \
+	--enable-demuxer=rtp \
+	--enable-demuxer=mjpeg \
+	--enable-demuxer=mjpeg_2000 \
+	--enable-demuxer=mpegvideo \
+	--enable-demuxer=gif \
+	--enable-demuxer=image_jpeg_pipe \
+	--enable-demuxer=image_png_pipe \
+	--enable-demuxer=image_webp_pipe \
+	--enable-demuxer=matroska \
+	--enable-demuxer=m4v \
+	--enable-demuxer=ogg \
+	--enable-demuxer=flac \
+	--enable-demuxer=wav \
+	--enable-demuxer=w64 \
+	--enable-demuxer=ac3 \
+	--enable-demuxer=g722 \
+	--enable-demuxer=pcm_mulaw \
+	--enable-demuxer=pcm_alaw \
+	--enable-demuxer=pcm_s16be \
+	--enable-demuxer=pcm_s16le \
+	--enable-demuxer=h263 \
+	--enable-demuxer=h264 \
+	--enable-demuxer=hevc
+
+#enable parsers
+FFMPEGCONF += \
+	--enable-parser=h263 \
+	--enable-parser=h264 \
+	--enable-parser=hevc \
+	--enable-parser=mpeg4video \
+	--enable-parser=vp8 \
+	--enable-parser=vp9 \
+	--enable-parser=opus \
+	--enable-parser=w64 \
+	--enable-parser=wav
+
+#encoders/decoders
+FFMPEGCONF += \
+	--enable-encoder=w64 \
+	--enable-encoder=wav \
+	--enable-decoder=w64 \
+	--enable-decoder=wav \
+	--enable-encoder=adpcm_g722 \
+	--enable-decoder=adpcm_g722 \
+	--enable-encoder=rawvideo \
+	--enable-decoder=rawvideo \
+	--enable-encoder=libx264 \
+	--enable-decoder=h264 \
+	--enable-encoder=pcm_alaw \
+	--enable-decoder=pcm_alaw \
+	--enable-encoder=pcm_mulaw \
+	--enable-decoder=pcm_mulaw \
+	--enable-encoder=mpeg4 \
+	--enable-decoder=mpeg4 \
+	--enable-encoder=libvpx_vp8 \
+	--enable-decoder=vp8 \
+	--enable-decoder=vp9 \
+	--enable-encoder=h263 \
+	--enable-encoder=h263p \
+	--enable-decoder=h263 \
+	--enable-encoder=mjpeg \
+	--enable-decoder=mjpeg \
+	--enable-decoder=mjpegb \
+	--enable-libspeex \
+	--enable-libopus \
+	--enable-libvpx \
+	--enable-libx264 \
+	--enable-encoder=libspeex \
+	--enable-decoder=libspeex \
+	--enable-encoder=libopus \
+	--enable-decoder=libopus
+
+ifdef __DEBUG__
+FFMPEGCONF += \
+	--enable-librav1e \
+	--enable-encoder=librav1e \
+	--enable-muxer=mp4
+endif
+
+# decoders for ringtones and audio streaming
+FFMPEGCONF += \
+	--enable-decoder=flac \
+	--enable-decoder=vorbis \
+	--enable-decoder=aac \
+	--enable-decoder=ac3 \
+	--enable-decoder=eac3 \
+	--enable-decoder=pcm_u24be \
+	--enable-decoder=pcm_u24le \
+	--enable-decoder=pcm_u32be \
+	--enable-decoder=pcm_u32le \
+	--enable-decoder=pcm_u8 \
+	--enable-decoder=pcm_f16le \
+	--enable-decoder=pcm_f24le \
+	--enable-decoder=pcm_f32be \
+	--enable-decoder=pcm_f32le \
+	--enable-decoder=pcm_f64be \
+	--enable-decoder=pcm_f64le \
+	--enable-decoder=pcm_s16be \
+	--enable-decoder=pcm_s16be_planar \
+	--enable-decoder=pcm_s16le \
+	--enable-decoder=pcm_s16le_planar \
+	--enable-decoder=pcm_s24be \
+	--enable-decoder=pcm_s24le \
+	--enable-decoder=pcm_s24le_planar \
+	--enable-decoder=pcm_s32be \
+	--enable-decoder=pcm_s32le \
+	--enable-decoder=pcm_s32le_planar \
+	--enable-decoder=pcm_s64be \
+	--enable-decoder=pcm_s64le \
+	--enable-decoder=pcm_s8 \
+	--enable-decoder=pcm_s8_planar \
+	--enable-decoder=pcm_u16be \
+	--enable-decoder=pcm_u16le
+
+#filters
+FFMPEGCONF += \
+	--enable-filter=scale \
+	--enable-filter=aresample \
+	--enable-filter=aformat \
+	--enable-filter=rotate \
+	--enable-filter=format \
+	--enable-filter=drawbox \
+	--enable-filter=drawtext \
+	--enable-libfreetype
+
+#platform specific options
+
+ifdef HAVE_WIN32
+FFMPEGCONF += \
+	--enable-indev=dshow \
+	--enable-indev=gdigrab \
+	--enable-dxva2
+endif
+
+ifdef HAVE_LINUX
+FFMPEGCONF += --enable-pic
+ifdef HAVE_ANDROID
+# Android Linux
+FFMPEGCONF += \
+	--target-os=android \
+	--enable-jni \
+	--enable-mediacodec \
+	--disable-vulkan \
+	--enable-decoder=vp8_mediacodec \
+	--enable-decoder=h264_mediacodec \
+	--enable-decoder=mpeg4_mediacodec \
+	--enable-decoder=hevc_mediacodec \
+	--enable-cross-compile \
+	--ranlib=$(RANLIB) \
+	--strip=$(STRIP) \
+	--cc=$(CC) \
+	--cxx=$(CXX) \
+	--ld=$(CC) \
+	--ar=$(AR)
+# ASM not working on Android x86 https://trac.ffmpeg.org/ticket/4928
+ifeq ($(ARCH),i386)
+FFMPEGCONF += --disable-asm
+endif
+ifeq ($(ARCH),x86_64)
+FFMPEGCONF += --disable-asm
+endif
+else
+# Desktop Linux
+DEPS_ffmpeg += ffnvcodec
+FFMPEGCONF += \
+	--target-os=linux \
+	--enable-indev=v4l2 \
+	--enable-indev=xcbgrab \
+	--enable-vdpau \
+	--enable-hwaccel=h264_vdpau \
+	--enable-hwaccel=mpeg4_vdpau \
+	--enable-vaapi \
+	--enable-hwaccel=h264_vaapi \
+	--enable-hwaccel=mpeg4_vaapi \
+	--enable-hwaccel=h263_vaapi \
+	--enable-hwaccel=vp8_vaapi \
+	--enable-hwaccel=mjpeg_vaapi \
+	--enable-hwaccel=hevc_vaapi \
+	--enable-encoder=h264_vaapi \
+	--enable-encoder=vp8_vaapi \
+	--enable-encoder=mjpeg_vaapi \
+	--enable-encoder=hevc_vaapi
+# ffnvcodec is not supported on ARM then we enable it here for i386 and x86_64
+ifeq ($(ARCH),$(filter $(ARCH),i386 x86_64))
+FFMPEGCONF += --enable-cuvid \
+	      --enable-ffnvcodec \
+	      --enable-nvdec \
+	      --enable-nvenc \
+	      --enable-hwaccel=h264_nvdec \
+	      --enable-hwaccel=hevc_nvdec \
+	      --enable-hwaccel=vp8_nvdec \
+	      --enable-hwaccel=mjpeg_nvdec \
+	      --enable-encoder=h264_nvenc \
+	      --enable-encoder=hevc_nvenc
+endif
+# End Desktop Linux:
+endif
+# End HAVE_LINUX:
+endif
+
+ifdef HAVE_MACOSX
+FFMPEGCONF += \
+	--enable-avfoundation \
+	--enable-indev=avfoundation \
+	--enable-videotoolbox \
+	--enable-hwaccel=h263_videotoolbox \
+	--enable-hwaccel=h264_videotoolbox \
+	--enable-hwaccel=mpeg4_videotoolbox \
+	--enable-hwaccel=hevc_videotoolbox \
+	--enable-encoder=h264_videotoolbox \
+	--enable-encoder=hevc_videotoolbox \
+	--disable-securetransport
+endif
+
+ifdef HAVE_IOS
+FFMPEGCONF += \
+	--enable-videotoolbox \
+	--enable-hwaccel=h263_videotoolbox \
+	--enable-hwaccel=h264_videotoolbox \
+	--enable-hwaccel=mpeg4_videotoolbox \
+	--enable-hwaccel=hevc_videotoolbox \
+	--enable-encoder=h264_videotoolbox \
+	--enable-encoder=hevc_videotoolbox \
+	--target-os=darwin \
+	--enable-cross-compile \
+	--enable-pic
+endif
+
+ifndef HAVE_IOS
+ifndef HAVE_ANDROID
+ifdef HAVE_CROSS_COMPILE
+FFMPEGCONF += --cross-prefix=$(HOST)-
+endif
+endif
+endif
+
+# x86 stuff
+ifeq ($(ARCH),i386)
+FFMPEGCONF += --arch=x86
+endif
+
+ifeq ($(ARCH),x86_64)
+FFMPEGCONF += --arch=x86_64
+endif
+
+# ARM stuff
+ifeq ($(ARCH),arm)
+FFMPEGCONF += --arch=arm
+ifdef HAVE_ARMV7A
+FFMPEGCONF += --cpu=cortex-a8
+endif
+ifdef HAVE_ARMV6
+FFMPEGCONF += --cpu=armv6 --disable-neon
+endif
+endif
+
+# ARM64 stuff
+ifeq ($(ARCH),aarch64)
+FFMPEGCONF += --arch=aarch64
+endif
+ifeq ($(ARCH),arm64)
+FFMPEGCONF += --arch=aarch64
+endif
+
+# Windows
+ifdef HAVE_WIN32
+DEPS_ffmpeg += ffnvcodec
+FFMPEGCONF += --target-os=mingw32 \
+    --enable-w32threads \
+    --disable-decoder=dca \
+	--enable-cuvid \
+	--enable-ffnvcodec \
+	--enable-nvdec \
+	--enable-nvenc \
+	--enable-hwaccel=h264_nvdec \
+	--enable-hwaccel=hevc_nvdec \
+	--enable-hwaccel=vp8_nvdec \
+	--enable-hwaccel=mjpeg_nvdec \
+	--enable-encoder=h264_nvenc \
+	--enable-encoder=hevc_nvenc
+endif
+
+$(TARBALLS)/ffmpeg-$(FFMPEG_HASH).tar.gz:
+	$(call download,$(FFMPEG_URL))
+
+.sum-ffmpeg: ffmpeg-$(FFMPEG_HASH).tar.gz
+
+ffmpeg: ffmpeg-$(FFMPEG_HASH).tar.gz
+	rm -Rf $@ $@-$(FFMPEG_HASH)
+	mkdir -p $@-$(FFMPEG_HASH)
+	(cd $@-$(FFMPEG_HASH) && tar x $(if ${BATCH_MODE},,-v) --strip-components=1 -f ../$<)
+	$(APPLY) $(SRC)/ffmpeg/remove-mjpeg-log.patch
+	$(APPLY) $(SRC)/ffmpeg/change-RTCP-ratio.patch
+	$(APPLY) $(SRC)/ffmpeg/rtp_ext_abs_send_time.patch
+	$(APPLY) $(SRC)/ffmpeg/libopusdec-enable-FEC.patch
+	$(APPLY) $(SRC)/ffmpeg/libopusenc-reload-packet-loss-at-encode.patch
+	$(APPLY) $(SRC)/ffmpeg/ios-disable-b-frames.patch
+	$(APPLY) $(SRC)/ffmpeg/screen-sharing-x11-fix.patch
+	$(UPDATE_AUTOCONFIG)
+	$(MOVE)
+
+.ffmpeg: ffmpeg .sum-ffmpeg
+	cd $< && $(HOSTVARS) ./configure \
+		--extra-cflags="$(CFLAGS)" \
+		--extra-ldflags="$(LDFLAGS)" $(FFMPEGCONF) \
+		--prefix="$(PREFIX)" --enable-static --disable-shared \
+		--pkg-config-flags="--static"
+	cd $< && $(MAKE) install-libs install-headers
+	touch $@
diff --git a/WhisperTranscript/ffmpeg/windows-configure-make.sh b/WhisperTranscript/ffmpeg/windows-configure-make.sh
new file mode 100644
index 0000000..dbd4ae0
--- /dev/null
+++ b/WhisperTranscript/ffmpeg/windows-configure-make.sh
@@ -0,0 +1,183 @@
+#!/bin/bash

+set +x

+set +e

+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

+cd $DIR/../../build/ffmpeg

+FFMPEGCONF='

+            --toolchain=msvc

+            --target-os=win32'

+

+#disable everything

+FFMPEGCONF+='

+            --disable-everything

+            --disable-programs

+            --disable-d3d11va

+            --disable-dxva2

+            --disable-postproc

+            --disable-filters'

+

+FFMPEGCONF+='

+            --enable-cross-compile

+            --enable-gpl

+            --enable-swscale

+            --enable-protocols

+            --enable-bsfs'

+

+#enable muxers/demuxers

+FFMPEGCONF+='

+            --enable-demuxers

+            --enable-muxers

+            --enable-muxer=mp4'

+

+#enable parsers

+FFMPEGCONF+='

+            --enable-parser=h263

+            --enable-parser=h264

+            --enable-parser=hevc

+            --enable-parser=mpeg4video

+            --enable-parser=vp8

+            --enable-parser=vp9

+            --enable-parser=opus'

+

+#encoders/decoders

+FFMPEGCONF+='

+            --enable-libopus

+            --enable-encoder=libopus

+            --enable-decoder=libopus

+            --enable-encoder=adpcm_g722

+            --enable-decoder=adpcm_g722

+            --enable-encoder=pcm_alaw

+            --enable-decoder=pcm_alaw

+            --enable-encoder=pcm_mulaw

+            --enable-decoder=pcm_mulaw

+            --enable-libx264

+            --enable-encoder=libx264

+            --enable-decoder=h264

+            --enable-encoder=rawvideo

+            --enable-decoder=rawvideo

+            --enable-encoder=mpeg4

+            --enable-decoder=mpeg4

+            --enable-encoder=h263

+            --enable-encoder=h263p

+            --enable-decoder=h263

+            --enable-encoder=mjpeg

+            --enable-decoder=mjpeg

+            --enable-decoder=mjpegb'

+

+# decoders for ringtones and audio streaming

+FFMPEGCONF+='

+            --enable-decoder=flac

+            --enable-decoder=vorbis

+            --enable-decoder=aac

+            --enable-decoder=ac3

+            --enable-decoder=eac3

+            --enable-decoder=pcm_u24be

+            --enable-decoder=pcm_u24le

+            --enable-decoder=pcm_u32be

+            --enable-decoder=pcm_u32le

+            --enable-decoder=pcm_u8

+            --enable-decoder=pcm_f16le

+            --enable-decoder=pcm_f24le

+            --enable-decoder=pcm_f32be

+            --enable-decoder=pcm_f32le

+            --enable-decoder=pcm_f64be

+            --enable-decoder=pcm_f64le

+            --enable-decoder=pcm_s16be

+            --enable-decoder=pcm_s16be_planar

+            --enable-decoder=pcm_s16le

+            --enable-decoder=pcm_s16le_planar

+            --enable-decoder=pcm_s24be

+            --enable-decoder=pcm_s24le

+            --enable-decoder=pcm_s24le_planar

+            --enable-decoder=pcm_s32be

+            --enable-decoder=pcm_s32le

+            --enable-decoder=pcm_s32le_planar

+            --enable-decoder=pcm_s64be

+            --enable-decoder=pcm_s64le

+            --enable-decoder=pcm_s8

+            --enable-decoder=pcm_s8_planar

+            --enable-decoder=pcm_u16be

+            --enable-decoder=pcm_u16le'

+

+#filters

+FFMPEGCONF+='

+            --enable-filter=scale

+            --enable-filter=aresample

+            --enable-filter=aformat

+            --enable-filter=rotate

+            --enable-filter=format

+            --enable-filter=drawtext'

+

+if [ "$1" == "uwp" ]; then

+    EXTRACFLAGS='-MD -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WIN32_WINNT=0x0A00 -I../../../../../msvc/include -I../../../../../msvc/include/opus'

+    if [ "$2" == "x64" ]; then

+        echo "configure and make ffmpeg for UWP-x64..."

+            EXTRALDFLAGS='-APPCONTAINER WindowsApp.lib libopus.lib libx264.lib -LIBPATH:../../../../../msvc/lib/x64'

+            FFMPEGCONF+=' --arch=x86_64'

+            PREFIX=../../../Build/Windows10/x64

+            OUTDIR=Output/Windows10/x64

+    elif [ "$2" == "x86" ]; then

+        echo "configure and make ffmpeg for UWP-x86..."

+            EXTRALDFLAGS='-APPCONTAINER WindowsApp.lib libopus.lib libx264.lib -LIBPATH:../../../../../msvc/lib/x86'

+            FFMPEGCONF+=' --arch=x86'

+            PREFIX=../../../Build/Windows10/x86

+            OUTDIR=Output/Windows10/x86

+    fi

+elif [ "$1" == "win32" ]; then

+    EXTRACFLAGS='-MD -D_WINDLL -I../../../../../msvc/include -I../../../../../msvc/include/opus -I../../../../../msvc/include/vpx -I../../../../../msvc/include/ffnvcodec -I../../../../../msvc/include/mfx -I../../../../../msvc/include/lame'

+    FFMPEGCONF+='

+                --enable-libvpx

+                --enable-encoder=libvpx_vp8

+                --enable-decoder=vp8

+                --enable-decoder=vp9'

+    FFMPEGCONF+='

+                --enable-indev=dshow

+                --enable-indev=gdigrab

+                --enable-dxva2'

+    FFMPEGCONF+='

+                --enable-ffnvcodec

+                --enable-cuvid

+                --enable-nvdec

+                --enable-nvenc

+                --enable-hwaccel=h264_nvdec

+                --enable-hwaccel=hevc_nvdec

+                --enable-hwaccel=vp8_nvdec

+                --enable-hwaccel=mjpeg_nvdec

+                --enable-encoder=h264_nvenc

+                --enable-encoder=hevc_nvenc'

+    FFMPEGCONF+='

+                --enable-libmfx

+                --enable-encoder=h264_qsv

+                --enable-encoder=hevc_qsv

+                --enable-encoder=mjpeg_qsv

+                --enable-decoder=vp8_qsv

+                --enable-decoder=h264_qsv

+                --enable-decoder=hevc_qsv

+                --enable-decoder=mjpeg_qsv

+                --enable-decoder=vp9_qsv

+                --enable-filter=scale_qsv

+                --enable-filter=overlay_qsv'

+    if [ "$2" == "x64" ]; then

+        echo "configure and make ffmpeg for win32-x64..."

+        EXTRALDFLAGS='-APPCONTAINER:NO -MACHINE:x64 Ole32.lib Kernel32.lib Gdi32.lib User32.lib Strmiids.lib Advapi32.lib OleAut32.lib Shlwapi.lib Vfw32.lib Secur32.lib Advapi32.lib libopus.lib libx264.lib libvpx.lib libmfx.lib -LIBPATH:../../../../../msvc/lib/x64'

+        FFMPEGCONF+=' --arch=x86_64'

+        PREFIX=../../../Build/win32/x64

+        OUTDIR=Output/win32/x64

+    elif [ "$2" == "x86" ]; then

+        echo "configure and make ffmpeg for win32-x86..."

+        EXTRALDFLAGS='-APPCONTAINER:NO -MACHINE:x86 Ole32.lib Kernel32.lib Gdi32.lib User32.lib Strmiids.lib OleAut32.lib Shlwapi.lib Vfw32.lib Secur32.lib Advapi32.lib libopus.lib libx264.lib libvpx.lib libmfx.lib -LIBPATH:../../../../../msvc/lib/x86'

+        FFMPEGCONF+=' --arch=x86'

+        PREFIX=../../../Build/win32/x86

+        OUTDIR=Output/win32/x86

+    fi

+fi

+rm -rf $OUTDIR

+mkdir -p $OUTDIR

+cd $OUTDIR

+pwd

+FFMPEGCONF=$(echo $FFMPEGCONF | sed -e "s/[[:space:]]\+/ /g")

+set -x

+set -e

+../../../configure $FFMPEGCONF --extra-cflags="${EXTRACFLAGS}" --extra-ldflags="${EXTRALDFLAGS}" --prefix="${PREFIX}"

+make -j8 install

+cd ../../..

diff --git a/WhisperTranscript/gb0.wav b/WhisperTranscript/gb0.wav
new file mode 100644
index 0000000..94455b4
--- /dev/null
+++ b/WhisperTranscript/gb0.wav
Binary files differ
diff --git a/WhisperTranscript/getonnxio.py b/WhisperTranscript/getonnxio.py
new file mode 100644
index 0000000..7385a51
--- /dev/null
+++ b/WhisperTranscript/getonnxio.py
@@ -0,0 +1,83 @@
+import onnx
+
+model = onnx.load('data/assets/mModelEncoder.onnx')
+output =[node.name for node in model.graph.output]
+
+input_all = [node.name for node in model.graph.input]
+input_initializer =  [node.name for node in model.graph.initializer]
+net_feed_input = list(set(input_all)  - set(input_initializer))
+
+print('Encoder Inputs: ', net_feed_input)
+print('Encoder Outputs: ', output)
+print("")
+
+onnx.checker.check_model(model)
+graph_def = model.graph
+
+inputs = graph_def.input
+for graph_input in inputs:
+    input_shape = []
+    for d in graph_input.type.tensor_type.shape.dim:
+        if d.dim_value == 0:
+            input_shape.append(None)
+        else:
+            input_shape.append(d.dim_value)
+    print(
+        f"Input Name: {graph_input.name}, Input Data Type: {graph_input.type.tensor_type.elem_type}, Input Shape: {input_shape}"
+    )
+
+
+print("")
+outputs = graph_def.output
+for graph_output in outputs:
+    output_shape = []
+    for d in graph_output.type.tensor_type.shape.dim:
+        if d.dim_value == 0:
+            output_shape.append(None)
+        else:
+            output_shape.append(d.dim_value)
+    print(
+        f"Output Name: {graph_output.name}, Output Data Type: {graph_output.type.tensor_type.elem_type}, Output Shape: {output_shape}"
+    )
+
+
+model = onnx.load('data/assets/mModelDecoder.onnx')
+output =[node.name for node in model.graph.output]
+
+input_all = [node.name for node in model.graph.input]
+input_initializer =  [node.name for node in model.graph.initializer]
+net_feed_input = list(set(input_all)  - set(input_initializer))
+
+print("\n")
+
+print('Decoder Inputs: ', net_feed_input)
+print('Decoder Outputs: ', output)
+print("")
+
+onnx.checker.check_model(model)
+graph_def = model.graph
+
+inputs = graph_def.input
+for graph_input in inputs:
+    input_shape = []
+    for d in graph_input.type.tensor_type.shape.dim:
+        if d.dim_value == 0:
+            input_shape.append(None)
+        else:
+            input_shape.append(d.dim_value)
+    print(
+        f"Input Name: {graph_input.name}, Input Data Type: {graph_input.type.tensor_type.elem_type}, Input Shape: {input_shape}"
+    )
+
+print("")
+outputs = graph_def.output
+for graph_output in outputs:
+    output_shape = []
+    for d in graph_output.type.tensor_type.shape.dim:
+        if d.dim_value == 0:
+            output_shape.append(None)
+        else:
+            output_shape.append(d.dim_value)
+    print(
+        f"Output Name: {graph_output.name}, Output Data Type: {graph_output.type.tensor_type.elem_type}, Output Shape: {output_shape}"
+    )
diff --git a/WhisperTranscript/jami.wav b/WhisperTranscript/jami.wav
new file mode 100644
index 0000000..48cb5cb
--- /dev/null
+++ b/WhisperTranscript/jami.wav
Binary files differ
diff --git a/WhisperTranscript/jfk.wav b/WhisperTranscript/jfk.wav
new file mode 100644
index 0000000..3184d37
--- /dev/null
+++ b/WhisperTranscript/jfk.wav
Binary files differ
diff --git a/WhisperTranscript/main.cpp b/WhisperTranscript/main.cpp
new file mode 100644
index 0000000..00c976d
--- /dev/null
+++ b/WhisperTranscript/main.cpp
@@ -0,0 +1,166 @@
+/**
+ *  Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Gondim Santos <aline.gondimsantos@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
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include <iostream>
+#include <string.h>
+#include <thread>
+#include <memory>
+#include <plugin/jamiplugin.h>
+
+#include "TranscriptMediaHandler.h"
+#include "PluginPreferenceHandler.h"
+
+#ifdef __DEBUG__
+#include <common.h>
+#include <assert.h>
+#include <yaml-cpp/yaml.h>
+#include <fstream>
+#include <AVFrameIO.h>
+#endif
+
+#ifdef WIN32
+#define EXPORT_PLUGIN __declspec(dllexport)
+#else
+#define EXPORT_PLUGIN
+#endif
+
+#define WhisperTranscript_VERSION_MAJOR 0
+#define WhisperTranscript_VERSION_MINOR 0
+#define WhisperTranscript_VERSION_PATCH 0
+
+extern "C" {
+
+void
+pluginExit(void)
+{}
+
+EXPORT_PLUGIN JAMI_PluginExitFunc
+JAMI_dynPluginInit(const JAMI_PluginAPI* api)
+{
+    std::cout << "**************************" << std::endl;
+    std::cout << "**  WhisperTranscript  **" << std::endl;
+    std::cout << "**************************" << std::endl << std::endl;
+    std::cout << "Version " << WhisperTranscript_VERSION_MAJOR << "." << WhisperTranscript_VERSION_MINOR << "."
+              << WhisperTranscript_VERSION_PATCH << std::endl;
+
+    // If invokeService doesn't return an error
+    if (api) {
+        if (api->version.api < JAMI_PLUGIN_API_VERSION)
+            return nullptr;
+
+        std::map<std::string, std::map<std::string, std::string>> preferences;
+        api->invokeService(api, "getPluginAccPreferences", &preferences);
+        std::string dataPath;
+        api->invokeService(api, "getPluginDataPath", &dataPath);
+
+        auto fmpPluginPreferenceHandler
+            = std::make_unique<jami::PluginPreferenceHandler>(api,
+                                                              std::move(preferences),
+                                                              dataPath);
+
+        auto fmpTranscriptMediaHandler
+            = std::make_unique<jami::TranscriptMediaHandler>(std::move(dataPath),
+                                                             fmpPluginPreferenceHandler.get());
+
+        fmpPluginPreferenceHandler->setTranscriptHandler(fmpTranscriptMediaHandler.get());
+
+        if (api->manageComponent(api,
+                                 "CallMediaHandlerManager",
+                                 fmpTranscriptMediaHandler.release())) {
+            return nullptr;
+        }
+        if (api->manageComponent(api,
+                                 "PreferenceHandlerManager",
+                                 fmpPluginPreferenceHandler.release())) {
+            return nullptr;
+        }
+    }
+    return pluginExit;
+}
+}
+
+#ifdef __DEBUG__
+
+int
+main ()
+{
+    std::cout << "***************************************" << std::endl;
+    std::cout << "**  WhisperTranscript Debug Version  **" << std::endl;
+    std::cout << "***************************************" << std::endl;
+    std::cout << "Version " << WhisperTranscript_VERSION_MAJOR << "." << WhisperTranscript_VERSION_MINOR << "."
+              << WhisperTranscript_VERSION_PATCH << std::endl;
+
+    std::ifstream file;
+    file_utils::openStream(file, "testPreferences.yml");
+
+    assert(file.is_open());
+    YAML::Node node = YAML::Load(file);
+
+    assert(node.IsMap());
+    std::map<std::string, std::map<std::string, std::string>> preferences;
+    preferences["default"] = {};
+    for (const auto& kv : node) {
+        preferences["default"][kv.first.as<std::string>()] = kv.second.as<std::string>();
+        std::cout << "Key: " << kv.first.as<std::string>() << "; Value: " << kv.second.as<std::string>() << std::endl;
+    }
+
+#ifdef _WIN32
+    std::string dataPath = "../data";
+#else
+    std::string dataPath = "data";
+#endif
+
+    auto fmpPluginPreferenceHandler
+            = std::make_unique<jami::PluginPreferenceHandler>(nullptr, std::move(preferences), dataPath);
+    auto fmpTranscriptMediaHandler
+            = std::make_unique<jami::TranscriptMediaHandler>(std::move(dataPath),
+                                                             fmpPluginPreferenceHandler.get());
+    fmpPluginPreferenceHandler->setTranscriptHandler(fmpTranscriptMediaHandler.get());
+
+    auto subject = std::make_shared<jami::PublishObservable<AVFrame*>>();
+
+    // Valid Read frames from audio sample file and send to subscriber
+    fmpTranscriptMediaHandler->notifyAVFrameSubject(StreamData("testCall",
+                                                               true,
+                                                               StreamType::audio,
+                                                               "origin",
+                                                               "destiny"),
+                                                    subject);
+    av_utils::readAndNotifyAVFrame(preferences["default"]["audiosample"],
+                                   subject.get(),
+                                   preferences["default"]["audiooutput"],
+                                   AVMEDIA_TYPE_AUDIO);
+
+    // Valid Read frames from video sample file and send to subscriber
+    fmpTranscriptMediaHandler->notifyAVFrameSubject(StreamData("testCall",
+                                                               true,
+                                                               StreamType::video,
+                                                               "origin",
+                                                               "destiny"),
+                                                    subject);
+    av_utils::readAndNotifyAVFrame(preferences["default"]["videosample"],
+                                   subject.get(),
+                                   preferences["default"]["videooutput"],
+                                   AVMEDIA_TYPE_VIDEO);
+
+    return 0;
+}
+
+#endif
diff --git a/WhisperTranscript/manifest.json b/WhisperTranscript/manifest.json
new file mode 100644
index 0000000..ae1e2b6
--- /dev/null
+++ b/WhisperTranscript/manifest.json
@@ -0,0 +1,5 @@
+{
+    "name": "WhisperTranscript",
+    "description": "Transcribe your calls if they are recorded",
+    "version": "0.0.0"
+}
\ No newline at end of file
diff --git a/WhisperTranscript/modelSRC/mLogSoftMax.onnx b/WhisperTranscript/modelSRC/mLogSoftMax.onnx
new file mode 100644
index 0000000..2f90b73
--- /dev/null
+++ b/WhisperTranscript/modelSRC/mLogSoftMax.onnx
Binary files differ
diff --git a/WhisperTranscript/modelSRC/mModelDecoder.onnx b/WhisperTranscript/modelSRC/mModelDecoder.onnx
new file mode 100644
index 0000000..323114d
--- /dev/null
+++ b/WhisperTranscript/modelSRC/mModelDecoder.onnx
Binary files differ
diff --git a/WhisperTranscript/modelSRC/mModelDecoder.ort b/WhisperTranscript/modelSRC/mModelDecoder.ort
new file mode 100644
index 0000000..dca38b7
--- /dev/null
+++ b/WhisperTranscript/modelSRC/mModelDecoder.ort
Binary files differ
diff --git a/WhisperTranscript/modelSRC/mModelEncoder.onnx b/WhisperTranscript/modelSRC/mModelEncoder.onnx
new file mode 100644
index 0000000..5da3279
--- /dev/null
+++ b/WhisperTranscript/modelSRC/mModelEncoder.onnx
Binary files differ
diff --git a/WhisperTranscript/modelSRC/mModelEncoder.ort b/WhisperTranscript/modelSRC/mModelEncoder.ort
new file mode 100644
index 0000000..abc7d9b
--- /dev/null
+++ b/WhisperTranscript/modelSRC/mModelEncoder.ort
Binary files differ
diff --git a/WhisperTranscript/package.json b/WhisperTranscript/package.json
new file mode 100644
index 0000000..72acbc7
--- /dev/null
+++ b/WhisperTranscript/package.json
@@ -0,0 +1,21 @@
+{
+    "name": "WhisperTranscript",
+    "version": "0.0.0",
+    "extractLibs": false,
+    "deps": [
+        "fmt"
+    ],
+    "defines": [
+        "NVIDIA=False",
+        "TESTPROCESS=False"
+    ],
+    "custom_scripts": {
+        "pre_build": [
+            "mkdir msvc"
+        ],
+        "build": [
+            "cmake --build ./msvc --config Release"
+        ],
+        "post_build": []
+    }
+}
\ No newline at end of file
diff --git a/WhisperTranscript/sample.mp4 b/WhisperTranscript/sample.mp4
new file mode 100644
index 0000000..f71fcb8
--- /dev/null
+++ b/WhisperTranscript/sample.mp4
Binary files differ
diff --git a/WhisperTranscript/testPreferences.yml b/WhisperTranscript/testPreferences.yml
new file mode 100644
index 0000000..eeb3a6c
--- /dev/null
+++ b/WhisperTranscript/testPreferences.yml
@@ -0,0 +1,9 @@
+avstream: "in"
+audiosample: "jami.wav"
+videosample: "sample.mp4"
+audiooutput: ""
+videooutput: "processed.mp4"
+subtitle: " "
+background: "black@0.0"
+position: "2"
+fontsize: "36"
\ No newline at end of file
diff --git a/WhisperTranscript/zlib/libzlib.vcxproj b/WhisperTranscript/zlib/libzlib.vcxproj
new file mode 100644
index 0000000..81f9634
--- /dev/null
+++ b/WhisperTranscript/zlib/libzlib.vcxproj
@@ -0,0 +1,918 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="DebugDLL|Win32">
+      <Configuration>DebugDLL</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="DebugDLL|x64">
+      <Configuration>DebugDLL</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="ReleaseDLL|Win32">
+      <Configuration>ReleaseDLL</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="ReleaseDLL|x64">
+      <Configuration>ReleaseDLL</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="ReleaseLTO|Win32">
+      <Configuration>ReleaseLTO</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="ReleaseLTO|x64">
+      <Configuration>ReleaseLTO</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{CA9A4A38-CC63-4BDB-8CFB-E058965DDA32}</ProjectGuid>
+    <RootNamespace>libzlib</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>libzlibd</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>libzlib</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|Win32'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>libzlib</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>zlib</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>zlibd</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>libzlibd</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>libzlib</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|x64'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>libzlib</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|x64'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>zlib</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'">
+    <OutDir>$(ProjectDir)..\..\..\msvc\</OutDir>
+    <IntDir>$(SolutionDir)obj\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <TargetName>zlibd</TargetName>
+    <CustomBuildAfterTargets>Clean</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_WIN32_WINNT=0x0502;_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
+      <MinimalRebuild>false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
+    </Lib>
+    <Lib>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Lib>
+    <Lib>
+      <SubSystem>Windows</SubSystem>
+    </Lib>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN64;_WIN32_WINNT=0x0600;_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
+      <MinimalRebuild>false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
+    </Lib>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_WIN32_WINNT=0x0502;_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+      <MinimalRebuild>false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <ImportLibrary>$(OutDir)\lib\x86\$(TargetName).lib</ImportLibrary>
+      <SubSystem>Windows</SubSystem>
+      <ProfileGuidedDatabase>$(IntDir)\$(TargetName).pgd</ProfileGuidedDatabase>
+      <ProgramDatabaseFile>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDatabaseFile>
+      <OutputFile>$(OutDir)\bin\x86\$(TargetName)$(TargetExt)</OutputFile>
+      <ModuleDefinitionFile>..\contrib\vstudio\vc11\zlibvc.def</ModuleDefinitionFile>
+      <LargeAddressAware>true</LargeAddressAware>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <MinimumRequiredVersion>5.1</MinimumRequiredVersion>
+    </Link>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugDLL|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN64;_WIN32_WINNT=0x0600;_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+      <MinimalRebuild>false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)\bin\x64\$(TargetName)$(TargetExt)</OutputFile>
+      <ProgramDatabaseFile>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDatabaseFile>
+      <SubSystem>Windows</SubSystem>
+      <ProfileGuidedDatabase>$(IntDir)\$(TargetName).pgd</ProfileGuidedDatabase>
+      <ImportLibrary>$(OutDir)\lib\x64\$(TargetName).lib</ImportLibrary>
+      <ModuleDefinitionFile>..\contrib\vstudio\vc11\zlibvc.def</ModuleDefinitionFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <MinimumRequiredVersion>6.0</MinimumRequiredVersion>
+    </Link>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+      <StringPooling>true</StringPooling>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <InterproceduralOptimization>SingleFile</InterproceduralOptimization>
+      <ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Lib>
+      <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
+    </Lib>
+    <Lib>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Lib>
+    <Lib>
+      <SubSystem>Windows</SubSystem>
+    </Lib>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+      <StringPooling>true</StringPooling>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <InterproceduralOptimization>SingleFile</InterproceduralOptimization>
+      <ProgramDataBaseFileName>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDataBaseFileName>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Lib>
+      <OutputFile>$(OutDir)\lib\x86\$(TargetName)$(TargetExt)</OutputFile>
+    </Lib>
+    <Lib>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Lib>
+    <Lib>
+      <SubSystem>Windows</SubSystem>
+    </Lib>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN64;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+      <StringPooling>true</StringPooling>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <InterproceduralOptimization>SingleFile</InterproceduralOptimization>
+      <ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Lib>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
+    </Lib>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTO|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN64;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+      <StringPooling>true</StringPooling>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <InterproceduralOptimization>SingleFile</InterproceduralOptimization>
+      <ProgramDataBaseFileName>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDataBaseFileName>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+    <Lib>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\lib\x64\$(TargetName)$(TargetExt)</OutputFile>
+    </Lib>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+      <StringPooling>true</StringPooling>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+    </ClCompile>
+    <Link>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ImportLibrary>$(OutDir)\lib\x86\$(TargetName).lib</ImportLibrary>
+      <SubSystem>Windows</SubSystem>
+      <ProfileGuidedDatabase>$(IntDir)\$(TargetName).pgd</ProfileGuidedDatabase>
+      <ProgramDatabaseFile>$(OutDir)\lib\x86\$(TargetName).pdb</ProgramDatabaseFile>
+      <OutputFile>$(OutDir)\bin\x86\$(TargetName)$(TargetExt)</OutputFile>
+      <ModuleDefinitionFile>..\contrib\vstudio\vc11\zlibvc.def</ModuleDefinitionFile>
+      <LargeAddressAware>true</LargeAddressAware>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <MinimumRequiredVersion>5.1</MinimumRequiredVersion>
+    </Link>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN64;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
+      <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+      <StringPooling>true</StringPooling>
+      <AdditionalIncludeDirectories>.\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+    </ClCompile>
+    <Link>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <OutputFile>$(OutDir)\bin\x64\$(TargetName)$(TargetExt)</OutputFile>
+      <ProgramDatabaseFile>$(OutDir)\lib\x64\$(TargetName).pdb</ProgramDatabaseFile>
+      <SubSystem>Windows</SubSystem>
+      <ProfileGuidedDatabase>$(IntDir)\$(TargetName).pgd</ProfileGuidedDatabase>
+      <ImportLibrary>$(OutDir)\lib\x64\$(TargetName).lib</ImportLibrary>
+      <ModuleDefinitionFile>..\contrib\vstudio\vc11\zlibvc.def</ModuleDefinitionFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <MinimumRequiredVersion>6.0</MinimumRequiredVersion>
+    </Link>
+    <MASM>
+      <UseSafeExceptionHandlers>true</UseSafeExceptionHandlers>
+    </MASM>
+    <PostBuildEvent>
+      <Command>mkdir "$(OutDir)"\include
+copy ..\zlib.h "$(OutDir)"\include
+copy "$(OutDir)"\..\src\zlib\zconf.h "$(OutDir)"\include /Y
+copy "$(OutDir)"\lib\$(Platform)\libzlib.lib "$(OutDir)"\lib\$(Platform)\zlib.lib /Y
+mkdir $(OutDir)\licenses
+copy ..\README $(OutDir)\licenses\zlib.txt</Command>
+    </PostBuildEvent>
+    <PreBuildEvent>
+      <Command>if exist ..\zconf.h (
+del ..\zconf.h
+)
+if exist "$(OutDir)"\include\zlib.h (
+del "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del "$(OutDir)"\include\zconf.h
+)</Command>
+    </PreBuildEvent>
+    <CustomBuildStep>
+      <Message>Custom Clean Step</Message>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>force_clean</Outputs>
+      <Command>if exist "$(OutDir)"\include\zlib.h (
+del /f /q "$(OutDir)"\include\zlib.h
+)
+if exist "$(OutDir)"\include\zconf.h (
+del /f /q "$(OutDir)"\include\zconf.h
+)
+if exist $(OutDir)\licenses\zlib.txt (
+del /f /q $(OutDir)\licenses\zlib.txt
+)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\adler32.c" />
+    <ClCompile Include="..\compress.c" />
+    <ClCompile Include="..\crc32.c" />
+    <ClCompile Include="..\deflate.c" />
+    <ClCompile Include="..\gzclose.c" />
+    <ClCompile Include="..\gzlib.c" />
+    <ClCompile Include="..\gzread.c" />
+    <ClCompile Include="..\gzwrite.c" />
+    <ClCompile Include="..\infback.c" />
+    <ClCompile Include="..\inffast.c" />
+    <ClCompile Include="..\inflate.c" />
+    <ClCompile Include="..\inftrees.c" />
+    <ClCompile Include="..\trees.c" />
+    <ClCompile Include="..\uncompr.c" />
+    <ClCompile Include="..\zutil.c" />
+    <ClCompile Include="..\contrib\minizip\ioapi.c" />
+    <ClCompile Include="..\contrib\minizip\iowin32.c">
+      <ExcludedFromBuild Condition="'$(Configuration)'=='Debug'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)'=='Release'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)'=='ReleaseLTO'">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="..\contrib\minizip\unzip.c" />
+    <ClCompile Include="..\contrib\minizip\zip.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\crc32.h" />
+    <ClInclude Include="..\deflate.h" />
+    <ClInclude Include="..\inffast.h" />
+    <ClInclude Include="..\inffixed.h" />
+    <ClInclude Include="..\inflate.h" />
+    <ClInclude Include="..\inftrees.h" />
+    <ClInclude Include="..\trees.h" />
+    <ClInclude Include="..\zlib.h" />
+    <ClInclude Include="..\zutil.h" />
+    <ClInclude Include="..\contrib\minizip\ioapi.h" />
+    <ClInclude Include="..\contrib\minizip\unzip.h" />
+    <ClInclude Include="..\contrib\minizip\zip.h" />
+    <ClInclude Include="zconf.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="..\contrib\vstudio\vc11\zlib.rc">
+      <ExcludedFromBuild Condition="'$(Configuration)'=='Debug'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)'=='Release'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)'=='ReleaseLTO'">true</ExcludedFromBuild>
+    </ResourceCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\contrib\vstudio\vc11\zlibvc.def" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+</Project>
diff --git a/WhisperTranscript/zlib/package.json b/WhisperTranscript/zlib/package.json
new file mode 100644
index 0000000..fdfec5e
--- /dev/null
+++ b/WhisperTranscript/zlib/package.json
@@ -0,0 +1,17 @@
+{
+    "name": "zlib",
+    "version": "8e4e3ead55cdd296130242d86b44b92fde3ea4d4",
+    "url": "https://github.com/ShiftMediaProject/zlib/archive/__VERSION__.tar.gz",
+    "deps": [],
+    "patches": [],
+    "win_patches": [],
+    "project_paths": [
+        "SMP/libzlib.vcxproj"
+    ],
+    "with_env" : "",
+    "custom_scripts": {
+        "pre_build": ["copy %cd%\\\\..\\\\..\\\\src\\\\zlib\\\\libzlib.vcxproj %cd%\\\\SMP\\\\libzlib.vcxproj /Y"],
+        "build": [],
+        "post_build": []
+    }
+}
diff --git a/WhisperTranscript/zlib/zconf.h b/WhisperTranscript/zlib/zconf.h
new file mode 100644
index 0000000..df47fef
--- /dev/null
+++ b/WhisperTranscript/zlib/zconf.h
@@ -0,0 +1,519 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
+#define Z_PREFIX_SET
+
+/* all linked symbols and init macros */
+#define _dist_code        z__dist_code
+#define _length_code      z__length_code
+#define _tr_align         z__tr_align
+#define _tr_flush_bits    z__tr_flush_bits
+#define _tr_flush_block   z__tr_flush_block
+#define _tr_init          z__tr_init
+#define _tr_stored_block  z__tr_stored_block
+#define _tr_tally         z__tr_tally
+#define adler32           z_adler32
+#define adler32_combine   z_adler32_combine
+#define adler32_combine64 z_adler32_combine64
+#define adler32_z         z_adler32_z
+#ifndef Z_SOLO
+#define compress      z_compress
+#define compress2     z_compress2
+#define compressBound z_compressBound
+#endif
+#define crc32                z_crc32
+#define crc32_combine        z_crc32_combine
+#define crc32_combine64      z_crc32_combine64
+#define crc32_z              z_crc32_z
+#define deflate              z_deflate
+#define deflateBound         z_deflateBound
+#define deflateCopy          z_deflateCopy
+#define deflateEnd           z_deflateEnd
+#define deflateGetDictionary z_deflateGetDictionary
+#define deflateInit          z_deflateInit
+#define deflateInit2         z_deflateInit2
+#define deflateInit2_        z_deflateInit2_
+#define deflateInit_         z_deflateInit_
+#define deflateParams        z_deflateParams
+#define deflatePending       z_deflatePending
+#define deflatePrime         z_deflatePrime
+#define deflateReset         z_deflateReset
+#define deflateResetKeep     z_deflateResetKeep
+#define deflateSetDictionary z_deflateSetDictionary
+#define deflateSetHeader     z_deflateSetHeader
+#define deflateTune          z_deflateTune
+#define deflate_copyright    z_deflate_copyright
+#define get_crc_table        z_get_crc_table
+#ifndef Z_SOLO
+#define gz_error       z_gz_error
+#define gz_intmax      z_gz_intmax
+#define gz_strwinerror z_gz_strwinerror
+#define gzbuffer       z_gzbuffer
+#define gzclearerr     z_gzclearerr
+#define gzclose        z_gzclose
+#define gzclose_r      z_gzclose_r
+#define gzclose_w      z_gzclose_w
+#define gzdirect       z_gzdirect
+#define gzdopen        z_gzdopen
+#define gzeof          z_gzeof
+#define gzerror        z_gzerror
+#define gzflush        z_gzflush
+#define gzfread        z_gzfread
+#define gzfwrite       z_gzfwrite
+#define gzgetc         z_gzgetc
+#define gzgetc_        z_gzgetc_
+#define gzgets         z_gzgets
+#define gzoffset       z_gzoffset
+#define gzoffset64     z_gzoffset64
+#define gzopen         z_gzopen
+#define gzopen64       z_gzopen64
+#ifdef _WIN32
+#define gzopen_w z_gzopen_w
+#endif
+#define gzprintf    z_gzprintf
+#define gzputc      z_gzputc
+#define gzputs      z_gzputs
+#define gzread      z_gzread
+#define gzrewind    z_gzrewind
+#define gzseek      z_gzseek
+#define gzseek64    z_gzseek64
+#define gzsetparams z_gzsetparams
+#define gztell      z_gztell
+#define gztell64    z_gztell64
+#define gzungetc    z_gzungetc
+#define gzvprintf   z_gzvprintf
+#define gzwrite     z_gzwrite
+#endif
+#define inflate              z_inflate
+#define inflateBack          z_inflateBack
+#define inflateBackEnd       z_inflateBackEnd
+#define inflateBackInit      z_inflateBackInit
+#define inflateBackInit_     z_inflateBackInit_
+#define inflateCodesUsed     z_inflateCodesUsed
+#define inflateCopy          z_inflateCopy
+#define inflateEnd           z_inflateEnd
+#define inflateGetDictionary z_inflateGetDictionary
+#define inflateGetHeader     z_inflateGetHeader
+#define inflateInit          z_inflateInit
+#define inflateInit2         z_inflateInit2
+#define inflateInit2_        z_inflateInit2_
+#define inflateInit_         z_inflateInit_
+#define inflateMark          z_inflateMark
+#define inflatePrime         z_inflatePrime
+#define inflateReset         z_inflateReset
+#define inflateReset2        z_inflateReset2
+#define inflateResetKeep     z_inflateResetKeep
+#define inflateSetDictionary z_inflateSetDictionary
+#define inflateSync          z_inflateSync
+#define inflateSyncPoint     z_inflateSyncPoint
+#define inflateUndermine     z_inflateUndermine
+#define inflateValidate      z_inflateValidate
+#define inflate_copyright    z_inflate_copyright
+#define inflate_fast         z_inflate_fast
+#define inflate_table        z_inflate_table
+#ifndef Z_SOLO
+#define uncompress  z_uncompress
+#define uncompress2 z_uncompress2
+#endif
+#define zError z_zError
+#ifndef Z_SOLO
+#define zcalloc z_zcalloc
+#define zcfree  z_zcfree
+#endif
+#define zlibCompileFlags z_zlibCompileFlags
+#define zlibVersion      z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#define Byte       z_Byte
+#define Bytef      z_Bytef
+#define alloc_func z_alloc_func
+#define charf      z_charf
+#define free_func  z_free_func
+#ifndef Z_SOLO
+#define gzFile z_gzFile
+#endif
+#define gz_header  z_gz_header
+#define gz_headerp z_gz_headerp
+#define in_func    z_in_func
+#define intf       z_intf
+#define out_func   z_out_func
+#define uInt       z_uInt
+#define uIntf      z_uIntf
+#define uLong      z_uLong
+#define uLongf     z_uLongf
+#define voidp      z_voidp
+#define voidpc     z_voidpc
+#define voidpf     z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#define gz_header_s    z_gz_header_s
+#define internal_state z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#ifndef WIN32
+#define WIN32
+#endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#ifndef SYS16BIT
+#define SYS16BIT
+#endif
+#endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#ifndef STDC
+#define STDC
+#endif
+#if __STDC_VERSION__ >= 199901L
+#ifndef STDC99
+#define STDC99
+#endif
+#endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+#define STDC
+#endif
+
+#ifndef STDC
+#ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#define const /* note: need a more gentle solution here */
+#endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#define z_const const
+#else
+#define z_const
+#endif
+
+#ifdef Z_SOLO
+typedef unsigned long z_size_t;
+#else
+#define z_longlong long long
+#if defined(NO_SIZE_T)
+typedef unsigned NO_SIZE_T z_size_t;
+#elif defined(STDC)
+#include <stddef.h>
+typedef size_t z_size_t;
+#else
+typedef unsigned long z_size_t;
+#endif
+#undef z_longlong
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#ifdef MAXSEG_64K
+#define MAX_MEM_LEVEL 8
+#else
+#define MAX_MEM_LEVEL 9
+#endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
+ for small objects.
+*/
+
+/* Type declarations */
+
+#ifndef OF /* function prototypes */
+#ifdef STDC
+#define OF(args) args
+#else
+#define OF(args) ()
+#endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#define Z_ARG(args) args
+#else
+#define Z_ARG(args) ()
+#endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#if defined(M_I86SM) || defined(M_I86MM)
+/* MSC small or medium model */
+#define SMALL_MEDIUM
+#ifdef _MSC_VER
+#define FAR _far
+#else
+#define FAR far
+#endif
+#endif
+#if (defined(__SMALL__) || defined(__MEDIUM__))
+/* Turbo C small or medium model */
+#define SMALL_MEDIUM
+#ifdef __BORLANDC__
+#define FAR _far
+#else
+#define FAR far
+#endif
+#endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+/* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+#ifdef ZLIB_DLL
+#if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#ifdef ZLIB_INTERNAL
+#define ZEXTERN extern __declspec(dllexport)
+#else
+#define ZEXTERN extern __declspec(dllimport)
+#endif
+#endif
+#endif /* ZLIB_DLL */
+       /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+        * define ZLIB_WINAPI.
+        * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+        */
+#ifdef ZLIB_WINAPI
+#ifdef FAR
+#undef FAR
+#endif
+#include <windows.h>
+/* No need for _export, use ZLIB.DEF instead. */
+/* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#define ZEXPORT WINAPI
+#ifdef WIN32
+#define ZEXPORTVA WINAPIV
+#else
+#define ZEXPORTVA FAR CDECL
+#endif
+#endif
+#endif
+
+#if defined(__BEOS__)
+#ifdef ZLIB_DLL
+#ifdef ZLIB_INTERNAL
+#define ZEXPORT   __declspec(dllexport)
+#define ZEXPORTVA __declspec(dllexport)
+#else
+#define ZEXPORT   __declspec(dllimport)
+#define ZEXPORTVA __declspec(dllimport)
+#endif
+#endif
+#endif
+
+#ifndef ZEXTERN
+#define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt;   /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#define Bytef Byte FAR
+#else
+typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+typedef void const* voidpc;
+typedef void FAR* voidpf;
+typedef void* voidp;
+#else
+typedef Byte const* voidpc;
+typedef Byte FAR* voidpf;
+typedef Byte* voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#include <limits.h>
+#if (UINT_MAX == 0xffffffffUL)
+#define Z_U4 unsigned
+#elif (ULONG_MAX == 0xffffffffUL)
+#define Z_U4 unsigned long
+#elif (USHRT_MAX == 0xffffffffUL)
+#define Z_U4 unsigned short
+#endif
+#endif
+
+#ifdef Z_U4
+typedef Z_U4 z_crc_t;
+#else
+typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
+#define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#ifndef Z_SOLO
+#include <sys/types.h> /* for off_t */
+#endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#ifndef Z_SOLO
+#include <stdarg.h> /* for va_list */
+#endif
+#endif
+
+#ifdef _WIN32
+#ifndef Z_SOLO
+#include <stddef.h> /* for wchar_t */
+#endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#define Z_HAVE_UNISTD_H
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE - 0
+#define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS - 0 == 64 && defined(Z_LFS64)
+#define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#define SEEK_SET 0 /* Seek from beginning of file.  */
+#define SEEK_CUR 1 /* Seek from current position.  */
+#define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#define z_off64_t off64_t
+#else
+#if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#define z_off64_t __int64
+#else
+#define z_off64_t z_off_t
+#endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#pragma map(deflateInit_, "DEIN")
+#pragma map(deflateInit2_, "DEIN2")
+#pragma map(deflateEnd, "DEEND")
+#pragma map(deflateBound, "DEBND")
+#pragma map(inflateInit_, "ININ")
+#pragma map(inflateInit2_, "ININ2")
+#pragma map(inflateEnd, "INEND")
+#pragma map(inflateSync, "INSY")
+#pragma map(inflateSetDictionary, "INSEDI")
+#pragma map(compressBound, "CMBND")
+#pragma map(inflate_table, "INTABL")
+#pragma map(inflate_fast, "INFA")
+#pragma map(inflate_copyright, "INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/lib/AVFrameIO.h b/lib/AVFrameIO.h
index 85d17c0..7f0006c 100644
--- a/lib/AVFrameIO.h
+++ b/lib/AVFrameIO.h
@@ -182,19 +182,21 @@
     AVCodecContext* encCodecCtx;
     AVFormatContext* encFormatCtx;
     AVStream* encStream;
-    const AVCodec* encCodec = openEncoder(encCodecCtx, decCodecCtx, encFormatCtx, encStream, rFile, decStream, mediaType);
-    if (!encCodec) {
-        avcodec_close(decCodecCtx);
-        avcodec_free_context(&decCodecCtx);
-        avformat_close_input(&decFormatCtx);
-        avformat_free_context(decFormatCtx);
+    if (!rFile.empty()) {
+        const AVCodec* encCodec = openEncoder(encCodecCtx, decCodecCtx, encFormatCtx, encStream, rFile, decStream, mediaType);
+        if (!encCodec) {
+            avcodec_close(decCodecCtx);
+            avcodec_free_context(&decCodecCtx);
+            avformat_close_input(&decFormatCtx);
+            avformat_free_context(decFormatCtx);
 
-        avio_closep(&encFormatCtx->pb);
-        avcodec_close(encCodecCtx);
-        avcodec_free_context(&encCodecCtx);
-        avformat_close_input(&encFormatCtx);
-        avformat_free_context(encFormatCtx);
-        return;
+            avio_closep(&encFormatCtx->pb);
+            avcodec_close(encCodecCtx);
+            avcodec_free_context(&encCodecCtx);
+            avformat_close_input(&encFormatCtx);
+            avformat_free_context(encFormatCtx);
+            return;
+        }
     }
 
     AVPacket* packet = av_packet_alloc();
@@ -217,29 +219,32 @@
                 pFrame->time_base.den = decCodecCtx->framerate.num;
                 subject->publish(pFrame);
 
-                // Send frame to encoder
-                if (avcodec_send_frame(encCodecCtx, pFrame) < 0) {
-                    break;
-                }
+                if (!rFile.empty()) {
+                    // Send frame to encoder
+                    if (avcodec_send_frame(encCodecCtx, pFrame) < 0) {
+                        break;
+                    }
 
-                // Read packet from encoder
-                AVPacket *enc_pkt = av_packet_alloc();
-                while (avcodec_receive_packet(encCodecCtx, enc_pkt) == 0) {
-                    enc_pkt->stream_index = 0; // 0 -> we only created one stream in the encoder
-                    av_packet_rescale_ts(enc_pkt,
-                                        encCodecCtx->time_base,
-                                        encFormatCtx->streams[0]->time_base);
+                    // Read packet from encoder
+                    AVPacket *enc_pkt = av_packet_alloc();
+                    while (avcodec_receive_packet(encCodecCtx, enc_pkt) == 0) {
+                        enc_pkt->stream_index = 0; // 0 -> we only created one stream in the encoder
+                        av_packet_rescale_ts(enc_pkt,
+                                            encCodecCtx->time_base,
+                                            encFormatCtx->streams[0]->time_base);
 
-                    av_interleaved_write_frame(encFormatCtx, enc_pkt);
+                        av_interleaved_write_frame(encFormatCtx, enc_pkt);
+                    }
+                    av_packet_unref(enc_pkt);
+                    av_packet_free(&enc_pkt);
                 }
-                av_packet_unref(enc_pkt);
-                av_packet_free(&enc_pkt);
             }
         }
         av_packet_unref(packet);
     }
 
-    av_write_trailer(encFormatCtx);
+    if (!rFile.empty())
+        av_write_trailer(encFormatCtx);
 
     av_frame_unref(pFrame);
     av_frame_free(&pFrame);
@@ -251,10 +256,12 @@
     avformat_close_input(&decFormatCtx);
     avformat_free_context(decFormatCtx);
 
-    avio_closep(&encFormatCtx->pb);
-    avcodec_close(encCodecCtx);
-    avcodec_free_context(&encCodecCtx);
-    avformat_close_input(&encFormatCtx);
-    avformat_free_context(encFormatCtx);
+    if (!rFile.empty()) {
+        avio_closep(&encFormatCtx->pb);
+        avcodec_close(encCodecCtx);
+        avcodec_free_context(&encCodecCtx);
+        avformat_close_input(&encFormatCtx);
+        avformat_free_context(encFormatCtx);
+    }
 }
 } //av_utils
diff --git a/lib/common.cpp b/lib/common.cpp
index 0c088bc..fdd37ea 100644
--- a/lib/common.cpp
+++ b/lib/common.cpp
@@ -54,12 +54,44 @@
 #endif
 }
 
+void ffmpegScapeStringInline(std::string& str)
+{
+    std::string newStr;
+    for (size_t i = 0; i < str.size(); i ++) {
+        switch (str[i]) {
+            case '\'':
+                newStr.append("´");
+                break;
+            case '%':
+                newStr.append("\\%");
+                break;
+            case ':':
+                newStr.append("\\:");
+                break;
+            case '\\':
+                newStr.append("\\\\");
+                break;
+            default:
+                newStr.insert(newStr.end(), str[i]);
+                break;
+        }
+    }
+    std::swap(newStr, str);
+}
+
 std::string ffmpegFormatString(const std::string& str)
 {
     std::string ret = str;
     ffmpegFormatStringInline(ret);
     return ret;
 }
+
+std::string ffmpegScapeString(const std::string& str)
+{
+    std::string ret = str;
+    ffmpegScapeStringInline(ret);
+    return ret;
+}
 } // namespace string_utils
 
 namespace file_utils {
diff --git a/lib/common.h b/lib/common.h
index 4f0858f..d7ebde9 100644
--- a/lib/common.h
+++ b/lib/common.h
@@ -30,6 +30,8 @@
 #endif // WIN32
 void ffmpegFormatStringInline(std::string& str);
 std::string ffmpegFormatString(const std::string& str);
+void ffmpegScapeStringInline(std::string& str);
+std::string ffmpegScapeString(const std::string& str);
 } // namespace string_utils
 
 namespace file_utils {
diff --git a/lib/frameFilter.h b/lib/frameFilter.h
index 29fedc1..96b9caa 100644
--- a/lib/frameFilter.h
+++ b/lib/frameFilter.h
@@ -104,7 +104,7 @@
      * @brief Frees resources used by FrameFilter.
      */
     void clean();
-    
+
     /**
      * @brief Flag to know whether or not the filter graph is initialized.
      */