diff --git a/.tx/config b/.tx/config index 3be6740469f4965c54b8d387c91525e830428712..db5203008cf6676590d5b2760d1250b0069cfc0f 100755 --- a/.tx/config +++ b/.tx/config @@ -25,3 +25,9 @@ source_file = AudioFilter/data/locale/AudioFilter_en.json 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 02a0e0636cccc89c0060d08a88f64b7756247edc..cb18408f9aa5a2285f11c0f6e5430f7782268182 100644 --- a/AudioFilter/FilterMediaHandler.cpp +++ b/AudioFilter/FilterMediaHandler.cpp @@ -57,12 +57,12 @@ FilterMediaHandler::notifyAVFrameSubject(const StreamData& data, jami::avSubject 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 d4677ed028dc115cf3a7c841d83b48165ee669c9..6401be9166cc634e98b877a4fff9cea5ab3df56a 100644 --- a/GreenScreen/CMakeLists.txt +++ b/GreenScreen/CMakeLists.txt @@ -118,6 +118,7 @@ add_custom_command( 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 @@ if(TESTPROCESS) 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 df7edd378601740c3350b26352c6671be97a4851..ba8f485b5175f42c70612988bd66fb62515c6940 100644 --- a/GreenScreen/videoSubscriber.h +++ b/GreenScreen/videoSubscriber.h @@ -33,15 +33,15 @@ extern "C" { 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 29481f776cd36cbe2348a61ee34835b77b535683..f8f11a5d5a406e92bd56d226edbb50d498e9933b 100644 --- a/HelloWorld/CenterCircleVideoSubscriber.h +++ b/HelloWorld/CenterCircleVideoSubscriber.h @@ -28,15 +28,15 @@ extern "C" { 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 373f0b8007f7a0ac42022021584ce67b0d2c2045..c355cab22f3321e7c930040757eae279da2adbcb 100644 --- a/HelloWorld/CoinCircleVideoSubscriber.h +++ b/HelloWorld/CoinCircleVideoSubscriber.h @@ -28,15 +28,15 @@ extern "C" { 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 6c23c1605d0e4c587c990ae6ab3197333254838a..7f618026e86e513e246cd3181dda8adf42debca5 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 @@ done 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 109ec71d05bf5d632c22a56ee38058345deb6f79..825cb1ca32e0f9074f1f843f0e8bc7624caa7ade 100644 --- a/SDK/Templates/genericMediaHandler.cpp +++ b/SDK/Templates/genericMediaHandler.cpp @@ -32,12 +32,12 @@ GENERICMediaHandler::notifyAVFrameSubject(const StreamData& data, jami::avSubjec 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 2e806b9605400a0d2bffc44703cff8bb8aa9f583..50409a7c7e9d45790ebb447435116729210162cb 100644 --- a/SDK/Templates/genericMediaHandler.h +++ b/SDK/Templates/genericMediaHandler.h @@ -7,11 +7,11 @@ HEADER #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 c716844dd4f54c8ad4e6a13290ee687a2d73c0a1..2e86975c736646ae9e1af7e9667cfbfff759b991 100644 --- a/SDK/Templates/genericMediaSubscriber.h +++ b/SDK/Templates/genericMediaSubscriber.h @@ -11,15 +11,15 @@ extern "C" { 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 abca25bd47e5d7f4f8eeaa2cf236b32259c43bf7..436601ed3f58ecf571346169803944ca97e87787 100644 --- a/SDK/Templates/main.cpp +++ b/SDK/Templates/main.cpp @@ -8,6 +8,14 @@ HEADER ---------------- #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 @@ JAMI_dynPluginInit(const JAMI_PluginAPI* api) 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 ddeb35462d757f82aec322678242f9ecd5803961..1c356736bec0a4a123f6e813fb92ef4ed7e5039d 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 8f37c54d9012bab1a1251d30986961fc4b025d27..51949f24f09a6e1d05512cac697262bfc04962dc 100644 --- a/TensorflowSegmentation/videoSubscriber.h +++ b/TensorflowSegmentation/videoSubscriber.h @@ -51,15 +51,15 @@ public: 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 49d5ca7f3f6adf123f733110649bc91993a01e9e..794637e9aceae14688ccaca4955a22ffd79f4591 100644 --- a/TestSuite/VideoSubscriberTester.h +++ b/TestSuite/VideoSubscriberTester.h @@ -27,15 +27,15 @@ extern "C" { 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 aff84f76298dda0b6d0e13f44ec6af03c65df393..1071671e753bc47b2a80236a1834ff478590d1f7 100644 --- a/WaterMark/CMakeLists.txt +++ b/WaterMark/CMakeLists.txt @@ -99,6 +99,7 @@ add_custom_command( 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 311d9332757f9e99d29c2ad506206bdf62f35eef..db0417a5e1cfcd8c8aabb22c5a89a2cfb7fccfbb 100644 --- a/WaterMark/WatermarkVideoSubscriber.h +++ b/WaterMark/WatermarkVideoSubscriber.h @@ -48,15 +48,15 @@ enum Parameter { 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 0000000000000000000000000000000000000000..5a3f9269e55b16187bfdcdd4dbf78a1e04733add --- /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 0000000000000000000000000000000000000000..db5f4163b3fb2fdad8dfbec59cdff2b1c021f03f --- /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 0000000000000000000000000000000000000000..6c0a7b8f01ee9d6e799e5fc20ce48be399204a36 --- /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 0000000000000000000000000000000000000000..4a2ad17aafe38c36ffdc70b2620187aef5106e50 --- /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 0000000000000000000000000000000000000000..202f70db7a61a825a187315b104cda2464289063 --- /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 0000000000000000000000000000000000000000..a45e12b14cad3e7a1a9cfc0c117671f031c6392e --- /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 0000000000000000000000000000000000000000..706c44f18c87c28048ad52c47bff091da70d228c --- /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 0000000000000000000000000000000000000000..455a96ee057c1c52caf80a5bb050db2f5e4ead00 --- /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 0000000000000000000000000000000000000000..d341671346db9b259f2c4b315c730488f490b403 --- /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 0000000000000000000000000000000000000000..b9b717ea87b362343d20ab02e173f257fa2001fd --- /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 0000000000000000000000000000000000000000..3e30733d054fa8544a55f1c428ff0f4fbf03b7be --- /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 0000000000000000000000000000000000000000..9191dffe950513c71908c6a7642289ef63e605b3 --- /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 0000000000000000000000000000000000000000..d17bc2b1d89f985b6aa81cc208cf1c9b128989c6 --- /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 0000000000000000000000000000000000000000..4d9087c8280e1a80bff2670d40857572fa1c472a --- /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 0000000000000000000000000000000000000000..8acf280bb14e5263749847ac9687139d19ea8177 --- /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 0000000000000000000000000000000000000000..0ffcfba2e8bfeea6944bfbba39447991daeffc97 Binary files /dev/null and b/WhisperTranscript/data/Muli-Light.ttf differ diff --git a/WhisperTranscript/data/accountpreferences.json b/WhisperTranscript/data/accountpreferences.json new file mode 100644 index 0000000000000000000000000000000000000000..a5a6a365810296517a01b689afd69e6d49f93caa --- /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 0000000000000000000000000000000000000000..e1a699ac37f449b6c2b99d720554c9122433b2de --- /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 0000000000000000000000000000000000000000..9e3c32b7b856f37c60392d2023be21d7e4d76022 Binary files /dev/null and b/WhisperTranscript/data/assets/mel_filters.bin differ diff --git a/WhisperTranscript/data/assets/tokenizer.bin b/WhisperTranscript/data/assets/tokenizer.bin new file mode 100644 index 0000000000000000000000000000000000000000..e85846349fd0eab07304e459b7e03dc2dc85cd49 Binary files /dev/null and b/WhisperTranscript/data/assets/tokenizer.bin differ diff --git a/WhisperTranscript/data/icon.svg b/WhisperTranscript/data/icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..326b0fe46d1dd076592f39744bcf78a9cdf358b4 --- /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 0000000000000000000000000000000000000000..b6beff2e303b1a7b3f9e8647323da6e2581a0b99 --- /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 0000000000000000000000000000000000000000..e5fd3d5eedf31ba1eb4fb4edd93fd8cec94dff94 --- /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 0000000000000000000000000000000000000000..69c2a52f7de4daa366d0773b09a9381fa9405ea3 --- /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 0000000000000000000000000000000000000000..7b5c55447f9757018014a913e3d25328b8577f46 --- /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 0000000000000000000000000000000000000000..dbd4ae0e3333a0a3048250b3e521e799356b795a --- /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 0000000000000000000000000000000000000000..94455b42042d9792c6019878c28e48e26b65069b Binary files /dev/null and b/WhisperTranscript/gb0.wav differ diff --git a/WhisperTranscript/getonnxio.py b/WhisperTranscript/getonnxio.py new file mode 100644 index 0000000000000000000000000000000000000000..7385a516384a148a2239b0104652e8d555b3f658 --- /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 0000000000000000000000000000000000000000..48cb5cbe78622c7af64ace8865e8e7b51c40cd9c Binary files /dev/null and b/WhisperTranscript/jami.wav differ diff --git a/WhisperTranscript/jfk.wav b/WhisperTranscript/jfk.wav new file mode 100644 index 0000000000000000000000000000000000000000..3184d372cd2f8b804d3a540c70ec50d927b335d2 Binary files /dev/null and b/WhisperTranscript/jfk.wav differ diff --git a/WhisperTranscript/main.cpp b/WhisperTranscript/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00c976d1fd654d84ad9750fbae688fcff9b5a424 --- /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 0000000000000000000000000000000000000000..ae1e2b636f414df2cb74427bd81b5e8bca9eadee --- /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 0000000000000000000000000000000000000000..2f90b7344cb512feab06bb9eb201cd0b58f52f73 Binary files /dev/null and b/WhisperTranscript/modelSRC/mLogSoftMax.onnx differ diff --git a/WhisperTranscript/modelSRC/mModelDecoder.onnx b/WhisperTranscript/modelSRC/mModelDecoder.onnx new file mode 100644 index 0000000000000000000000000000000000000000..323114dbd0c1dcb18aabfa4f09618a138b1fe2c8 Binary files /dev/null and b/WhisperTranscript/modelSRC/mModelDecoder.onnx differ diff --git a/WhisperTranscript/modelSRC/mModelDecoder.ort b/WhisperTranscript/modelSRC/mModelDecoder.ort new file mode 100644 index 0000000000000000000000000000000000000000..dca38b7e2aa2bbf4420d44e4d2593a4af5ed66cc Binary files /dev/null and b/WhisperTranscript/modelSRC/mModelDecoder.ort differ diff --git a/WhisperTranscript/modelSRC/mModelEncoder.onnx b/WhisperTranscript/modelSRC/mModelEncoder.onnx new file mode 100644 index 0000000000000000000000000000000000000000..5da3279acb94c398779c90864b0f9b8243dd590d Binary files /dev/null and b/WhisperTranscript/modelSRC/mModelEncoder.onnx differ diff --git a/WhisperTranscript/modelSRC/mModelEncoder.ort b/WhisperTranscript/modelSRC/mModelEncoder.ort new file mode 100644 index 0000000000000000000000000000000000000000..abc7d9b8dce8d0ce25d0e2a120a07f3ec1251868 Binary files /dev/null and b/WhisperTranscript/modelSRC/mModelEncoder.ort differ diff --git a/WhisperTranscript/package.json b/WhisperTranscript/package.json new file mode 100644 index 0000000000000000000000000000000000000000..72acbc7d406f94f4ff5747ab3492d9db0070144e --- /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 0000000000000000000000000000000000000000..f71fcb8f46f609dbe52048262363759901ccd366 Binary files /dev/null and b/WhisperTranscript/sample.mp4 differ diff --git a/WhisperTranscript/testPreferences.yml b/WhisperTranscript/testPreferences.yml new file mode 100644 index 0000000000000000000000000000000000000000..eeb3a6c6efbe5da56792089a8cdbdba7374915bd --- /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 0000000000000000000000000000000000000000..81f96347fe6a2c7b55d8dd6e071afddf83edc3e4 --- /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 0000000000000000000000000000000000000000..fdfec5e2e50721f6639212ecaca718106f207669 --- /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 0000000000000000000000000000000000000000..df47fefc9a8cfa93586750e890b4723ee67d4665 --- /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 85d17c0dd29b9660c6d6f37e836a6ed1b018c66c..7f0006cc3f6c35792118c2e698bae38c53484d0f 100644 --- a/lib/AVFrameIO.h +++ b/lib/AVFrameIO.h @@ -182,19 +182,21 @@ readAndNotifyAVFrame(const std::string& file, jami::PublishObservable<AVFrame*>* 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); - - avio_closep(&encFormatCtx->pb); - avcodec_close(encCodecCtx); - avcodec_free_context(&encCodecCtx); - avformat_close_input(&encFormatCtx); - avformat_free_context(encFormatCtx); - return; + 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; + } } AVPacket* packet = av_packet_alloc(); @@ -217,29 +219,32 @@ readAndNotifyAVFrame(const std::string& file, jami::PublishObservable<AVFrame*>* 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); + + av_interleaved_write_frame(encFormatCtx, enc_pkt); + } + av_packet_unref(enc_pkt); + av_packet_free(&enc_pkt); } - - // 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_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 @@ readAndNotifyAVFrame(const std::string& file, jami::PublishObservable<AVFrame*>* 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 0c088bc4d919abe0d118087c2c996642ea2356ea..fdd37eab85bd9a692c7b203ccf8538adb3d28491 100644 --- a/lib/common.cpp +++ b/lib/common.cpp @@ -54,12 +54,44 @@ void ffmpegFormatStringInline(std::string& str) #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 4f0858fb8cb7ee9c3e06604cac8abd54d82350c2..d7ebde99561962cb3dc28d13afb94bb76d9eab1c 100644 --- a/lib/common.h +++ b/lib/common.h @@ -30,6 +30,8 @@ std::wstring to_wstring(const std::string& str); #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 29fedc18e66b543f1b8ee8da898850f47cb84091..96b9caaeb425a8e320733790b02b198e8ccf277c 100644 --- a/lib/frameFilter.h +++ b/lib/frameFilter.h @@ -104,7 +104,7 @@ public: * @brief Frees resources used by FrameFilter. */ void clean(); - + /** * @brief Flag to know whether or not the filter graph is initialized. */