AudioFilter: add process test
GitLab: https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/745
Change-Id: I4ec8adcc7cb1dbbc52b908fdddc7b380cded7350
diff --git a/AudioFilter/.gitignore b/AudioFilter/.gitignore
new file mode 100644
index 0000000..e090044
--- /dev/null
+++ b/AudioFilter/.gitignore
@@ -0,0 +1,3 @@
+/AudioFilter
+*.mp3
+AudioFilter*
diff --git a/AudioFilter/CMakeLists.txt b/AudioFilter/CMakeLists.txt
index 39b2590..0ff0a5e 100644
--- a/AudioFilter/CMakeLists.txt
+++ b/AudioFilter/CMakeLists.txt
@@ -2,7 +2,7 @@
# set the project name
set (ProjectName AudioFilter)
-set (Version 0.1.0)
+set (Version 1.0.0)
project(${ProjectName} VERSION ${Version})
@@ -34,12 +34,19 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
-set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
+
+if(TESTPROCESS)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D__DEBUG__ /MD")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /D__DEBUG__ /MD")
+else()
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MD")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
+endif()
set(plugin_SRC FilterMediaHandler.cpp
FilterAudioSubscriber.cpp
main.cpp
+ ../lib/common.cpp
../lib/frameFilter.cpp
../lib/frameUtils.cpp
)
@@ -51,11 +58,18 @@
../lib/frameFilter.h
../lib/mediaStream.h
../lib/pluglog.h
+ ../lib/common.h
)
-add_library(${ProjectName} SHARED ${plugin_SRC}
- ${plugin_HDR}
- )
+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}
@@ -64,32 +78,50 @@
${CONTRIB_PATH}
${CONTRIB_PATH}/build/fmt/include
${FFMPEG}/include
+ ${CONTRIB_PATH}/build/yaml-cpp/include
)
target_link_directories(${ProjectName} PUBLIC ${CONTRIB_PATH}
${FFMPEG}/lib
${CONTRIB_PATH}/msvc/lib/x64
${CONTRIB_PATH}/build/fmt/msvc/Release
+ ${CONTRIB_PATH}/build/yaml-cpp/msvc/Release
)
-target_link_libraries(${ProjectName} PUBLIC libavfilter libswscale libswresample libavformat libavcodec libavutil libvpx libx264 libopus libmfx
+target_link_libraries(${ProjectName} PUBLIC libyaml-cppmd libavfilter libswscale
+ libswresample libavformat libavcodec libavutil
+ libmp3lame libvpx libx264 libopus libmfx
ws2_32 Bcrypt Secur32)
add_custom_command(
TARGET ${ProjectName}
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/ffmpeg/ ${CONTRIB_PATH}/src/ffmpeg
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/../contrib/mp3lame ${CONTRIB_PATH}/src/mp3lame
COMMAND python ${DAEMON}/compat/msvc/winmake.py -fb ffmpeg
- COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --preassemble --plugin=${ProjectName}
- COMMENT "Assembling Plugin files"
-)
-
-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}
COMMAND cd ${CONTRIB_PATH}/src/ffmpeg/
COMMAND git checkout *
- COMMENT "Generating JPL archive"
)
+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}/sample.mp3 ${PROJECT_BINARY_DIR}/
+ )
+else()
+ add_custom_command(
+ TARGET ${ProjectName}
+ PRE_BUILD
+ COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --preassemble --plugin=${ProjectName}
+ COMMENT "Assembling Plugin files"
+ )
+
+ 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}
+ COMMENT "Generating JPL archive"
+ )
+endif()
diff --git a/AudioFilter/FilterAudioSubscriber.cpp b/AudioFilter/FilterAudioSubscriber.cpp
index e3d2825..02c2555 100644
--- a/AudioFilter/FilterAudioSubscriber.cpp
+++ b/AudioFilter/FilterAudioSubscriber.cpp
@@ -23,7 +23,6 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
-#include <libavfilter/buffersrc.h>
}
#include <frameUtils.h>
@@ -42,6 +41,10 @@
FilterAudioSubscriber::~FilterAudioSubscriber()
{
+ if(pFormatCtx_) {
+ avformat_close_input(&pFormatCtx_);
+ avformat_free_context(pFormatCtx_);
+ }
std::ostringstream oss;
oss << "~FilterMediaProcessor" << std::endl;
Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
@@ -66,7 +69,11 @@
"[ resample1 ] [ ir0 ] afir=maxir=1:wet=10:dry=10:irgain=1:irfmt=mono:maxp="
+ std::to_string(rSamples) + ":minp=" + std::to_string(rSamples)
+ " [ reverb ] , "
+#ifdef __DEBUG__
+ "[ reverb ] aformat=sample_fmts=s16p:sample_rates="
+#else
"[ reverb ] aformat=sample_fmts=s16:sample_rates="
+#endif
+ std::to_string(pSampleRate) + ":channel_layouts=stereo ";
}
@@ -114,11 +121,7 @@
void
FilterAudioSubscriber::setIRAVFrame()
{
- int ret, got_frame;
AVCodecContext* pCodecCtx;
- AVPacket* packet;
-
- FILE* pFile = fopen(irFile_.c_str(), "rb");
const AVCodec* pCodec = avcodec_find_decoder(pFormatCtx_->streams[audioStream_]->codecpar->codec_id);
if (pCodec == NULL) {
@@ -127,63 +130,46 @@
}
pCodecCtx = avcodec_alloc_context3(pCodec);
+ if (avcodec_parameters_to_context(pCodecCtx, pFormatCtx_->streams[audioStream_]->codecpar) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__, "Failed to copy decoder parameters to decoder context.");
+ return;
+ }
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
Plog::log(Plog::LogPriority::INFO, TAG, "Could not open codec.");
return;
}
- packet = av_packet_alloc();
- int buffsize
- = av_samples_get_buffer_size(NULL,
- pFormatCtx_->streams[audioStream_]->codecpar->channels,
- pFormatCtx_->streams[audioStream_]->codecpar->frame_size,
- static_cast<AVSampleFormat>(
- pFormatCtx_->streams[audioStream_]->codecpar->format),
- 1);
- int frames = static_cast<int>(pFormatCtx_->streams[audioStream_]->codecpar->sample_rate
- / pFormatCtx_->streams[audioStream_]->codecpar->frame_size);
- int AUDIO_INBUF_SIZE = buffsize * frames / 4;
- uint8_t* inbuf = new uint8_t[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
-
- packet->data = inbuf;
- packet->size = static_cast<int>(fread(inbuf, 1, AUDIO_INBUF_SIZE, pFile));
- int idx = 0;
+ AVPacket* packet = av_packet_alloc();
AVFrame* pFrame = av_frame_alloc();
- if (avcodec_send_packet(pCodecCtx, packet) < 0) {
- avcodec_close(pCodecCtx);
+ int idx = 0;
+ while (av_read_frame(pFormatCtx_, packet) == 0 && idx < 40) { // Limit for filter coefficients
+ idx++;
av_frame_unref(pFrame);
av_frame_free(&pFrame);
- av_packet_free(&packet);
- avformat_close_input(&pFormatCtx_);
- avformat_free_context(pFormatCtx_);
- Plog::log(Plog::LogPriority::INFO, TAG, "Error submitting the packet to the decoder");
- return;
- }
+ pFrame = av_frame_alloc();
- while (packet->size > 0 && idx < frames) {
- idx++;
- got_frame = 0;
-
- if (avcodec_receive_frame(pCodecCtx, pFrame) < 0) {
+ if (avcodec_send_packet(pCodecCtx, packet) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__, "Error submitting the packet to the decoder");
break;
}
- auto len = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
-
- reverbFilter_.feedInput(pFrame, "ir0");
- packet->size -= len;
- packet->data += len;
+ // Read frames from decoder
+ while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {
+ reverbFilter_.feedInput(pFrame, "ir0");
+ }
+ av_packet_unref(packet);
}
- av_frame_unref(pFrame);
reverbFilter_.feedEOF("ir0");
- fclose(pFile);
- avcodec_close(pCodecCtx);
+ av_frame_unref(pFrame);
av_frame_free(&pFrame);
+ av_packet_unref(packet);
av_packet_free(&packet);
+ avcodec_close(pCodecCtx);
+ avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx_);
avformat_free_context(pFormatCtx_);
}
@@ -210,12 +196,13 @@
if (!reverbFilter_.initialized_)
return;
- AVFrame* filteredFrame;
if (reverbFilter_.feedInput(pluginFrame, "input") == 0) {
- if ((filteredFrame = reverbFilter_.readOutput()))
+ AVFrame* filteredFrame = reverbFilter_.readOutput();
+ if (filteredFrame) {
moveFrom(pluginFrame, filteredFrame);
- av_frame_unref(filteredFrame);
- av_frame_free(&filteredFrame);
+ av_frame_unref(filteredFrame);
+ av_frame_free(&filteredFrame);
+ }
}
}
diff --git a/AudioFilter/FilterAudioSubscriber.h b/AudioFilter/FilterAudioSubscriber.h
index 9c3912d..b5ce828 100644
--- a/AudioFilter/FilterAudioSubscriber.h
+++ b/AudioFilter/FilterAudioSubscriber.h
@@ -50,7 +50,7 @@
// Data
std::string path_;
FrameFilter reverbFilter_;
- AVFormatContext* pFormatCtx_;
+ AVFormatContext* pFormatCtx_ = NULL;
int audioStream_ = -1;
// Status variables of the processing
diff --git a/AudioFilter/FilterMediaHandler.cpp b/AudioFilter/FilterMediaHandler.cpp
index e04a603..02a0e06 100644
--- a/AudioFilter/FilterMediaHandler.cpp
+++ b/AudioFilter/FilterMediaHandler.cpp
@@ -38,13 +38,13 @@
setId(datapath_);
auto it = preferences_.find("irFile");
if (it != preferences_.end())
- mAS = std::make_shared<FilterAudioSubscriber>(datapath_, it->second);
+ mAS_ = std::make_shared<FilterAudioSubscriber>(datapath_, it->second);
}
void
FilterMediaHandler::notifyAVFrameSubject(const StreamData& data, jami::avSubjectPtr subject)
{
- if (!mAS)
+ if (!mAS_)
return;
std::ostringstream oss;
std::string_view direction = data.direction ? "Receive" : "Preview";
@@ -57,12 +57,12 @@
oss << "preferredStreamDirection " << preferredStreamDirection << std::endl;
if (data.type == StreamType::audio && !data.direction
&& data.direction == preferredStreamDirection) {
- subject->attach(mAS.get()); // your image
+ subject->attach(mAS_.get()); // your image
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 image you receive from others on the call
oss << "got received audio attached" << std::endl;
attached_ = '1';
}
@@ -86,8 +86,8 @@
auto it = preferences_.find(key);
if (it != preferences_.end() && it->second != value) {
it->second = value;
- if (key == "irFile")
- mAS->setIRFile(value);
+ if (key == "irFile" && mAS_)
+ mAS_->setIRFile(value);
}
}
@@ -103,7 +103,8 @@
FilterMediaHandler::detach()
{
attached_ = '0';
- mAS->detach();
+ if (mAS_)
+ mAS_->detach();
}
FilterMediaHandler::~FilterMediaHandler()
diff --git a/AudioFilter/FilterMediaHandler.h b/AudioFilter/FilterMediaHandler.h
index 01ed64e..c19b8b4 100644
--- a/AudioFilter/FilterMediaHandler.h
+++ b/AudioFilter/FilterMediaHandler.h
@@ -41,7 +41,7 @@
virtual void setPreferenceAttribute(const std::string& key, const std::string& value) override;
virtual bool preferenceMapHasKey(const std::string& key) override;
- std::shared_ptr<FilterAudioSubscriber> mAS;
+ std::shared_ptr<FilterAudioSubscriber> mAS_{};
private:
const std::string datapath_;
diff --git a/AudioFilter/build.sh b/AudioFilter/build.sh
index 91ee4ae..36e6d30 100755
--- a/AudioFilter/build.sh
+++ b/AudioFilter/build.sh
@@ -6,9 +6,10 @@
EXTRAPATH=''
# Flags:
-# -p: number of processors to use
+# -p: number of processors to use.
# -c: Runtime plugin cpu/gpu setting.
# -t: target platform.
+# -d: debug program.
if [ -z "${DAEMON}" ]; then
@@ -38,8 +39,12 @@
echo "Building with ${PLATFORM}"
fi
-while getopts t:c:p OPT; do
+while getopts t:c:p:d OPT; do
case "$OPT" in
+ d)
+ DEBUG=true
+ export __DEBUG__=true
+ ;;
t)
PLATFORM="${OPTARG}"
;;
@@ -55,6 +60,7 @@
done
cp -r ffmpeg ${CONTRIB_PATH}/src/
+cp -r ../contrib/mp3lame ${CONTRIB_PATH}/src/
if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
then
@@ -67,21 +73,30 @@
rm .ffmpeg
cd ${WORKPATH}
- python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
-
CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+ if [ ${DEBUG} ]; then
+ OUTPUT="${PLUGIN_NAME}"
+ CLANG_OPTS="-g -fsanitize=address"
+ EXTRA_DEBUG_LIBRARIES="-lyaml-cpp -lvdpau -lX11 -lva-drm -lva-x11 -lmp3lame"
+ 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 \
+ ${EXTRA_DEFINES} \
-I"." \
-I"${DAEMON_SRC}" \
-I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include" \
-I"${PLUGINS_LIB}" \
+ ./../lib/common.cpp \
./../lib/frameFilter.cpp \
./../lib/frameUtils.cpp \
FilterMediaHandler.cpp \
@@ -94,10 +109,14 @@
-l:libavformat.a \
-l:libavcodec.a \
-l:libavutil.a \
- -l:libvpx.a \
- -l:libx264.a \
+ -lvpx \
+ -lx264 \
+ -lspeex \
+ -lopus \
+ -lz \
-lva \
- -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+ ${EXTRA_DEBUG_LIBRARIES} \
+ -o "${OUTPUT}"
elif [ "${PLATFORM}" = "darwin" ]
then
@@ -110,24 +129,33 @@
rm .ffmpeg
cd ${WORKPATH}
- python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
-
CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+ if [ ${DEBUG} ]; then
+ OUTPUT="${PLUGIN_NAME}"
+ CLANG_OPTS="-g -fsanitize=address"
+ EXTRA_DEBUG_LIBRARIES="-lyaml-cpp -lmp3lame"
+ 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,-no_compact_unwind -Wl,-framework,CoreFoundation \
-Wl,-framework,Security -Wl,-framework,VideoToolbox \
-Wl,-framework,CoreMedia -Wl,-framework,CoreVideo \
-Wl,-rpath,"\${ORIGIN}" \
-Wall -Wextra \
- -Wno-unused-variable \
- -Wno-unused-function \
-Wno-unused-parameter \
+ ${EXTRA_DEFINES} \
-I"." \
-I"${DAEMON_SRC}" \
-I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
-I"${PLUGINS_LIB}" \
+ ./../lib/common.cpp \
./../lib/frameFilter.cpp \
./../lib/frameUtils.cpp \
FilterMediaHandler.cpp \
@@ -141,11 +169,16 @@
-lavcodec \
-lavutil \
-lvpx -lx264 -lbz2 -liconv -lz \
- "/usr/local/opt/speex/lib/libspeex.a" \
- "/usr/local/opt/opus/lib/libopus.a" \
- -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+ -lspeex \
+ -lopus \
+ ${EXTRA_DEBUG_LIBRARIES} \
+ -o "${OUTPUT}"
- install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+ if [ ! ${DEBUG} ]; then
+ install_name_tool -id "@loader_path/${PLUGIN_NAME}" "${OUTPUT}"
+ else
+ install_name_tool -id "@loader_path/${SO_FILE_NAME}" "${OUTPUT}"
+ fi
if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
@@ -308,7 +341,9 @@
done
fi
-python3 ./../SDK/jplManipulation.py --assemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM} --extraPath=${EXTRAPATH}
+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
diff --git a/AudioFilter/ffmpeg/package.json b/AudioFilter/ffmpeg/package.json
index 69c2a52..ef1d754 100644
--- a/AudioFilter/ffmpeg/package.json
+++ b/AudioFilter/ffmpeg/package.json
@@ -3,6 +3,7 @@
"version": "n5.0",
"url": "https://git.ffmpeg.org/gitweb/ffmpeg.git/snapshot/__VERSION__.tar.gz",
"deps": [
+ "mp3lame",
"vpx",
"x264",
"opus",
@@ -16,7 +17,8 @@
"libopusdec-enable-FEC.patch",
"windows-configure.patch",
"windows-configure-ffnvcodec.patch",
- "windows-configure-libmfx.patch"
+ "windows-configure-libmfx.patch",
+ "windows-configure-mp3lame.patch"
],
"win_patches": [
],
diff --git a/AudioFilter/ffmpeg/rules.mak b/AudioFilter/ffmpeg/rules.mak
index a2bf7d9..eda60ec 100644
--- a/AudioFilter/ffmpeg/rules.mak
+++ b/AudioFilter/ffmpeg/rules.mak
@@ -3,7 +3,11 @@
PKGS+=ffmpeg
+ifdef __DEBUG__
+DEPS_ffmpeg = iconv zlib vpx opus speex x264 mp3lame
+else
DEPS_ffmpeg = iconv zlib vpx opus speex x264
+endif
FFMPEGCONF = \
--cc="$(CC)" \
@@ -110,6 +114,13 @@
--enable-encoder=libopus \
--enable-decoder=libopus
+ifdef __DEBUG__
+FFMPEGCONF += \
+ --enable-libmp3lame \
+ --enable-encoder=libmp3lame \
+ --enable-muxer=mp3
+endif
+
# decoders for ringtones and audio streaming
FFMPEGCONF += \
--enable-decoder=flac \
@@ -184,6 +195,7 @@
--target-os=android \
--enable-jni \
--enable-mediacodec \
+ --disable-vulkan \
--enable-decoder=vp8_mediacodec \
--enable-decoder=h264_mediacodec \
--enable-decoder=mpeg4_mediacodec \
diff --git a/AudioFilter/ffmpeg/windows-configure-make.sh b/AudioFilter/ffmpeg/windows-configure-make.sh
index 8fa4935..cf4fa01 100644
--- a/AudioFilter/ffmpeg/windows-configure-make.sh
+++ b/AudioFilter/ffmpeg/windows-configure-make.sh
@@ -63,6 +63,11 @@
--enable-decoder=mjpeg
--enable-decoder=mjpegb'
+FFMPEGCONF+='
+ --enable-libmp3lame
+ --enable-encoder=libmp3lame
+ --enable-muxer=mp3'
+
# decoders for ringtones and audio streaming
FFMPEGCONF+='
--enable-decoder=flac
@@ -144,7 +149,7 @@
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'
+ 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
@@ -179,13 +184,13 @@
--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'
+ 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 libmp3lame.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'
+ 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 libmp3lame.lib -LIBPATH:../../../../../msvc/lib/x86'
FFMPEGCONF+=' --arch=x86'
PREFIX=../../../Build/win32/x86
OUTDIR=Output/win32/x86
diff --git a/AudioFilter/ffmpeg/windows-configure-mp3lame.patch b/AudioFilter/ffmpeg/windows-configure-mp3lame.patch
new file mode 100644
index 0000000..76e6b74
--- /dev/null
+++ b/AudioFilter/ffmpeg/windows-configure-mp3lame.patch
@@ -0,0 +1,24 @@
+From ccf53cdcdbb11a57d5874ba803538c3cc98031bd Mon Sep 17 00:00:00 2001
+From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+Date: Fri, 26 Aug 2022 17:01:30 -0300
+Subject: [PATCH] windows-configure-mp3lame
+
+---
+ configure | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/configure b/configure
+index 70e909c603..eebb3dd510 100755
+--- a/configure
++++ b/configure
+@@ -6549,7 +6549,6 @@ enabled liblensfun && require_pkg_config liblensfun lensfun lensfun.h lf_
+ # can find the libraries and headers through other means.
+
+ enabled libmodplug && require_pkg_config libmodplug libmodplug libmodplug/modplug.h ModPlug_Load
+-enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs
+ enabled libmysofa && { check_pkg_config libmysofa libmysofa mysofa.h mysofa_neighborhood_init_withstepdefine ||
+ require libmysofa mysofa.h mysofa_neighborhood_init_withstepdefine -lmysofa $zlib_extralibs; }
+ enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei -lnppif ||
+--
+2.30.2.windows.1
+
diff --git a/AudioFilter/main.cpp b/AudioFilter/main.cpp
index 4b30b2d..1a28e49 100644
--- a/AudioFilter/main.cpp
+++ b/AudioFilter/main.cpp
@@ -26,14 +26,21 @@
#include "FilterMediaHandler.h"
+#ifdef __DEBUG__
+#include <common.h>
+#include <assert.h>
+#include <yaml-cpp/yaml.h>
+#include <AVFrameIO.h>
+#endif
+
#ifdef WIN32
#define EXPORT_PLUGIN __declspec(dllexport)
#else
#define EXPORT_PLUGIN
#endif
-#define AudioFilter_VERSION_MAJOR 0
-#define AudioFilter_VERSION_MINOR 1
+#define AudioFilter_VERSION_MAJOR 1
+#define AudioFilter_VERSION_MINOR 0
#define AudioFilter_VERSION_PATCH 0
extern "C" {
@@ -68,3 +75,54 @@
return pluginExit;
}
}
+
+#ifdef __DEBUG__
+
+int
+main ()
+{
+ std::cout << "*********************************" << std::endl;
+ std::cout << "** AudioFilter Debug Version **" << std::endl;
+ std::cout << "*********************************" << std::endl;
+ std::cout << "Version " << AudioFilter_VERSION_MAJOR << "." << AudioFilter_VERSION_MINOR << "."
+ << AudioFilter_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::string> preferences;
+ for (const auto& kv : node) {
+ preferences[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 fmpFilterMediaHandler = std::make_unique<jami::FilterMediaHandler>(std::move(
+ preferences),
+ std::move(dataPath));
+
+ auto subject = std::make_shared<jami::PublishObservable<AVFrame*>>();
+
+ // Valid Read frames from sample file and send to subscriber
+ std::cout << "Test 1" << std::endl << "Received audio: " << preferences["sample"] << std::endl;
+ fmpFilterMediaHandler->notifyAVFrameSubject(StreamData("testCall", true, StreamType::audio, "origin", "destiny"), subject);
+ av_utils::readAndNotifyAVFrame(preferences["sample"], subject.get(), preferences["output1"], AVMEDIA_TYPE_AUDIO);
+
+ // Valid Read frames from sample file and send to subscriber
+ std::cout << "Test 2" << std::endl << "Sent audio: " << preferences["sample"] << std::endl;
+ fmpFilterMediaHandler->detach();
+ fmpFilterMediaHandler->notifyAVFrameSubject(StreamData("testCall", false, StreamType::audio, "origin", "destiny"), subject);
+ av_utils::readAndNotifyAVFrame(preferences["sample"], subject.get(), preferences["output2"], AVMEDIA_TYPE_AUDIO);
+
+ return 0;
+}
+#endif
diff --git a/AudioFilter/manifest.json b/AudioFilter/manifest.json
index 7de0b23..bc5b9fe 100644
--- a/AudioFilter/manifest.json
+++ b/AudioFilter/manifest.json
@@ -1,6 +1,6 @@
{
"name": "AudioFilter",
"description": "Provides audio filter for audio and video calls: reverb",
- "version": "0.1.0",
+ "version": "1.0.0",
"iconPath" : "icon.svg"
}
\ No newline at end of file
diff --git a/AudioFilter/package.json b/AudioFilter/package.json
index 1206532..8d6d69e 100644
--- a/AudioFilter/package.json
+++ b/AudioFilter/package.json
@@ -1,12 +1,14 @@
{
"name": "AudioFilter",
- "version": "0.1.0",
+ "version": "1.0.0",
"extractLibs": false,
"deps": [
"fmt",
- "ffmpeg"
+ "yaml-cpp"
],
- "defines": [],
+ "defines": [
+ "TESTPROCESS=False"
+ ],
"custom_scripts": {
"pre_build": [
"mkdir msvc"
diff --git a/AudioFilter/sample.mp3 b/AudioFilter/sample.mp3
new file mode 100644
index 0000000..e68cb46
--- /dev/null
+++ b/AudioFilter/sample.mp3
Binary files differ
diff --git a/AudioFilter/testPreferences.yml b/AudioFilter/testPreferences.yml
new file mode 100644
index 0000000..30e970c
--- /dev/null
+++ b/AudioFilter/testPreferences.yml
@@ -0,0 +1,5 @@
+irFile: "rir_jack_lyons_lp2_96k.mp3"
+streamlist: "in"
+sample: "sample.mp3"
+output1: "processed.mp3"
+output2: "notprocessed.mp3"
\ No newline at end of file
diff --git a/contrib/mp3lame/package.json b/contrib/mp3lame/package.json
new file mode 100644
index 0000000..f0a572b
--- /dev/null
+++ b/contrib/mp3lame/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "mp3lame",
+ "version": "b8d31e1d07b851208ad413ee82deca875d8a1c80",
+ "url": "https://github.com/ShiftMediaProject/lame/archive/__VERSION__.tar.gz",
+ "deps": [],
+ "patches": [],
+ "win_patches": [],
+ "project_paths": ["SMP/libmp3lame.vcxproj"],
+ "with_env" : "",
+ "custom_scripts": {
+ "pre_build": [],
+ "build": [],
+ "post_build": []
+ }
+}
\ No newline at end of file
diff --git a/contrib/mp3lame/rules.mak b/contrib/mp3lame/rules.mak
new file mode 100644
index 0000000..418e1cd
--- /dev/null
+++ b/contrib/mp3lame/rules.mak
@@ -0,0 +1,25 @@
+# lame
+LAME_HASH := f416c19b3140a8610507ebb60ac7cd06e94472b8
+LAME_GITURL := https://github.com/gypified/libmp3lame.git
+
+LAMECONFIG := --prefix="$(PREFIX)"
+
+$(TARBALLS)/mp3lame-$(LAME_HASH).tar.xz:
+ $(call download_git,$(LAME_GITURL),master,$(LAME_HASH))
+
+.sum-mp3lame: mp3lame-$(LAME_HASH).tar.xz
+ $(warning $@ not implemented)
+ touch $@
+
+mp3lame: mp3lame-$(LAME_HASH).tar.xz .sum-mp3lame
+ rm -Rf $@-$(LAME_HASH)
+ mkdir -p $@-$(LAME_HASH)
+ (cd $@-$(LAME_HASH) && tar x $(if ${BATCH_MODE},,-v) --strip-components=1 -f $<)
+ $(UPDATE_AUTOCONFIG)
+ $(MOVE)
+
+.mp3lame: mp3lame
+ cd $< && $(HOSTVARS) ./configure $(LAMECONFIG)
+ cd $< && $(MAKE)
+ cd $< && $(MAKE) install
+ touch $@
diff --git a/lib/AVFrameIO.h b/lib/AVFrameIO.h
new file mode 100644
index 0000000..867ffa8
--- /dev/null
+++ b/lib/AVFrameIO.h
@@ -0,0 +1,240 @@
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavfilter/buffersrc.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/common.h>
+#include <libavutil/frame.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/rational.h>
+}
+
+#include "pluglog.h"
+
+#include <observer.h>
+
+namespace av_utils
+{
+
+const AVCodec*
+openDecoder(AVCodecContext*& decCodecCtx,
+ AVFormatContext*& decFormatCtx,
+ const std::string& file,
+ AVStream*& decStream,
+ const AVMediaType& mediaType)
+{
+ // Open
+ if (avformat_open_input(&decFormatCtx, file.c_str(), NULL, NULL) != 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Couldn't open input stream.");
+ return nullptr;
+ }
+ // Retrieve stream information
+ if (avformat_find_stream_info(decFormatCtx, NULL) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Couldn't find stream information.");
+ return nullptr;
+ }
+ // Dump valid information onto standard error
+ av_dump_format(decFormatCtx, 0, file.c_str(), false);
+
+ // Find the first audio/video stream
+ const AVCodec* decCodec;
+ auto stream = av_find_best_stream(decFormatCtx, mediaType, -1, -1, &decCodec, 0);
+
+ if (stream < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Didn't find an audio stream.");
+ return nullptr;
+ }
+ decStream = decFormatCtx->streams[stream];
+
+ if (decCodec == NULL) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Decoder not found.");
+ return nullptr;
+ }
+
+ decCodecCtx = avcodec_alloc_context3(decCodec);
+ if (avcodec_parameters_to_context(decCodecCtx, decStream->codecpar) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Failed to copy decoder parameters to decoder context.");
+ return nullptr;
+ }
+
+ if (decCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO)
+ decCodecCtx->framerate = av_guess_frame_rate(decFormatCtx, decStream, NULL);
+
+ // Open codec
+ if (avcodec_open2(decCodecCtx, decCodec, NULL) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Could not open codec.");
+ return nullptr;
+ }
+ return decCodec;
+}
+
+const AVCodec*
+openEncoder(AVCodecContext*& encCodecCtx,
+ AVCodecContext*& decCodecCtx,
+ AVFormatContext*& encFormatCtx,
+ AVStream*& encStream,
+ const std::string& rFile,
+ AVStream*& decStream,
+ const AVMediaType& mediaType)
+{
+ avformat_alloc_output_context2(&encFormatCtx, NULL, NULL, rFile.c_str());
+ if (!encFormatCtx) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Could not create output context.");
+ return nullptr;
+ }
+
+ encStream = avformat_new_stream(encFormatCtx, NULL);
+ if (!encStream) {
+ return nullptr;
+ }
+
+ const AVCodec* encCodec = avcodec_find_encoder(decStream->codecpar->codec_id);
+ if (encCodec == NULL) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Encoder not found.");
+ return nullptr;
+ }
+ encCodecCtx = avcodec_alloc_context3(encCodec);
+ if (encCodecCtx == NULL) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Could not allocate audio codec context.");
+ return nullptr;
+ }
+
+ if (mediaType == AVMEDIA_TYPE_AUDIO) {
+ encCodecCtx->sample_rate = decCodecCtx->sample_rate;
+ encCodecCtx->channel_layout = decCodecCtx->channel_layout;
+ encCodecCtx->channels = decCodecCtx->channels;
+ encCodecCtx->channels = av_get_channel_layout_nb_channels(encCodecCtx->channel_layout);
+ encCodecCtx->sample_fmt = decCodecCtx->sample_fmt;
+ encCodecCtx->time_base = AVRational{1, encCodecCtx->sample_rate};
+ } else if (mediaType == AVMEDIA_TYPE_VIDEO) {
+ encCodecCtx->height = decCodecCtx->height;
+ encCodecCtx->width = decCodecCtx->width;
+ encCodecCtx->sample_aspect_ratio = decCodecCtx->sample_aspect_ratio;
+ encCodecCtx->pix_fmt = decCodecCtx->pix_fmt;
+ encCodecCtx->time_base = decStream->time_base;
+ encCodecCtx->bit_rate = decCodecCtx->bit_rate;
+ } else {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Unsupported media type");
+ return nullptr;
+ }
+
+ if (avcodec_open2(encCodecCtx, encCodec, NULL) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Could not open codec.");
+ return nullptr;
+ }
+ if (avcodec_parameters_from_context(encStream->codecpar, encCodecCtx) < 0) {
+ return nullptr;
+ }
+ encStream->time_base = encCodecCtx->time_base;
+
+ av_dump_format(encFormatCtx, 0, rFile.c_str(), 1);
+
+ if (!(encFormatCtx->oformat->flags & AVFMT_NOFILE)) {
+ if (avio_open(&encFormatCtx->pb, rFile.c_str(), AVIO_FLAG_WRITE) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Could not open output file.");
+ return nullptr;
+ }
+ }
+
+ if (avformat_write_header(encFormatCtx, NULL) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Could not open output file.");
+ return nullptr;
+ }
+ return encCodec;
+}
+
+void
+readAndNotifyAVFrame(const std::string& file, jami::PublishObservable<AVFrame*>* subject, const std::string& rFile, const AVMediaType mediaType)
+{
+ // Open Decoder
+ AVCodecContext* decCodecCtx;
+ AVFormatContext* decFormatCtx = avformat_alloc_context();
+ AVStream* decStream;
+ const AVCodec* decCodec = openDecoder(decCodecCtx, decFormatCtx, file, decStream, mediaType);
+ if (!decCodec) {
+ avcodec_close(decCodecCtx);
+ avcodec_free_context(&decCodecCtx);
+ avformat_close_input(&decFormatCtx);
+ avformat_free_context(decFormatCtx);
+ return;
+ }
+
+ // Open Encoder
+ 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;
+ }
+
+ AVPacket* packet = av_packet_alloc();
+ AVFrame* pFrame = av_frame_alloc();
+
+ while (av_read_frame(decFormatCtx, packet) == 0) {
+ av_frame_unref(pFrame);
+ av_frame_free(&pFrame);
+ pFrame = av_frame_alloc();
+ if (packet->stream_index == decStream->index) {
+ if (avcodec_send_packet(decCodecCtx, packet) < 0) {
+ Plog::log(Plog::LogPriority::INFO, __FILE__ + std::string(":") + std::to_string(__LINE__), "Error submitting the packet to the decoder");
+ break;
+ }
+
+ // Read frames from decoder
+ while (avcodec_receive_frame(decCodecCtx, pFrame) == 0) {
+ // Publish frames for the plugin subscriber
+ subject->publish(pFrame);
+
+ // 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);
+ }
+ }
+ av_packet_unref(packet);
+ }
+
+ av_write_trailer(encFormatCtx);
+
+ av_frame_unref(pFrame);
+ av_frame_free(&pFrame);
+ av_packet_unref(packet);
+ av_packet_free(&packet);
+
+ 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);
+}
+} //av_utils
diff --git a/lib/common.cpp b/lib/common.cpp
index 2047278..4803f1c 100644
--- a/lib/common.cpp
+++ b/lib/common.cpp
@@ -41,3 +41,16 @@
}
} // namespace string_utils
#endif // WIN32
+
+namespace file_utils {
+
+void
+openStream(std::ifstream& file, const std::string& path)
+{
+#ifdef _WIN32
+ file = std::ifstream(string_utils::to_wstring(path));
+#else
+ file = std::ifstream(path);
+#endif
+}
+} // namespace file_utils
diff --git a/lib/common.h b/lib/common.h
index f0543d0..5e25091 100644
--- a/lib/common.h
+++ b/lib/common.h
@@ -21,6 +21,8 @@
#ifndef COMMON_H
#define COMMON_H
+#include <fstream>
+
#ifdef WIN32
#include <string>
@@ -29,4 +31,8 @@
std::wstring to_wstring(const std::string& str);
} // namespace string_utils
#endif // WIN32
+
+namespace file_utils {
+void openStream(std::ifstream& file, const std::string& path);
+}
#endif // COMMON_H
diff --git a/lib/frameFilter.cpp b/lib/frameFilter.cpp
index 1cba04d..dc571d4 100644
--- a/lib/frameFilter.cpp
+++ b/lib/frameFilter.cpp
@@ -216,6 +216,8 @@
auto type = av_buffersink_get_type(output_);
if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
+ av_frame_unref(frame);
+ av_frame_free(&frame);
return nullptr;
}
auto err = av_buffersink_get_frame(output_, frame);
@@ -228,6 +230,8 @@
} else {
fail("Error occurred while pulling from filter graph", err);
}
+ av_frame_unref(frame);
+ av_frame_free(&frame);
return nullptr;
}