From f63c1e0a65c6d1031cd1a55e0dde1a75fd21830d Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 16 Feb 2020 10:00:18 -0800 Subject: [PATCH 001/100] Newer codecs --- src/FFmpegWriter.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 8d060d77..dec430d1 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -255,7 +255,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f } if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; - if ((bit_rate >= 0) && (bit_rate < 64)) // bit_rate is the bitrate in crf + if ((bit_rate >= 0) && (bit_rate < 256)) // bit_rate is the bitrate in crf info.video_bit_rate = bit_rate; info.interlaced_frame = interlaced; @@ -341,7 +341,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va // Was option found? if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" || name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || - name == "rc_buffer_size" || name == "crf" || name == "cqp")) { + name == "rc_buffer_size" || name == "crf" || name == "cqp" || name == "qp")) { // Check for specific named options if (name == "g") // Set gop_size @@ -462,6 +462,18 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va case AV_CODEC_ID_AV1 : c->bit_rate = 0; av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); + if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { + //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); + av_opt_set_int(c->priv_data, "preset", 6, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } + if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); + av_opt_set_int(c->priv_data, "speed", 7, 0); + av_opt_set_int(c->priv_data, "tile-rows", 2, 0); + av_opt_set_int(c->priv_data, "tile-columns", 4, 0); + //av_opt_set(c->priv_data, "tile-row", "", 0); + } break; #endif case AV_CODEC_ID_VP8 : @@ -503,6 +515,36 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va c->bit_rate = (int) (mbs); } } +#endif + } else if (name == "qp") { + // encode quality and special settings like lossless + // This might be better in an extra methods as more options + // and way to set quality are possible +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + switch (c->codec_id) { + case AV_CODEC_ID_AV1 : + c->bit_rate = 0; + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); + if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); + av_opt_set_int(c->priv_data, "preset", 6, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } + if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); + av_opt_set_int(c->priv_data, "speed", 7, 0); + av_opt_set_int(c->priv_data, "tile-rows", 2, 0); + av_opt_set_int(c->priv_data, "tile-columns", 4, 0); + //av_opt_set(c->priv_data, "tile-row", "", 0); + } + if (strstr(info.vcodec.c_str(), "aom") != NULL) { + // Hack to set tiles; libaom doesn have qp only crf + av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); + av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows + av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns + } + break; + } #endif } else { // Set AVOption From 6711c9c788eea07595b9627fb6e428f841dc557f Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 16 Feb 2020 19:16:45 -0800 Subject: [PATCH 002/100] Minor improvements --- src/FFmpegWriter.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index dec430d1..b3a0b59c 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -463,16 +463,13 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va c->bit_rate = 0; av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { - //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); av_opt_set_int(c->priv_data, "preset", 6, 0); av_opt_set_int(c->priv_data, "forced-idr",1,0); } if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { - //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); av_opt_set_int(c->priv_data, "speed", 7, 0); av_opt_set_int(c->priv_data, "tile-rows", 2, 0); av_opt_set_int(c->priv_data, "tile-columns", 4, 0); - //av_opt_set(c->priv_data, "tile-row", "", 0); } break; #endif @@ -524,25 +521,30 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va switch (c->codec_id) { case AV_CODEC_ID_AV1 : c->bit_rate = 0; - av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); av_opt_set_int(c->priv_data, "preset", 6, 0); av_opt_set_int(c->priv_data, "forced-idr",1,0); } - if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + // Set number of tiles to a fixed value + // TODO Let user choose number of tiles av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); av_opt_set_int(c->priv_data, "speed", 7, 0); - av_opt_set_int(c->priv_data, "tile-rows", 2, 0); - av_opt_set_int(c->priv_data, "tile-columns", 4, 0); - //av_opt_set(c->priv_data, "tile-row", "", 0); + av_opt_set_int(c->priv_data, "tile-rows", 2, 0); // number of rows + av_opt_set_int(c->priv_data, "tile-columns", 4, 0); // number of columns } - if (strstr(info.vcodec.c_str(), "aom") != NULL) { - // Hack to set tiles; libaom doesn have qp only crf + else if (strstr(info.vcodec.c_str(), "aom") != NULL) { + // Set number of tiles to a fixed value + // TODO Let user choose number of tiles + // libaom doesn't have qp only crf av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns } + else { + av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); + } break; } #endif From e03cd87373faf119057da3914af6dda1d06e9fa2 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 17 Feb 2020 10:56:00 -0800 Subject: [PATCH 003/100] Initial svt-hevc (h.265) encoder support added --- src/FFmpegWriter.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index b3a0b59c..beb19534 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -492,7 +492,14 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va } break; case AV_CODEC_ID_HEVC : - av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51 + if (strstr(info.vcodec.c_str(), "svt_hevc") != NULL) { + av_opt_set_int(c->priv_data, "preset", 7, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + av_opt_set_int(c->priv_data, "qp",std::min(std::stoi(value), 51),0); + } + else { + av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51 + } if (std::stoi(value) == 0) { av_opt_set(c->priv_data, "preset", "veryslow", 0); av_opt_set_int(c->priv_data, "lossless", 1, 0); @@ -545,6 +552,13 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va else { av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); } + case AV_CODEC_ID_HEVC : + c->bit_rate = 0; + if (strstr(info.vcodec.c_str(), "svt_hevc") != NULL) { + av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),51), 0); + av_opt_set_int(c->priv_data, "preset", 7, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } break; } #endif From e7bd91814a239a0d4a3bc93b655173257f51e21e Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 24 Feb 2020 09:35:13 +0200 Subject: [PATCH 004/100] Change frame rate detection Make FPS detection of the input file similar to the FFmpeg's own re-encoding algorithm. --- src/FFmpegReader.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index b548fa8f..9b0f7bcb 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -706,9 +706,16 @@ void FFmpegReader::UpdateVideoInfo() { info.vcodec = pCodecCtx->codec->name; info.video_bit_rate = (pFormatCtx->bit_rate / 8); - // set frames per second (fps) - info.fps.num = pStream->avg_frame_rate.num; - info.fps.den = pStream->avg_frame_rate.den; + // Frame rate from the container and codec + AVRational framerate = av_guess_frame_rate(pFormatCtx, pStream, NULL); + info.fps.num = framerate.num; + info.fps.den = framerate.den; + + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdateVideoInfo", "info.fps.num", info.fps.num, "info.fps.den", info.fps.den); + + // TODO: remove excessive debug info in the next releases + // The debug info below is just for comparison and troubleshooting on users side during the transition period + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdateVideoInfo (pStream->avg_frame_rate)", "num", pStream->avg_frame_rate.num, "den", pStream->avg_frame_rate.den); if (pStream->sample_aspect_ratio.num != 0) { info.pixel_ratio.num = pStream->sample_aspect_ratio.num; From ddd52460e17f37d7078ee5ac4ae3335301c9ea86 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 1 Mar 2020 16:59:06 -0800 Subject: [PATCH 005/100] Fix handling of RAWIMAGE under ffmpeg 4 --- src/FFmpegWriter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index beb19534..cc71e11a 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -842,6 +842,9 @@ void FFmpegWriter::flush_encoders() { #if (LIBAVFORMAT_VERSION_MAJOR < 58) if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) return; +#else + if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) + return; #endif int error_code = 0; @@ -1991,10 +1994,14 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) { bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *frame_final) { #if (LIBAVFORMAT_VERSION_MAJOR >= 58) ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags); + + if (video_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + video_st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) { #else ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE); if (oc->oformat->flags & AVFMT_RAWPICTURE) { +#endif // Raw video case. AVPacket pkt; av_init_packet(&pkt); @@ -2019,7 +2026,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra AV_FREE_PACKET(&pkt); } else -#endif { AVPacket pkt; From 6476f930bb601cebe7f8470776e7a4f836e46ca6 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 1 Mar 2020 17:10:39 -0800 Subject: [PATCH 006/100] Simplify fix for RAWVIDEO handling for ffmpeg 4+ --- src/FFmpegWriter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index cc71e11a..cc4b3d3a 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1995,8 +1995,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra #if (LIBAVFORMAT_VERSION_MAJOR >= 58) ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags); - if (video_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - video_st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) { + if (AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) { #else ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE); From 20fffc404cb920f860d8b208f659d6f06be9e8b0 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 9 Mar 2020 09:10:55 -0400 Subject: [PATCH 007/100] bindings: Relative paths, overridable --- .gitlab-ci.yml | 15 ++--- src/bindings/python/CMakeLists.txt | 52 ++++++++------- src/bindings/ruby/CMakeLists.txt | 102 +++++++++++++++++------------ 3 files changed, 94 insertions(+), 75 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f998c3d4..6b2645d8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,13 +16,11 @@ linux-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - mkdir -p install-x64/python; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"CMAKE_BUILD_TYPE:STRING=Release" -D"USE_SYSTEM_JSONCPP=0" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -DCMAKE_BUILD_TYPE:STRING=Release -DUSE_SYSTEM_JSONCPP=0 ../ - make - make install - make doc - ~/auto-update-docs "$CI_PROJECT_DIR/build" "$CI_COMMIT_REF_NAME" - - mv install-x64/lib/python3.4/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0 @^)..@ --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" when: always @@ -45,11 +43,9 @@ mac-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - mkdir -p install-x64/python; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc48/bin/g++-4.8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc48/bin/gcc-4.8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc48/bin/g++-4.8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc48/bin/gcc-4.8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPYTHON_MODULE_PATH=python -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ - make - make install - - mv install-x64/lib/python3.6/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0 @^)..@ --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" when: always @@ -73,9 +69,8 @@ windows-builder-x64: - $env:RESVGDIR = "C:\msys64\usr" - $env:Path = "C:\msys64\mingw64\bin;C:\msys64\mingw64\lib;C:\msys64\usr\lib\cmake\UnitTest++;C:\msys64\home\jonathan\depot_tools;C:\msys64\usr;C:\msys64\usr\lib;" + $env:Path; - New-Item -ItemType Directory -Force -Path build - - New-Item -ItemType Directory -Force -Path build\install-x64\python - cd build - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - mingw32-make install - Move-Item -Force -path "install-x64\lib\python3.7\site-packages\*openshot*" -destination "install-x64\python\" - New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force @@ -102,11 +97,9 @@ windows-builder-x86: - $env:RESVGDIR = "C:\msys32\usr" - $env:Path = "C:\msys32\mingw32\bin;C:\msys32\mingw32\lib;C:\msys32\usr\lib\cmake\UnitTest++;C:\msys32\home\jonathan\depot_tools;C:\msys32\usr;C:\msys32\usr\lib;" + $env:Path; - New-Item -ItemType Directory -Force -Path build - - New-Item -ItemType Directory -Force -Path build\install-x86\python - cd build - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x86" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_CXX_FLAGS=-m32" -D"CMAKE_EXE_LINKER_FLAGS=-Wl,--large-address-aware" -D"CMAKE_C_FLAGS=-m32" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x86" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_CXX_FLAGS=-m32" -D"CMAKE_EXE_LINKER_FLAGS=-Wl,--large-address-aware" -D"CMAKE_C_FLAGS=-m32" ../ - mingw32-make install - - Move-Item -Force -path "install-x86\lib\python3.7\site-packages\*openshot*" -destination "install-x86\python\" - New-Item -path "install-x86/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - $PREV_GIT_LABEL=(git describe --tags --abbrev=0 '@^') - git log "$PREV_GIT_LABEL..@" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x86/share/$CI_PROJECT_NAME.log" diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 21405f63..42a15c8e 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -71,36 +71,44 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ### Set output name of target set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES - PREFIX "_" OUTPUT_NAME "openshot") + PREFIX "_" OUTPUT_NAME "openshot") ### Link the new python wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} - PUBLIC ${PYTHON_LIBRARIES} openshot) + target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} PUBLIC + ${PYTHON_LIBRARIES} openshot) - ### Check if the following Debian-friendly python module path exists - SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - if (NOT EXISTS ${PYTHON_MODULE_PATH}) + ######### INSTALL PATH ######## + if (NOT DEFINED PYTHON_MODULE_PATH AND DEFINED $ENV{PYTHON_MODULE_PATH}) + set(PYTHON_MODULE_PATH $ENV{PYTHON_MODULE_PATH}) + endif() - ### Calculate the python module path (using distutils) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + if (NOT DEFINED PYTHON_MODULE_PATH) + if (WIN32 OR APPLE) + set (PYTHON_MODULE_PATH "python") + endif() + + if (UNIX AND NOT APPLE) + ### Check if the following Debian-friendly python module path exists + set(PYTHON_MODULE_PATH "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") + if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") + + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) +print( get_python_lib( plat_specific=True, prefix='' ) )" + OUTPUT_VARIABLE PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + endif() + endif() + endif() - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) - endif() - message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") + message(STATUS "PYTHON_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ ### Install Python bindings - INSTALL(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} - LIBRARY DESTINATION ${PYTHON_MODULE_PATH} ) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py - DESTINATION ${PYTHON_MODULE_PATH} ) + install(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} + DESTINATION ${PYTHON_MODULE_PATH} ) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py + DESTINATION ${PYTHON_MODULE_PATH} ) endif () diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index bf7e6421..8be7d792 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -36,56 +36,74 @@ if (POLICY CMP0086) cmake_policy(SET CMP0086 OLD) endif() -FIND_PACKAGE(Ruby) -IF (RUBY_FOUND) +find_package(Ruby) +if (NOT RUBY_FOUND) + return() +endif() - ### Include the Ruby header files - INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +### Include the Ruby header files +INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - ### Enable C++ in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) +### Enable C++ in SWIG +set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - ### Suppress a ton of warnings in the generated SWIG C++ code - set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ +### Suppress a ton of warnings in the generated SWIG C++ code +set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") - separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) - set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) +separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) +set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) - ### Take include dirs from target, automatically if possible - if (CMAKE_VERSION VERSION_GREATER 3.13) - set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) - else () - set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) - endif () +### Take include dirs from target, automatically if possible +if (CMAKE_VERSION VERSION_GREATER 3.13) + set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) +else () + set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) +endif () - ### Add the SWIG interface file (which defines all the SWIG methods) - if (CMAKE_VERSION VERSION_LESS 3.8.0) - swig_add_module(rbopenshot ruby openshot.i) - else() - swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) - endif() +### Add the SWIG interface file (which defines all the SWIG methods) +if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(rbopenshot ruby openshot.i) +else() + swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) +endif() - ### Set name of target (with no prefix, since Ruby does not like that) - SET_TARGET_PROPERTIES(${SWIG_MODULE_rbopenshot_REAL_NAME} PROPERTIES - PREFIX "" OUTPUT_NAME "openshot") +### Set name of target (with no prefix, since Ruby does not like that) +set_target_properties(${SWIG_MODULE_rbopenshot_REAL_NAME} PROPERTIES + PREFIX "" OUTPUT_NAME "openshot") - ### Link the new Ruby wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} - ${RUBY_LIBRARY} openshot) +### Link the new Ruby wrapper library with libopenshot +target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} PUBLIC + ${RUBY_LIBRARY} openshot) - ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} - -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" - OUTPUT_VARIABLE RUBY_VENDOR_ARCH_DIR) - MESSAGE(STATUS "Ruby executable: ${RUBY_EXECUTABLE}") - MESSAGE(STATUS "Ruby vendor arch dir: ${RUBY_VENDOR_ARCH_DIR}") - MESSAGE(STATUS "Ruby include path: ${RUBY_INCLUDE_PATH}") +######### INSTALL PATH ######## +if (NOT DEFINED RUBY_MODULE_PATH AND DEFINED $ENV{RUBY_MODULE_PATH}) + set(RUBY_MODULE_PATH $ENV{RUBY_MODULE_PATH}) +endif() - ############### INSTALL HEADERS & LIBRARY ################ - # Install Ruby bindings - install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} - LIBRARY DESTINATION ${RUBY_VENDOR_ARCH_DIR} ) +if (NOT DEFINED RUBY_MODULE_PATH) + if (WIN32 OR APPLE) + set (RUBY_MODULE_PATH "ruby") + endif() + + if (UNIX AND NOT APPLE) + ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) + execute_process(COMMAND ${RUBY_EXECUTABLE} -r rbconfig + -e "dir = RbConfig::CONFIG['vendorarchdir']" + -e "dir.start_with?(RbConfig::CONFIG['prefix']) && dir.sub!(RbConfig::CONFIG['prefix']+'/', '')" + -e "p dir" + OUTPUT_VARIABLE RUBY_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + # Ruby quotes its output strings + string(REPLACE "\"" "" RUBY_MODULE_PATH "${RUBY_MODULE_PATH}") + endif() +endif() + +message(STATUS "RUBY_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${RUBY_MODULE_PATH}") + +############### INSTALL HEADERS & LIBRARY ################ +# Install Ruby bindings +install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} + DESTINATION ${RUBY_MODULE_PATH} ) -ENDIF (RUBY_FOUND) From f5ab99fa9e3a0fdf5bf11367468227bc493945d6 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 9 Mar 2020 09:20:04 -0400 Subject: [PATCH 008/100] Travis: Use CMAKE_INSTALL_PREFIX --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a89aa74f..c7aa1958 100644 --- a/.travis.yml +++ b/.travis.yml @@ -157,10 +157,10 @@ matrix: script: - mkdir -p build; cd build; - - cmake -DCMAKE_BUILD_TYPE:STRING="Debug" ${CMAKE_EXTRA_ARGS} ../ + - cmake -DCMAKE_INSTALL_PREFIX:PATH="$TRAVIS_OS_NAME-x64" -DCMAKE_BUILD_TYPE:STRING="Debug" ${CMAKE_EXTRA_ARGS} ../ - make VERBOSE=1 - make ${TEST_TARGET} - - make install DESTDIR="$BUILD_VERSION" + - make install - cd .. after_success: From 8b3167a99aa5220ec827a6eac5ce5171336b0eb0 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 9 Mar 2020 16:49:06 -0500 Subject: [PATCH 009/100] Adding ability for a Clip to auto-detect and instantiate a Timeline Reader from the *.osp file type. Added new Timeline constructor, to auto load UTF-8 JSON file, and regex convert all paths to absolute. Fixed a dead lock issue when a Timeline loads another Timeline. --- include/Settings.h | 4 ++ include/Timeline.h | 7 +++ src/Clip.cpp | 23 +++++++-- src/Timeline.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 142 insertions(+), 5 deletions(-) diff --git a/include/Settings.h b/include/Settings.h index 56a84fd7..e82bf56b 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -124,6 +124,10 @@ namespace openshot { /// The audio device name to use during playback std::string PLAYBACK_AUDIO_DEVICE_NAME = ""; + /// The current install path of OpenShot (needs to be set when using Timeline(path), since certain + /// paths depend on the location of OpenShot transitions and files) + std::string PATH_OPENSHOT_INSTALL = ""; + /// Create or get an instance of this logger singleton (invoke the class with this method) static Settings * Instance(); }; diff --git a/include/Timeline.h b/include/Timeline.h index 70c6e1a8..56a89586 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "CacheBase.h" #include "CacheDisk.h" #include "CacheMemory.h" @@ -156,6 +157,7 @@ namespace openshot { CacheBase *final_cache; /// allocated_frame_mappers; ///< all the frame mappers we allocated and must free bool managed_cache; ///< Does this timeline instance manage the cache object + std::string path; ///< Optional path of loaded UTF-8 OpenShot JSON project file /// Process a new layer of video or audio void add_layer(std::shared_ptr new_frame, Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume); @@ -209,6 +211,11 @@ namespace openshot { /// @param channel_layout The channel layout (i.e. mono, stereo, 3 point surround, etc...) Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout); + /// @brief Constructor for the timeline (which loads a JSON structure from a file path, and initializes a timeline) + /// @param projectPath The path of the UTF-8 *.osp project file (JSON contents). Contents will be loaded automatically. + /// @param convert_absolute_paths Should all paths be converted to absolute paths (based on the folder of the path provided) + Timeline(std::string projectPath, bool convert_absolute_paths); + virtual ~Timeline(); /// @brief Add an openshot::Clip to the timeline diff --git a/src/Clip.cpp b/src/Clip.cpp index 695fb9a1..1968bb3b 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -38,6 +38,7 @@ #include "../include/QtImageReader.h" #include "../include/ChunkReader.h" #include "../include/DummyReader.h" +#include "../include/Timeline.h" using namespace openshot; @@ -159,7 +160,7 @@ Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL), // Get file extension (and convert to lower case) std::string ext = get_file_extension(path); - transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); // Determine if common video formats if (ext=="avi" || ext=="mov" || ext=="mkv" || ext=="mpg" || ext=="mpeg" || ext=="mp3" || ext=="mp4" || ext=="mts" || @@ -172,6 +173,16 @@ Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL), } catch(...) { } } + if (ext=="osp") + { + try + { + // Open common video format + reader = new Timeline(path, true); + + } catch(...) { } + } + // If no video found, try each reader if (!reader) @@ -319,12 +330,10 @@ std::shared_ptr Clip::GetFrame(int64_t requested_frame) // Now that we have re-mapped what frame number is needed, go and get the frame pointer std::shared_ptr original_frame; - #pragma omp critical (Clip_GetFrame) original_frame = GetOrCreateFrame(new_frame_number); // Create a new frame std::shared_ptr frame(new Frame(new_frame_number, 1, 1, "#000000", original_frame->GetAudioSamplesCount(), original_frame->GetAudioChannelsCount())); - #pragma omp critical (Clip_GetFrame) { frame->SampleRate(original_frame->SampleRate()); frame->ChannelsLayout(original_frame->ChannelsLayout()); @@ -789,6 +798,8 @@ Json::Value Clip::JsonValue() const { if (reader) root["reader"] = reader->JsonValue(); + else + root["reader"] = Json::Value(Json::objectValue); // return JsonValue return root; @@ -964,6 +975,12 @@ void Clip::SetJsonValue(const Json::Value root) { // Create new reader reader = new DummyReader(); reader->SetJsonValue(root["reader"]); + + } else if (type == "Timeline") { + + // Create new reader (always load from file again) + // This prevents FrameMappers from being loaded on accident + reader = new Timeline(root["reader"]["path"].asString(), true); } // mark as managed reader and set parent diff --git a/src/Timeline.cpp b/src/Timeline.cpp index b5a33920..671e2884 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -34,7 +34,7 @@ using namespace openshot; // Default Constructor for the timeline (which sets the canvas width and height) Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout) : - is_open(false), auto_map_clips(true), managed_cache(true) + is_open(false), auto_map_clips(true), managed_cache(true), path("") { // Create CrashHandler and Attach (incase of errors) CrashHandler::Instance(); @@ -64,6 +64,8 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha info.display_ratio = openshot::Fraction(width, height); info.display_ratio.Reduce(); info.pixel_ratio = openshot::Fraction(1, 1); + info.acodec = "openshot::timeline"; + info.vcodec = "openshot::timeline"; // Init max image size SetMaxSize(info.width, info.height); @@ -73,6 +75,107 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); } +// Constructor for the timeline (which loads a JSON structure from a file path, and initializes a timeline) +Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) : + is_open(false), auto_map_clips(true), managed_cache(true), path(projectPath) { + + // Create CrashHandler and Attach (incase of errors) + CrashHandler::Instance(); + + // Init final cache as NULL (will be created after loading json) + final_cache = NULL; + + // Init viewport size (curve based, because it can be animated) + viewport_scale = Keyframe(100.0); + viewport_x = Keyframe(0.0); + viewport_y = Keyframe(0.0); + + // Init background color + color.red = Keyframe(0.0); + color.green = Keyframe(0.0); + color.blue = Keyframe(0.0); + + // Check if path exists + QFileInfo filePath(QString::fromStdString(path)); + if (!filePath.exists()) { + throw InvalidFile("File could not be opened.", path); + } + + // Check OpenShot Install Path exists + Settings *s = Settings::Instance(); + QDir openshotPath(QString::fromStdString(s->PATH_OPENSHOT_INSTALL)); + if (!openshotPath.exists()) { + throw InvalidFile("PATH_OPENSHOT_INSTALL could not be found.", s->PATH_OPENSHOT_INSTALL); + } + QDir openshotTransPath(openshotPath.filePath("transitions")); + if (!openshotTransPath.exists()) { + throw InvalidFile("PATH_OPENSHOT_INSTALL/transitions could not be found.", openshotTransPath.path().toStdString()); + } + + // Determine asset path + QString asset_name = filePath.baseName().left(30) + "_assets"; + QDir asset_folder(filePath.dir().filePath(asset_name)); + if (!asset_folder.exists()) { + // Create directory if needed + asset_folder.makeAbsolute(); + } + + // Load UTF-8 project file into QString + QFile projectFile(QString::fromStdString(path)); + projectFile.open(QFile::ReadOnly); + QString projectContents = QString::fromUtf8(projectFile.readAll()); + + // Convert all relative paths into absolute paths (does not support relative paths with ../) + // In otherwords, assets and files must be located in a child/sub-folder (and not from outside this folder) + if (convert_absolute_paths) { + // Convert all paths into absolute (if requested) + QRegularExpression pathRegex(QStringLiteral("\"(image|path)\":.*?\"(?:\\./)?(?!@assets|@transitions+)(.*?)\"")); + projectContents.replace(pathRegex, "\"\\1\": \"" + filePath.absoluteDir().absoluteFilePath("\\2") + "\""); + + // Convert all transitions paths into absolute (if requested) + QRegularExpression transRegex(QStringLiteral("\"(image|path)\":.*?\"@transitions/*(.*?)\"")); + projectContents.replace(transRegex, "\"\\1\": \"" + openshotTransPath.absoluteFilePath("\\2") + "\""); + + // Convert all assets paths into absolute + QRegularExpression assetRegex(QStringLiteral("\"(image|path)\":.*?\"@assets/*(.*?)\"")); + projectContents.replace(assetRegex, "\"\\1\": \"" + asset_folder.absoluteFilePath("\\2") + "\""); + } + + // Set JSON of project + SetJson(projectContents.toStdString()); + + // Calculate valid duration and set has_audio and has_video + // based on content inside this Timeline's clips. + float calculated_duration = 0.0; + for (auto clip : clips) + { + float clip_last_frame = clip->Position() + clip->Duration(); + if (clip_last_frame > calculated_duration) + calculated_duration = clip_last_frame; + if (clip->Reader() && clip->Reader()->info.has_audio) + info.has_audio = true; + if (clip->Reader() && clip->Reader()->info.has_video) + info.has_video = true; + + } + info.video_length = calculated_duration * info.fps.ToFloat(); + info.duration = calculated_duration; + + // Init FileInfo settings + info.acodec = "openshot::timeline"; + info.vcodec = "openshot::timeline"; + info.video_timebase = info.fps.Reciprocal(); + info.has_video = true; + info.has_audio = true; + + // Init max image size + SetMaxSize(info.width, info.height); + + // Init cache + final_cache = new CacheMemory(); + final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); +} + Timeline::~Timeline() { if (is_open) // Auto Close if not already @@ -706,7 +809,8 @@ void Timeline::Close() is_open = false; // Clear cache - final_cache->Clear(); + if (final_cache) + final_cache->Clear(); } // Open the reader (and start consuming resources) @@ -984,6 +1088,7 @@ Json::Value Timeline::JsonValue() const { root["viewport_x"] = viewport_x.JsonValue(); root["viewport_y"] = viewport_y.JsonValue(); root["color"] = color.JsonValue(); + root["path"] = path; // Add array of clips root["clips"] = Json::Value(Json::arrayValue); @@ -1037,6 +1142,10 @@ void Timeline::SetJsonValue(const Json::Value root) { // Set parent data ReaderBase::SetJsonValue(root); + // Set data from Json (if key is found) + if (!root["path"].isNull()) + path = root["path"].asString(); + if (!root["clips"].isNull()) { // Clear existing clips clips.clear(); From de42a90f5a36961cc1b4feb24b461fb40bf15600 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 9 Mar 2020 18:22:41 -0500 Subject: [PATCH 010/100] Adding stale bot for github issue management --- .github/stale.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..b9a4dee7 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,18 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security + - enhancement +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as **stale** because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false \ No newline at end of file From 4ea362380acffbcf96b0c9087e321eacf63921f0 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 10 Mar 2020 17:35:21 -0500 Subject: [PATCH 011/100] Adding support for proper absolute/canonical path detection and replacement --- src/Timeline.cpp | 50 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 671e2884..61ce31e3 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -117,7 +117,7 @@ Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) : QDir asset_folder(filePath.dir().filePath(asset_name)); if (!asset_folder.exists()) { // Create directory if needed - asset_folder.makeAbsolute(); + asset_folder.mkpath("."); } // Load UTF-8 project file into QString @@ -125,20 +125,46 @@ Timeline::Timeline(std::string projectPath, bool convert_absolute_paths) : projectFile.open(QFile::ReadOnly); QString projectContents = QString::fromUtf8(projectFile.readAll()); - // Convert all relative paths into absolute paths (does not support relative paths with ../) - // In otherwords, assets and files must be located in a child/sub-folder (and not from outside this folder) + // Convert all relative paths into absolute paths (if requested) if (convert_absolute_paths) { - // Convert all paths into absolute (if requested) - QRegularExpression pathRegex(QStringLiteral("\"(image|path)\":.*?\"(?:\\./)?(?!@assets|@transitions+)(.*?)\"")); - projectContents.replace(pathRegex, "\"\\1\": \"" + filePath.absoluteDir().absoluteFilePath("\\2") + "\""); - // Convert all transitions paths into absolute (if requested) - QRegularExpression transRegex(QStringLiteral("\"(image|path)\":.*?\"@transitions/*(.*?)\"")); - projectContents.replace(transRegex, "\"\\1\": \"" + openshotTransPath.absoluteFilePath("\\2") + "\""); + // Find all "image" or "path" references in JSON (using regex). Must loop through match results + // due to our path matching needs, which are not possible with the QString::replace() function. + QRegularExpression allPathsRegex(QStringLiteral("\"(image|path)\":.*?\"(.*?)\"")); + std::vector matchedPositions; + QRegularExpressionMatchIterator i = allPathsRegex.globalMatch(projectContents); + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + if (match.hasMatch()) { + // Push all match objects into a vector (so we can reverse them later) + matchedPositions.push_back(match); + } + } - // Convert all assets paths into absolute - QRegularExpression assetRegex(QStringLiteral("\"(image|path)\":.*?\"@assets/*(.*?)\"")); - projectContents.replace(assetRegex, "\"\\1\": \"" + asset_folder.absoluteFilePath("\\2") + "\""); + // Reverse the matches (bottom of file to top, so our replacements don't break our match positions) + std::vector::reverse_iterator itr; + for (itr = matchedPositions.rbegin(); itr != matchedPositions.rend(); itr++) { + QRegularExpressionMatch match = *itr; + QString relativeKey = match.captured(1); // image or path + QString relativePath = match.captured(2); // relative file path + QString absolutePath = ""; + + // Find absolute path of all path, image (including special replacements of @assets and @transitions) + if (relativePath.startsWith("@assets")) { + absolutePath = QFileInfo(asset_folder.absoluteFilePath(relativePath.replace("@assets", "."))).canonicalFilePath(); + } else if (relativePath.startsWith("@transitions")) { + absolutePath = QFileInfo(openshotTransPath.absoluteFilePath(relativePath.replace("@transitions", "."))).canonicalFilePath(); + } else { + absolutePath = QFileInfo(filePath.absoluteDir().absoluteFilePath(relativePath)).canonicalFilePath(); + } + + // Replace path in JSON content, if an absolute path was successfully found + if (!absolutePath.isEmpty()) { + projectContents.replace(match.capturedStart(0), match.capturedLength(0), "\"" + relativeKey + "\": \"" + absolutePath + "\""); + } + } + // Clear matches + matchedPositions.clear(); } // Set JSON of project From a21e3283c15a86e533b17d626ec18a28d62f3b48 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 10 Mar 2020 17:46:49 -0500 Subject: [PATCH 012/100] Updating auto-stale conditions (90 days warning, 10 days to respond, only issues, ignore assigned issues) --- .github/stale.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index b9a4dee7..c5ec1048 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Number of days of inactivity before an issue becomes stale -daysUntilStale: 60 +daysUntilStale: 90 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 +daysUntilClose: 10 # Issues with these labels will never be considered stale exemptLabels: - pinned @@ -15,4 +15,8 @@ markComment: > recent activity. It will be closed if no further activity occurs. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false +# Only close issues +only: issues +# Don't close issues which are assigned to somebody +exemptAssignees: true From 4058dde300629f97fe2f6a2999d42cd9f90b0649 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Tue, 10 Mar 2020 23:56:27 -0400 Subject: [PATCH 013/100] ReaderBase_Tests: 100% internal coverage (#462) --- tests/ReaderBase_Tests.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp index e3062bc1..776529d3 100644 --- a/tests/ReaderBase_Tests.cpp +++ b/tests/ReaderBase_Tests.cpp @@ -49,9 +49,9 @@ TEST(ReaderBase_Derived_Class) std::shared_ptr GetFrame(int64_t number) { std::shared_ptr f(new Frame()); return f; } void Close() { }; void Open() { }; - string Json() const { return NULL; }; + string Json() const { return ""; }; void SetJson(string value) { }; - Json::Value JsonValue() const { return (int) NULL; }; + Json::Value JsonValue() const { return Json::Value("{}"); }; void SetJsonValue(Json::Value root) { }; bool IsOpen() { return true; }; string Name() { return "TestReader"; }; @@ -60,6 +60,23 @@ TEST(ReaderBase_Derived_Class) // Create an instance of the derived class TestReader t1; + // Validate the new class + CHECK_EQUAL("TestReader", t1.Name()); + + t1.Close(); + t1.Open(); + CHECK_EQUAL(true, t1.IsOpen()); + + CHECK_EQUAL(true, t1.GetCache() == NULL); + + t1.SetJson("{ }"); + t1.SetJsonValue(Json::Value("{}")); + CHECK_EQUAL("", t1.Json()); + auto json = t1.JsonValue(); + CHECK_EQUAL(json, Json::Value("{}")); + + auto f = t1.GetFrame(1); + // Check some of the default values of the FileInfo struct on the base class CHECK_EQUAL(false, t1.info.has_audio); CHECK_EQUAL(false, t1.info.has_audio); From e19291a362c68baf77c6199b9693dd699f6a11e7 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 12 Mar 2020 09:32:26 -0400 Subject: [PATCH 014/100] Travis: Drop extra FFmpeg 3.4 GCC job (#463) --- .travis.yml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index a89aa74f..e2c3d5f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ addons: matrix: include: - - name: "Coverage (Ubuntu 18.04 Bionic)" + - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" env: - BUILD_VERSION=coverage_ffmpeg34 - CMAKE_EXTRA_ARGS="-DENABLE_COVERAGE=1" @@ -50,6 +50,7 @@ matrix: packages: - *ff_common - qt5-default + - libjsoncpp-dev - lcov - binutils-common # For c++filt @@ -80,23 +81,6 @@ matrix: - libavresample4 - libswresample3 - - name: "FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" - env: - - BUILD_VERSION=ffmpeg34 - - CMAKE_EXTRA_ARGS="" - - TEST_TARGET=test - os: linux - dist: bionic - addons: - apt: - sources: - - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' - packages: - - *ff_common - - qt5-default - - libjsoncpp-dev - - name: "FFmpeg 3.4 Clang (Ubuntu 18.04 Bionic)" env: - BUILD_VERSION=clang_ffmpeg34 From 816118b6f62743142839b9a73631b7a9d7518a4e Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 12 Mar 2020 09:35:00 -0400 Subject: [PATCH 015/100] CMake: Use GNUInstallDirs for install paths (#457) --- src/CMakeLists.txt | 97 +++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a544982e..a57780b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,23 +27,25 @@ # Collect and display summary of options/dependencies include(FeatureSummary) +include(GNUInstallDirs) ################ WINDOWS ################## # Set some compiler options for Windows # required for libopenshot-audio headers -IF (WIN32) +if (WIN32) add_definitions( -DIGNORE_JUCE_HYPOT=1 ) - SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath") -ENDIF(WIN32) -IF (APPLE) - # If you still get errors compiling with GCC 4.8, mac headers need to be patched: http://hamelot.co.uk/programming/osx-gcc-dispatch_block_t-has-not-been-declared-invalid-typedef/ - SET_PROPERTY(GLOBAL PROPERTY JUCE_MAC "JUCE_MAC") - ADD_DEFINITIONS(-DNDEBUG) - SET(EXTENSION "mm") + set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath") +endif() - SET(JUCE_PLATFORM_SPECIFIC_DIR build/macosx/platform_specific_code) - SET(JUCE_PLATFORM_SPECIFIC_LIBRARIES "-framework Carbon -framework Cocoa -framework CoreFoundation -framework CoreAudio -framework CoreMidi -framework IOKit -framework AGL -framework AudioToolbox -framework QuartzCore -lobjc -framework Accelerate") -ENDIF(APPLE) +if (APPLE) + # If you still get errors compiling with GCC 4.8, mac headers need to be patched: http://hamelot.co.uk/programming/osx-gcc-dispatch_block_t-has-not-been-declared-invalid-typedef/ + set_property(GLOBAL PROPERTY JUCE_MAC "JUCE_MAC") + add_definitions(-DNDEBUG) + set(EXTENSION "mm") + + set(JUCE_PLATFORM_SPECIFIC_DIR build/macosx/platform_specific_code) + set(JUCE_PLATFORM_SPECIFIC_LIBRARIES "-framework Carbon -framework Cocoa -framework CoreFoundation -framework CoreAudio -framework CoreMidi -framework IOKit -framework AGL -framework AudioToolbox -framework QuartzCore -lobjc -framework Accelerate") +endif() ################ IMAGE MAGICK ################## # Set the Quantum Depth that ImageMagick was built with (default to 16 bits) @@ -64,39 +66,40 @@ ELSE (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) ENDIF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) # Find the ImageMagick++ library -FIND_PACKAGE(ImageMagick COMPONENTS Magick++ MagickWand MagickCore) -IF (ImageMagick_FOUND) +find_package(ImageMagick COMPONENTS Magick++ MagickWand MagickCore) +if (ImageMagick_FOUND) # Include ImageMagick++ headers (needed for compile) include_directories(${ImageMagick_INCLUDE_DIRS}) # define a global var (used in the C++) add_definitions( -DUSE_IMAGEMAGICK=1 ) - SET(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") + set(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") -ENDIF (ImageMagick_FOUND) +endif() ################# LIBOPENSHOT-AUDIO ################### # Find JUCE-based openshot Audio libraries -FIND_PACKAGE(OpenShotAudio 0.2.0 REQUIRED) +find_package(OpenShotAudio 0.2.0 REQUIRED) # Include Juce headers (needed for compile) include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) ################# BLACKMAGIC DECKLINK ################### # Find BlackMagic DeckLinkAPI libraries -IF (ENABLE_BLACKMAGIC) - FIND_PACKAGE(BlackMagic) +if (ENABLE_BLACKMAGIC) - IF (BLACKMAGIC_FOUND) + find_package(BlackMagic) + + if (BLACKMAGIC_FOUND) # Include Blackmagic headers (needed for compile) include_directories(${BLACKMAGIC_INCLUDE_DIR}) # define a global var (used in the C++) add_definitions( -DUSE_BLACKMAGIC=1 ) - SET(CMAKE_SWIG_FLAGS "-DUSE_BLACKMAGIC=1") + set(CMAKE_SWIG_FLAGS "-DUSE_BLACKMAGIC=1") + endif() - ENDIF (BLACKMAGIC_FOUND) -ENDIF (ENABLE_BLACKMAGIC) +endif() ############### PROFILING ################# #set(PROFILER "/usr/lib/libprofiler.so.0.3.2") @@ -193,7 +196,7 @@ set(QT_PLAYER_SOURCES file(GLOB_RECURSE OPENSHOT_QT_HEADERS ${CMAKE_SOURCE_DIR}/include/Qt/*.h) # Disable RPATH -SET(CMAKE_MACOSX_RPATH 0) +set(CMAKE_MACOSX_RPATH 0) ############### CREATE LIBRARY ################# # Create shared openshot library @@ -293,7 +296,7 @@ endforeach() ################### FFMPEG ##################### # Find FFmpeg libraries (used for video encoding / decoding) -FIND_PACKAGE(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale) +find_package(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale) foreach(ff_comp avcodec avdevice avformat avfilter avutil postproc swscale swresample avresample) if(TARGET FFmpeg::${ff_comp}) @@ -389,9 +392,9 @@ add_executable(openshot-example examples/Example.cpp) # Define path to test input files SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") -IF (WIN32) +if (WIN32) STRING(REPLACE "/" "\\\\" TEST_MEDIA_PATH TEST_MEDIA_PATH) -ENDIF(WIN32) +endif() target_compile_definitions(openshot-example PRIVATE -DTEST_MEDIA_PATH="${TEST_MEDIA_PATH}" ) @@ -409,42 +412,40 @@ add_executable(openshot-player Qt/demo/main.cpp) target_link_libraries(openshot-player openshot) ############### TEST BLACKMAGIC CAPTURE APP ################ -IF (BLACKMAGIC_FOUND) +if (BLACKMAGIC_FOUND) # Create test executable add_executable(openshot-blackmagic examples/ExampleBlackmagic.cpp) # Link test executable to the new library target_link_libraries(openshot-blackmagic openshot) -ENDIF (BLACKMAGIC_FOUND) +endif() ############### INCLUDE SWIG BINDINGS ################ add_subdirectory(bindings) ############### INSTALL HEADERS & LIBRARY ################ -set(LIB_INSTALL_DIR lib${LIB_SUFFIX}) # determine correct lib folder # Install primary library -INSTALL(TARGETS openshot - ARCHIVE DESTINATION ${LIB_INSTALL_DIR} - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - RUNTIME DESTINATION ${LIB_INSTALL_DIR} - COMPONENT library ) +install(TARGETS openshot + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}) -INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/libopenshot - FILES_MATCHING PATTERN "*.h") +install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot + FILES_MATCHING PATTERN "*.h") ############### CPACK PACKAGING ############## -IF(MINGW) - SET(CPACK_GENERATOR "NSIS") -ENDIF(MINGW) -IF(UNIX AND NOT APPLE) - SET(CPACK_GENERATOR "DEB") -ENDIF(UNIX AND NOT APPLE) -#IF(UNIX AND APPLE) -# SET(CPACK_GENERATOR "DragNDrop") -#ENDIF(UNIX AND APPLE) -SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Jonathan Thomas") #required +if(MINGW) + set(CPACK_GENERATOR "NSIS") +endif() +if(UNIX AND NOT APPLE) + set(CPACK_GENERATOR "DEB") +endif() +#if(UNIX AND APPLE) +# set(CPACK_GENERATOR "DragNDrop") +#endif() +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Jonathan Thomas") #required -INCLUDE(CPack) +include(CPack) From c28a8bf4edc82a43c6eabbdd50335d15be4da5c8 Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 16 Mar 2020 14:41:49 +0200 Subject: [PATCH 016/100] Fix float to int16_t conversion Float values after mix or gain applied can exceed the (1.0; -1.0) range. This caused distortion in audio instead of limiting values at max. --- src/FFmpegWriter.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e6a1d180..2b97ba91 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1525,11 +1525,23 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Calculate total samples total_frame_samples = samples_in_frame * channels_in_frame; - // Translate audio sample values back to 16 bit integers - for (int s = 0; s < total_frame_samples; s++, frame_position++) - // Translate sample value and copy into buffer - all_queued_samples[frame_position] = int(frame_samples_float[s] * (1 << 15)); + // Translate audio sample values back to 16 bit integers with saturation + float valF; + int16_t conv; + const int16_t max16 = 32767; + const int16_t min16 = -32768; + for (int s = 0; s < total_frame_samples; s++, frame_position++) { + valF = frame_samples_float[s] * (1 << 15); + if (valF > max16) + conv = max16; + else if (valF < min16) + conv = min16; + else + conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + // Copy into buffer + all_queued_samples[frame_position] = conv; + } // Deallocate float array delete[] frame_samples_float; From dff42011ff41cc1c2e1799e5e4601c45f743fe7e Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 16 Mar 2020 14:49:41 +0200 Subject: [PATCH 017/100] Restore default gain when adding audio Incorrect conversion of float to int16_t caused distortion that was mistakenly perceived as clipping. Now because the convertion was fixed, there is no more sense to reduce input gain of the source. --- src/FFmpegReader.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2b03994b..080a652d 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -1627,9 +1627,8 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr else partial_frame = true; - // Add samples for current channel to the frame. Reduce the volume to 98%, to prevent - // some louder samples from maxing out at 1.0 (not sure why this happens) - f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 0.98f); + // Add samples for current channel to the frame. + f->AddAudio(true, channel_filter, start, iterate_channel_buffer, samples, 1.0f); // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (f->AddAudio)", "frame", starting_frame_number, "start", start, "samples", samples, "channel", channel_filter, "partial_frame", partial_frame, "samples_per_frame", samples_per_frame); From 54a82ff0a68fb39bb875b63157cc91c549771647 Mon Sep 17 00:00:00 2001 From: SuslikV Date: Mon, 16 Mar 2020 16:22:41 +0200 Subject: [PATCH 018/100] Fix test sample values Previously, x0.98 gain was applied for all input audio sources. As it's no longer needed, the new values should be specified as reference for the tests. --- tests/FFmpegReader_Tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 0a8620c9..a1f7a42d 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -76,8 +76,8 @@ TEST(FFmpegReader_Check_Audio_File) CHECK_CLOSE(0.0f, samples[50], 0.00001); CHECK_CLOSE(0.0f, samples[100], 0.00001); CHECK_CLOSE(0.0f, samples[200], 0.00001); - CHECK_CLOSE(0.160781f, samples[230], 0.00001); - CHECK_CLOSE(-0.06125f, samples[300], 0.00001); + CHECK_CLOSE(0.16406f, samples[230], 0.00001); + CHECK_CLOSE(-0.06250f, samples[300], 0.00001); // Close reader r.Close(); From b7384605ed3e6943cf9b08bba52ae0e544a9a0c5 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 19 Mar 2020 05:55:06 -0400 Subject: [PATCH 019/100] Clip_Tests: Remove try/catch blocks --- tests/Clip_Tests.cpp | 134 +++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 82 deletions(-) diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp index c66cc9a4..f72d8b05 100644 --- a/tests/Clip_Tests.cpp +++ b/tests/Clip_Tests.cpp @@ -29,14 +29,22 @@ */ #include "UnitTest++.h" + +// Work around older versions of UnitTest++ without REQUIRE +#ifndef REQUIRE + #define REQUIRE +#endif + // Prevent name clashes with juce::UnitTest #define DONT_SET_USING_JUCE_NAMESPACE 1 #include "../include/OpenShot.h" -using namespace std; using namespace openshot; -TEST(Clip_Default_Constructor) +SUITE(Clip) +{ + +TEST(Default_Constructor) { // Create a empty clip Clip c1; @@ -54,7 +62,7 @@ TEST(Clip_Default_Constructor) TEST(Clip_Constructor) { // Create a empty clip - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "piano.wav"; Clip c1(path.str()); c1.Open(); @@ -69,7 +77,7 @@ TEST(Clip_Constructor) CHECK_CLOSE(4.39937f, c1.End(), 0.00001); } -TEST(Clip_Basic_Gettings_and_Setters) +TEST(Basic_Gettings_and_Setters) { // Create a empty clip Clip c1; @@ -96,7 +104,7 @@ TEST(Clip_Basic_Gettings_and_Setters) CHECK_CLOSE(10.5f, c1.End(), 0.00001); } -TEST(Clip_Properties) +TEST(Properties) { // Create a empty clip Clip c1; @@ -110,116 +118,75 @@ TEST(Clip_Properties) c1.alpha.AddPoint(500, 0.0); // Get properties JSON string at frame 1 - string properties = c1.PropertiesJSON(1); + std::string properties = c1.PropertiesJSON(1); // Parse JSON string into JSON objects Json::Value root; Json::CharReaderBuilder rbuilder; Json::CharReader* reader(rbuilder.newCharReader()); - string errors; - bool success = reader->parse( properties.c_str(), - properties.c_str() + properties.size(), &root, &errors ); - - if (!success) - // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)"); - - try - { - // Check for specific things - CHECK_CLOSE(1.0f, root["alpha"]["value"].asDouble(), 0.01); - CHECK_EQUAL(true, root["alpha"]["keyframe"].asBool()); - - } - catch (const std::exception& e) - { - // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); - } + std::string errors; + bool success = reader->parse( + properties.c_str(), + properties.c_str() + properties.size(), + &root, &errors ); + CHECK_EQUAL(true, success); + // Check for specific things + CHECK_CLOSE(1.0f, root["alpha"]["value"].asDouble(), 0.01); + CHECK_EQUAL(true, root["alpha"]["keyframe"].asBool()); // Get properties JSON string at frame 250 properties = c1.PropertiesJSON(250); // Parse JSON string into JSON objects root.clear(); - success = reader->parse( properties.c_str(), - properties.c_str() + properties.size(), &root, &errors ); - if (!success) - // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)"); - - try - { - // Check for specific things - CHECK_CLOSE(0.5f, root["alpha"]["value"].asDouble(), 0.01); - CHECK_EQUAL(false, root["alpha"]["keyframe"].asBool()); - - } - catch (const std::exception& e) - { - // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); - } + success = reader->parse( + properties.c_str(), + properties.c_str() + properties.size(), + &root, &errors ); + REQUIRE CHECK_EQUAL(true, success); + // Check for specific things + CHECK_CLOSE(0.5f, root["alpha"]["value"].asDouble(), 0.01); + CHECK_EQUAL(false, root["alpha"]["keyframe"].asBool()); // Get properties JSON string at frame 250 (again) - properties = c1.PropertiesJSON(250); // again + properties = c1.PropertiesJSON(250); // Parse JSON string into JSON objects root.clear(); - success = reader->parse( properties.c_str(), - properties.c_str() + properties.size(), &root, &errors ); - if (!success) - // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)"); - - try - { - // Check for specific things - CHECK_EQUAL(false, root["alpha"]["keyframe"].asBool()); - - } - catch (const std::exception& e) - { - // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); - } + success = reader->parse( + properties.c_str(), + properties.c_str() + properties.size(), + &root, &errors ); + REQUIRE CHECK_EQUAL(true, success); + // Check for specific things + CHECK_EQUAL(false, root["alpha"]["keyframe"].asBool()); // Get properties JSON string at frame 500 properties = c1.PropertiesJSON(500); // Parse JSON string into JSON objects root.clear(); - success = reader->parse( properties.c_str(), - properties.c_str() + properties.size(), &root, &errors ); - if (!success) - // Raise exception - throw InvalidJSON("JSON could not be parsed (or is invalid)"); - - try - { - // Check for specific things - CHECK_CLOSE(0.0f, root["alpha"]["value"].asDouble(), 0.00001); - CHECK_EQUAL(true, root["alpha"]["keyframe"].asBool()); - - } - catch (const std::exception& e) - { - // Error parsing JSON (or missing keys) - throw InvalidJSON("JSON is invalid (missing keys or invalid data types)"); - } + success = reader->parse( + properties.c_str(), + properties.c_str() + properties.size(), + &root, &errors ); + REQUIRE CHECK_EQUAL(true, success); + // Check for specific things + CHECK_CLOSE(0.0f, root["alpha"]["value"].asDouble(), 0.00001); + CHECK_EQUAL(true, root["alpha"]["keyframe"].asBool()); // Free up the reader we allocated delete reader; } -TEST(Clip_Effects) +TEST(Effects) { // Load clip with video - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; Clip c10(path.str()); c10.Open(); @@ -264,3 +231,6 @@ TEST(Clip_Effects) // Check the # of Effects CHECK_EQUAL(2, (int)c10.Effects().size()); } + +} // SUITE + From 818ce5ab00c55942cb3421d2c415979824e894b3 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 19 Mar 2020 06:07:03 -0400 Subject: [PATCH 020/100] Exclude thirdpart/jsoncpp from Codecov scanning --- codecov.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index dfdc9375..ee151daa 100644 --- a/codecov.yml +++ b/codecov.yml @@ -9,7 +9,8 @@ coverage: ignore: - "/src/examples" - "/src/Qt/demo" - - "/thirdparty" + - "/thirdparty/jsoncpp/*.cpp" + - "/thirdparty/jsoncpp/json/*.h" - "/doc" - "/cmake" - "/*.md" From 527acfe77a4fa17d5b0af6a8a5d2b908c170ba03 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 22 Mar 2020 12:08:40 -0400 Subject: [PATCH 021/100] FFmpegWriter: (a/v)_codec => (a/v)_codec_ctx The audio_codec and video_codec vars have type AVCodecContext. Renaming them to reflect that makes the code easier to follow. A couple of places in FFmpegUtilities macros that also used context variables named _codec got the same fix. --- include/FFmpegUtilities.h | 8 +- include/FFmpegWriter.h | 4 +- src/FFmpegWriter.cpp | 174 +++++++++++++++++++------------------- 3 files changed, 93 insertions(+), 93 deletions(-) diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 62d64df1..895b220d 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -40,7 +40,7 @@ #ifndef IS_FFMPEG_3_2 #define IS_FFMPEG_3_2 (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101)) #endif - + #ifndef HAVE_HW_ACCEL #define HAVE_HW_ACCEL (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 107, 100)) #endif @@ -178,13 +178,13 @@ #define AV_OUTPUT_CONTEXT(output_context, path) avformat_alloc_output_context2( output_context, NULL, NULL, path) #define AV_OPTION_FIND(priv_data, name) av_opt_find(priv_data, name, NULL, 0, 0) #define AV_OPTION_SET( av_stream, priv_data, name, value, avcodec) av_opt_set(priv_data, name, value, 0); avcodec_parameters_from_context(av_stream->codecpar, avcodec); - #define AV_FORMAT_NEW_STREAM(oc, st_codec, av_codec, av_st) av_st = avformat_new_stream(oc, NULL);\ + #define AV_FORMAT_NEW_STREAM(oc, st_codec_ctx, av_codec, av_st) av_st = avformat_new_stream(oc, NULL);\ if (!av_st) \ throw OutOfMemory("Could not allocate memory for the video stream.", path); \ c = avcodec_alloc_context3(av_codec); \ - st_codec = c; \ + st_codec_ctx = c; \ av_st->codecpar->codec_id = av_codec->id; - #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) avcodec_parameters_from_context(av_stream->codecpar, av_codec); + #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec_ctx) avcodec_parameters_from_context(av_stream->codecpar, av_codec_ctx); #elif IS_FFMPEG_3_2 #define AV_REGISTER_ALL av_register_all(); #define AVCODEC_REGISTER_ALL avcodec_register_all(); diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 1dfb21a9..7480663f 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -164,8 +164,8 @@ namespace openshot { AVOutputFormat *fmt; AVFormatContext *oc; AVStream *audio_st, *video_st; - AVCodecContext *video_codec; - AVCodecContext *audio_codec; + AVCodecContext *video_codec_ctx; + AVCodecContext *audio_codec_ctx; SwsContext *img_convert_ctx; double audio_pts, video_pts; int16_t *samples; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e6a1d180..435c6b47 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -87,7 +87,7 @@ FFmpegWriter::FFmpegWriter(std::string path) : path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32), - rescaler_position(0), video_codec(NULL), audio_codec(NULL), is_writing(false), write_video_count(0), write_audio_count(0), + rescaler_position(0), video_codec_ctx(NULL), audio_codec_ctx(NULL), is_writing(false), write_video_count(0), write_audio_count(0), original_sample_rate(0), original_channels(0), avr(NULL), avr_planar(NULL), is_open(false), prepare_streams(false), write_header(false), write_trailer(false), audio_encoder_buffer_size(0), audio_encoder_buffer(NULL) { @@ -339,11 +339,11 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va if (info.has_video && stream == VIDEO_STREAM && video_st) { st = video_st; // Get codec context - c = AV_GET_CODEC_PAR_CONTEXT(st, video_codec); + c = AV_GET_CODEC_PAR_CONTEXT(st, video_codec_ctx); } else if (info.has_audio && stream == AUDIO_STREAM && audio_st) { st = audio_st; // Get codec context - c = AV_GET_CODEC_PAR_CONTEXT(st, audio_codec); + c = AV_GET_CODEC_PAR_CONTEXT(st, audio_codec_ctx); } else throw NoStreamsFound("The stream was not found. Be sure to call PrepareStreams() first.", path); @@ -796,10 +796,10 @@ void FFmpegWriter::WriteTrailer() { // Flush encoders void FFmpegWriter::flush_encoders() { - if (info.has_audio && audio_codec && AV_GET_CODEC_TYPE(audio_st) == AVMEDIA_TYPE_AUDIO && AV_GET_CODEC_ATTRIBUTES(audio_st, audio_codec)->frame_size <= 1) + if (info.has_audio && audio_codec_ctx && AV_GET_CODEC_TYPE(audio_st) == AVMEDIA_TYPE_AUDIO && AV_GET_CODEC_ATTRIBUTES(audio_st, audio_codec_ctx)->frame_size <= 1) return; #if (LIBAVFORMAT_VERSION_MAJOR < 58) - if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) + if (info.has_video && video_codec_ctx && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) return; #endif @@ -811,7 +811,7 @@ void FFmpegWriter::flush_encoders() { for (;;) { // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base); + write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec_ctx->time_base); AVPacket pkt; av_init_packet(&pkt); @@ -829,22 +829,22 @@ void FFmpegWriter::flush_encoders() { #pragma omp critical (write_video_packet) { // Encode video packet (latest version of FFmpeg) - error_code = avcodec_send_frame(video_codec, NULL); + error_code = avcodec_send_frame(video_codec_ctx, NULL); got_packet = 0; while (error_code >= 0) { - error_code = avcodec_receive_packet(video_codec, &pkt); + error_code = avcodec_receive_packet(video_codec_ctx, &pkt); if (error_code == AVERROR(EAGAIN)|| error_code == AVERROR_EOF) { got_packet = 0; // Write packet - avcodec_flush_buffers(video_codec); + avcodec_flush_buffers(video_codec_ctx); break; } if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, video_codec->time_base, video_st->time_base); + pkt.pts = av_rescale_q(pkt.pts, video_codec_ctx->time_base, video_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, video_codec->time_base, video_st->time_base); + pkt.dts = av_rescale_q(pkt.dts, video_codec_ctx->time_base, video_st->time_base); if (pkt.duration > 0) - pkt.duration = av_rescale_q(pkt.duration, video_codec->time_base, video_st->time_base); + pkt.duration = av_rescale_q(pkt.duration, video_codec_ctx->time_base, video_st->time_base); pkt.stream_index = video_st->index; error_code = av_interleaved_write_frame(oc, &pkt); } @@ -853,18 +853,18 @@ void FFmpegWriter::flush_encoders() { #if LIBAVFORMAT_VERSION_MAJOR >= 54 // Encode video packet (older than FFmpeg 3.2) - error_code = avcodec_encode_video2(video_codec, &pkt, NULL, &got_packet); + error_code = avcodec_encode_video2(video_codec_ctx, &pkt, NULL, &got_packet); #else // Encode video packet (even older version of FFmpeg) int video_outbuf_size = 0; /* encode the image */ - int out_size = avcodec_encode_video(video_codec, NULL, video_outbuf_size, NULL); + int out_size = avcodec_encode_video(video_codec_ctx, NULL, video_outbuf_size, NULL); /* if zero size, it means the image was buffered */ if (out_size > 0) { - if(video_codec->coded_frame->key_frame) + if(video_codec_ctx->coded_frame->key_frame) pkt.flags |= AV_PKT_FLAG_KEY; pkt.data= video_outbuf; pkt.size= out_size; @@ -888,11 +888,11 @@ void FFmpegWriter::flush_encoders() { // set the timestamp if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, video_codec->time_base, video_st->time_base); + pkt.pts = av_rescale_q(pkt.pts, video_codec_ctx->time_base, video_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, video_codec->time_base, video_st->time_base); + pkt.dts = av_rescale_q(pkt.dts, video_codec_ctx->time_base, video_st->time_base); if (pkt.duration > 0) - pkt.duration = av_rescale_q(pkt.duration, video_codec->time_base, video_st->time_base); + pkt.duration = av_rescale_q(pkt.duration, video_codec_ctx->time_base, video_st->time_base); pkt.stream_index = video_st->index; // Write packet @@ -913,9 +913,9 @@ void FFmpegWriter::flush_encoders() { // Increment PTS (in samples and scaled to the codec's timebase) #if LIBAVFORMAT_VERSION_MAJOR >= 54 // for some reason, it requires me to multiply channels X 2 - write_audio_count += av_rescale_q(audio_input_position / (audio_codec->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), (AVRational){1, info.sample_rate}, audio_codec->time_base); + write_audio_count += av_rescale_q(audio_input_position / (audio_codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), av_make_q(1, info.sample_rate), audio_codec_ctx->time_base); #else - write_audio_count += av_rescale_q(audio_input_position / audio_codec->channels, (AVRational){1, info.sample_rate}, audio_codec->time_base); + write_audio_count += av_rescale_q(audio_input_position / audio_codec_ctx->channels, (AVRational){1, info.sample_rate}, audio_codec_ctx->time_base); #endif AVPacket pkt; @@ -927,10 +927,10 @@ void FFmpegWriter::flush_encoders() { /* encode the image */ int got_packet = 0; #if IS_FFMPEG_3_2 - avcodec_send_frame(audio_codec, NULL); + avcodec_send_frame(audio_codec_ctx, NULL); got_packet = 0; #else - error_code = avcodec_encode_audio2(audio_codec, &pkt, NULL, &got_packet); + error_code = avcodec_encode_audio2(audio_codec_ctx, &pkt, NULL, &got_packet); #endif if (error_code < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code); @@ -946,11 +946,11 @@ void FFmpegWriter::flush_encoders() { // Scale the PTS to the audio stream timebase (which is sometimes different than the codec's timebase) if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, audio_codec->time_base, audio_st->time_base); + pkt.pts = av_rescale_q(pkt.pts, audio_codec_ctx->time_base, audio_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, audio_codec->time_base, audio_st->time_base); + pkt.dts = av_rescale_q(pkt.dts, audio_codec_ctx->time_base, audio_st->time_base); if (pkt.duration > 0) - pkt.duration = av_rescale_q(pkt.duration, audio_codec->time_base, audio_st->time_base); + pkt.duration = av_rescale_q(pkt.duration, audio_codec_ctx->time_base, audio_st->time_base); // set stream pkt.stream_index = audio_st->index; @@ -1068,7 +1068,7 @@ AVStream *FFmpegWriter::add_audio_stream() { throw InvalidCodec("A valid audio codec could not be found for this file.", path); // Create a new audio stream - AV_FORMAT_NEW_STREAM(oc, audio_codec, codec, st) + AV_FORMAT_NEW_STREAM(oc, audio_codec_ctx, codec, st) c->codec_id = codec->id; #if LIBAVFORMAT_VERSION_MAJOR >= 53 @@ -1151,7 +1151,7 @@ AVStream *FFmpegWriter::add_video_stream() { throw InvalidCodec("A valid video codec could not be found for this file.", path); // Create a new video stream - AV_FORMAT_NEW_STREAM(oc, video_codec, codec, st) + AV_FORMAT_NEW_STREAM(oc, video_codec_ctx, codec, st) c->codec_id = codec->id; #if LIBAVFORMAT_VERSION_MAJOR >= 53 @@ -1281,15 +1281,15 @@ AVStream *FFmpegWriter::add_video_stream() { // open audio codec void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) { AVCodec *codec; - AV_GET_CODEC_FROM_STREAM(st, audio_codec) + AV_GET_CODEC_FROM_STREAM(st, audio_codec_ctx) // Set number of threads equal to number of processors (not to exceed 16) - audio_codec->thread_count = std::min(FF_NUM_PROCESSORS, 16); + audio_codec_ctx->thread_count = std::min(FF_NUM_PROCESSORS, 16); // Find the audio encoder codec = avcodec_find_encoder_by_name(info.acodec.c_str()); if (!codec) - codec = avcodec_find_encoder(audio_codec->codec_id); + codec = avcodec_find_encoder(audio_codec_ctx->codec_id); if (!codec) throw InvalidCodec("Could not find codec", path); @@ -1298,16 +1298,16 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) { av_dict_set(&opts, "strict", "experimental", 0); // Open the codec - if (avcodec_open2(audio_codec, codec, &opts) < 0) + if (avcodec_open2(audio_codec_ctx, codec, &opts) < 0) throw InvalidCodec("Could not open audio codec", path); - AV_COPY_PARAMS_FROM_CONTEXT(st, audio_codec); + AV_COPY_PARAMS_FROM_CONTEXT(st, audio_codec_ctx); // Free options av_dict_free(&opts); // Calculate the size of the input frame (i..e how many samples per packet), and the output buffer // TODO: Ugly hack for PCM codecs (will be removed ASAP with new PCM support to compute the input frame size in samples - if (audio_codec->frame_size <= 1) { + if (audio_codec_ctx->frame_size <= 1) { // No frame size found... so calculate audio_input_frame_size = 50000 / info.channels; @@ -1324,7 +1324,7 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) { } } else { // Set frame size based on the codec - audio_input_frame_size = audio_codec->frame_size; + audio_input_frame_size = audio_codec_ctx->frame_size; } // Set the initial frame size (since it might change during resampling) @@ -1346,16 +1346,16 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) { av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_audio", "audio_codec->thread_count", audio_codec->thread_count, "audio_input_frame_size", audio_input_frame_size, "buffer_size", AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_audio", "audio_codec_ctx->thread_count", audio_codec_ctx->thread_count, "audio_input_frame_size", audio_input_frame_size, "buffer_size", AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE); } // open video codec void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { AVCodec *codec; - AV_GET_CODEC_FROM_STREAM(st, video_codec) + AV_GET_CODEC_FROM_STREAM(st, video_codec_ctx) // Set number of threads equal to number of processors (not to exceed 16) - video_codec->thread_count = std::min(FF_NUM_PROCESSORS, 16); + video_codec_ctx->thread_count = std::min(FF_NUM_PROCESSORS, 16); #if HAVE_HW_ACCEL if (hw_en_on && hw_en_supported) { @@ -1410,8 +1410,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { throw InvalidCodec("Could not find codec", path); /* Force max_b_frames to 0 in some cases (i.e. for mjpeg image sequences */ - if (video_codec->max_b_frames && video_codec->codec_id != AV_CODEC_ID_MPEG4 && video_codec->codec_id != AV_CODEC_ID_MPEG1VIDEO && video_codec->codec_id != AV_CODEC_ID_MPEG2VIDEO) - video_codec->max_b_frames = 0; + if (video_codec_ctx->max_b_frames && video_codec_ctx->codec_id != AV_CODEC_ID_MPEG4 && video_codec_ctx->codec_id != AV_CODEC_ID_MPEG1VIDEO && video_codec_ctx->codec_id != AV_CODEC_ID_MPEG2VIDEO) + video_codec_ctx->max_b_frames = 0; // Init options AVDictionary *opts = NULL; @@ -1419,7 +1419,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { #if HAVE_HW_ACCEL if (hw_en_on && hw_en_supported) { - video_codec->pix_fmt = hw_en_av_pix_fmt; + video_codec_ctx->pix_fmt = hw_en_av_pix_fmt; // for the list of possible options, see the list of codec-specific options: // e.g. ffmpeg -h encoder=h264_vaapi or ffmpeg -h encoder=hevc_vaapi @@ -1429,23 +1429,23 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { // which is ffmpeg version-specific. if (hw_en_av_pix_fmt == AV_PIX_FMT_VAAPI) { int64_t qp; - if (av_opt_get_int(video_codec->priv_data, "qp", 0, &qp) != 0 || qp == 0) { + if (av_opt_get_int(video_codec_ctx->priv_data, "qp", 0, &qp) != 0 || qp == 0) { // unless "qp" was set for CQP, switch to VBR RC mode - av_opt_set(video_codec->priv_data, "rc_mode", "VBR", 0); + av_opt_set(video_codec_ctx->priv_data, "rc_mode", "VBR", 0); // In the current state (ffmpeg-4.2-4 libva-mesa-driver-19.1.5-1) to use VBR, // one has to specify both bit_rate and maxrate, otherwise a small low quality file is generated on Intel iGPU). - video_codec->rc_max_rate = video_codec->bit_rate; + video_codec_ctx->rc_max_rate = video_codec_ctx->bit_rate; } } - switch (video_codec->codec_id) { + switch (video_codec_ctx->codec_id) { case AV_CODEC_ID_H264: - video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames - video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; - av_opt_set(video_codec->priv_data, "preset", "slow", 0); - av_opt_set(video_codec->priv_data, "tune", "zerolatency", 0); - av_opt_set(video_codec->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); + video_codec_ctx->max_b_frames = 0; // At least this GPU doesn't support b-frames + video_codec_ctx->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; + av_opt_set(video_codec_ctx->priv_data, "preset", "slow", 0); + av_opt_set(video_codec_ctx->priv_data, "tune", "zerolatency", 0); + av_opt_set(video_codec_ctx->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); break; case AV_CODEC_ID_HEVC: // tested to work with defaults @@ -1455,13 +1455,13 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { break; default: ZmqLogger::Instance()->AppendDebugMethod("No codec-specific options defined for this codec. HW encoding may fail", - "codec_id", video_codec->codec_id); + "codec_id", video_codec_ctx->codec_id); break; } // set hw_frames_ctx for encoder's AVCodecContext int err; - if ((err = set_hwframe_ctx(video_codec, hw_device_ctx, info.width, info.height)) < 0) { + if ((err = set_hwframe_ctx(video_codec_ctx, hw_device_ctx, info.width, info.height)) < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video (set_hwframe_ctx) ERROR faled to set hwframe context", "width", info.width, "height", info.height, av_err2str(err), -1); } @@ -1469,9 +1469,9 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { #endif // HAVE_HW_ACCEL /* open the codec */ - if (avcodec_open2(video_codec, codec, &opts) < 0) + if (avcodec_open2(video_codec_ctx, codec, &opts) < 0) throw InvalidCodec("Could not open video codec", path); - AV_COPY_PARAMS_FROM_CONTEXT(st, video_codec); + AV_COPY_PARAMS_FROM_CONTEXT(st, video_codec_ctx); // Free options av_dict_free(&opts); @@ -1481,7 +1481,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video", "video_codec->thread_count", video_codec->thread_count); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video", "video_codec_ctx->thread_count", video_codec_ctx->thread_count); } @@ -1549,7 +1549,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets", "is_final", is_final, "total_frame_samples", total_frame_samples, "channel_layout_in_frame", channel_layout_in_frame, "channels_in_frame", channels_in_frame, "samples_in_frame", samples_in_frame, "LAYOUT_MONO", LAYOUT_MONO); // Keep track of the original sample format - AVSampleFormat output_sample_fmt = audio_codec->sample_fmt; + AVSampleFormat output_sample_fmt = audio_codec_ctx->sample_fmt; AVFrame *audio_frame = NULL; if (!is_final) { @@ -1565,7 +1565,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) { } // Do not convert audio to planar format (yet). We need to keep everything interleaved at this point. - switch (audio_codec->sample_fmt) { + switch (audio_codec_ctx->sample_fmt) { case AV_SAMPLE_FMT_FLTP: { output_sample_fmt = AV_SAMPLE_FMT_FLT; break; @@ -1676,8 +1676,8 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Convert to planar (if needed by audio codec) AVFrame *frame_final = AV_ALLOCATE_FRAME(); AV_RESET_FRAME(frame_final); - if (av_sample_fmt_is_planar(audio_codec->sample_fmt)) { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets (2nd resampling for Planar formats)", "in_sample_fmt", output_sample_fmt, "out_sample_fmt", audio_codec->sample_fmt, "in_sample_rate", info.sample_rate, "out_sample_rate", info.sample_rate, "in_channels", info.channels, "out_channels", info.channels); + if (av_sample_fmt_is_planar(audio_codec_ctx->sample_fmt)) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets (2nd resampling for Planar formats)", "in_sample_fmt", output_sample_fmt, "out_sample_fmt", audio_codec_ctx->sample_fmt, "in_sample_rate", info.sample_rate, "out_sample_rate", info.sample_rate, "in_channels", info.channels, "out_channels", info.channels); // setup resample context if (!avr_planar) { @@ -1685,7 +1685,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) { av_opt_set_int(avr_planar, "in_channel_layout", info.channel_layout, 0); av_opt_set_int(avr_planar, "out_channel_layout", info.channel_layout, 0); av_opt_set_int(avr_planar, "in_sample_fmt", output_sample_fmt, 0); - av_opt_set_int(avr_planar, "out_sample_fmt", audio_codec->sample_fmt, 0); // planar not allowed here + av_opt_set_int(avr_planar, "out_sample_fmt", audio_codec_ctx->sample_fmt, 0); // planar not allowed here av_opt_set_int(avr_planar, "in_sample_rate", info.sample_rate, 0); av_opt_set_int(avr_planar, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr_planar, "in_channels", info.channels, 0); @@ -1711,7 +1711,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Create output frame (and allocate arrays) frame_final->nb_samples = audio_input_frame_size; - av_samples_alloc(frame_final->data, frame_final->linesize, info.channels, frame_final->nb_samples, audio_codec->sample_fmt, 0); + av_samples_alloc(frame_final->data, frame_final->linesize, info.channels, frame_final->nb_samples, audio_codec_ctx->sample_fmt, 0); // Convert audio samples int nb_samples = SWR_CONVERT(avr_planar, // audio resample context @@ -1724,7 +1724,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Copy audio samples over original samples if (nb_samples > 0) - memcpy(samples, frame_final->data[0], nb_samples * av_get_bytes_per_sample(audio_codec->sample_fmt) * info.channels); + memcpy(samples, frame_final->data[0], nb_samples * av_get_bytes_per_sample(audio_codec_ctx->sample_fmt) * info.channels); // deallocate AVFrame av_freep(&(audio_frame->data[0])); @@ -1736,16 +1736,16 @@ void FFmpegWriter::write_audio_packets(bool is_final) { } else { // Create a new array final_samples = (int16_t *) av_malloc( - sizeof(int16_t) * audio_input_position * (av_get_bytes_per_sample(audio_codec->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); + sizeof(int16_t) * audio_input_position * (av_get_bytes_per_sample(audio_codec_ctx->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); // Copy audio into buffer for frame - memcpy(final_samples, samples, audio_input_position * av_get_bytes_per_sample(audio_codec->sample_fmt)); + memcpy(final_samples, samples, audio_input_position * av_get_bytes_per_sample(audio_codec_ctx->sample_fmt)); // Init the nb_samples property frame_final->nb_samples = audio_input_frame_size; // Fill the final_frame AVFrame with audio (non planar) - avcodec_fill_audio_frame(frame_final, audio_codec->channels, audio_codec->sample_fmt, (uint8_t *) final_samples, + avcodec_fill_audio_frame(frame_final, audio_codec_ctx->channels, audio_codec_ctx->sample_fmt, (uint8_t *) final_samples, audio_encoder_buffer_size, 0); } @@ -1770,18 +1770,18 @@ void FFmpegWriter::write_audio_packets(bool is_final) { int error_code; int ret = 0; int frame_finished = 0; - error_code = ret = avcodec_send_frame(audio_codec, frame_final); + error_code = ret = avcodec_send_frame(audio_codec_ctx, frame_final); if (ret < 0 && ret != AVERROR(EINVAL) && ret != AVERROR_EOF) { - avcodec_send_frame(audio_codec, NULL); + avcodec_send_frame(audio_codec_ctx, NULL); } else { if (ret >= 0) pkt.size = 0; - ret = avcodec_receive_packet(audio_codec, &pkt); + ret = avcodec_receive_packet(audio_codec_ctx, &pkt); if (ret >= 0) frame_finished = 1; if(ret == AVERROR(EINVAL) || ret == AVERROR_EOF) { - avcodec_flush_buffers(audio_codec); + avcodec_flush_buffers(audio_codec_ctx); ret = 0; } if (ret >= 0) { @@ -1795,7 +1795,7 @@ void FFmpegWriter::write_audio_packets(bool is_final) { got_packet_ptr = ret; #else // Encode audio (older versions of FFmpeg) - int error_code = avcodec_encode_audio2(audio_codec, &pkt, frame_final, &got_packet_ptr); + int error_code = avcodec_encode_audio2(audio_codec_ctx, &pkt, frame_final, &got_packet_ptr); #endif /* if zero size, it means the image was buffered */ if (error_code == 0 && got_packet_ptr) { @@ -1806,11 +1806,11 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Scale the PTS to the audio stream timebase (which is sometimes different than the codec's timebase) if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, audio_codec->time_base, audio_st->time_base); + pkt.pts = av_rescale_q(pkt.pts, audio_codec_ctx->time_base, audio_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, audio_codec->time_base, audio_st->time_base); + pkt.dts = av_rescale_q(pkt.dts, audio_codec_ctx->time_base, audio_st->time_base); if (pkt.duration > 0) - pkt.duration = av_rescale_q(pkt.duration, audio_codec->time_base, audio_st->time_base); + pkt.duration = av_rescale_q(pkt.duration, audio_codec_ctx->time_base, audio_st->time_base); // set stream pkt.stream_index = audio_st->index; @@ -1924,7 +1924,7 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) { frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); } #else - AVFrame *frame_final = allocate_avframe(video_codec->pix_fmt, info.width, info.height, &bytes_final, NULL); + AVFrame *frame_final = allocate_avframe(video_codec_ctx->pix_fmt, info.width, info.height, &bytes_final, NULL); #endif // IS_FFMPEG_3_2 // Fill with data @@ -1964,7 +1964,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra pkt.size = sizeof(AVPicture); // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base); + write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec_ctx->time_base); pkt.pts = write_video_count; /* write the compressed frame in the media file */ @@ -1991,7 +1991,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra uint8_t *video_outbuf = NULL; // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base); + write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec_ctx->time_base); // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; @@ -2000,7 +2000,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra if (!(hw_frame = av_frame_alloc())) { fprintf(stderr, "Error code: av_hwframe_alloc\n"); } - if (av_hwframe_get_buffer(video_codec->hw_frames_ctx, hw_frame, 0) < 0) { + if (av_hwframe_get_buffer(video_codec_ctx->hw_frames_ctx, hw_frame, 0) < 0) { fprintf(stderr, "Error code: av_hwframe_get_buffer\n"); } if (!hw_frame->hw_frames_ctx) { @@ -2023,11 +2023,11 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra #if HAVE_HW_ACCEL if (hw_en_on && hw_en_supported) { - ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! + ret = avcodec_send_frame(video_codec_ctx, hw_frame); //hw_frame!!! } else #endif // HAVE_HW_ACCEL { - ret = avcodec_send_frame(video_codec, frame_final); + ret = avcodec_send_frame(video_codec_ctx, frame_final); } error_code = ret; if (ret < 0 ) { @@ -2038,14 +2038,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra if (ret == AVERROR_EOF ) { std::cerr << "Frame AVERROR_EOF" << "\n"; } - avcodec_send_frame(video_codec, NULL); + avcodec_send_frame(video_codec_ctx, NULL); } else { while (ret >= 0) { - ret = avcodec_receive_packet(video_codec, &pkt); + ret = avcodec_receive_packet(video_codec_ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { - avcodec_flush_buffers(video_codec); + avcodec_flush_buffers(video_codec_ctx); got_packet_ptr = 0; break; } @@ -2058,7 +2058,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra #else #if LIBAVFORMAT_VERSION_MAJOR >= 54 // Write video packet (older than FFmpeg 3.2) - error_code = avcodec_encode_video2(video_codec, &pkt, frame_final, &got_packet_ptr); + error_code = avcodec_encode_video2(video_codec_ctx, &pkt, frame_final, &got_packet_ptr); if (error_code != 0) { std::cerr << "Frame AVERROR_EOF" << "\n"; } @@ -2071,11 +2071,11 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra video_outbuf = (uint8_t*) av_malloc(200000); /* encode the image */ - int out_size = avcodec_encode_video(video_codec, video_outbuf, video_outbuf_size, frame_final); + int out_size = avcodec_encode_video(video_codec_ctx, video_outbuf, video_outbuf_size, frame_final); /* if zero size, it means the image was buffered */ if (out_size > 0) { - if(video_codec->coded_frame->key_frame) + if(video_codec_ctx->coded_frame->key_frame) pkt.flags |= AV_PKT_FLAG_KEY; pkt.data= video_outbuf; pkt.size= out_size; @@ -2095,11 +2095,11 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra // set the timestamp if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, video_codec->time_base, video_st->time_base); + pkt.pts = av_rescale_q(pkt.pts, video_codec_ctx->time_base, video_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, video_codec->time_base, video_st->time_base); + pkt.dts = av_rescale_q(pkt.dts, video_codec_ctx->time_base, video_st->time_base); if (pkt.duration > 0) - pkt.duration = av_rescale_q(pkt.duration, video_codec->time_base, video_st->time_base); + pkt.duration = av_rescale_q(pkt.duration, video_codec_ctx->time_base, video_st->time_base); pkt.stream_index = video_st->index; /* write the compressed frame in the media file */ From f9a91a5a92d834ee19030b213fadbd9482adc198 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 22 Mar 2020 12:15:02 -0400 Subject: [PATCH 022/100] FFmpegWriter: Replace AVRational casts with av_make_q() Some compilers balk at the compound initializers in the cast form --- src/FFmpegWriter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 435c6b47..54b5bc85 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -811,7 +811,7 @@ void FFmpegWriter::flush_encoders() { for (;;) { // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec_ctx->time_base); + write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base); AVPacket pkt; av_init_packet(&pkt); @@ -915,7 +915,7 @@ void FFmpegWriter::flush_encoders() { // for some reason, it requires me to multiply channels X 2 write_audio_count += av_rescale_q(audio_input_position / (audio_codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), av_make_q(1, info.sample_rate), audio_codec_ctx->time_base); #else - write_audio_count += av_rescale_q(audio_input_position / audio_codec_ctx->channels, (AVRational){1, info.sample_rate}, audio_codec_ctx->time_base); + write_audio_count += av_rescale_q(audio_input_position / audio_codec_ctx->channels, av_make_q(1, info.sample_rate), audio_codec_ctx->time_base); #endif AVPacket pkt; @@ -1964,7 +1964,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra pkt.size = sizeof(AVPicture); // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec_ctx->time_base); + write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base); pkt.pts = write_video_count; /* write the compressed frame in the media file */ @@ -1991,7 +1991,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra uint8_t *video_outbuf = NULL; // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec_ctx->time_base); + write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base); // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; From 999887687c5e406fb8cd8597d2be9fa09a862002 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 22 Mar 2020 12:19:11 -0400 Subject: [PATCH 023/100] FFmpegWriter: Free any old context before clobbering valgrind caught that AVFORMAT_NEW_STREAM() could be leaking pointers when calling avcodec_alloc_context3(), if there's an existing context already assigned. So we check and free it first, if necessary. --- src/FFmpegWriter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 54b5bc85..eb100095 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1067,6 +1067,11 @@ AVStream *FFmpegWriter::add_audio_stream() { if (codec == NULL) throw InvalidCodec("A valid audio codec could not be found for this file.", path); + // Free any previous memory allocations + if (audio_codec_ctx != NULL) { + AV_FREE_CONTEXT(audio_codec_ctx); + } + // Create a new audio stream AV_FORMAT_NEW_STREAM(oc, audio_codec_ctx, codec, st) From 36801445118dee936d94fc5ee0194599191334bb Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 22 Mar 2020 12:33:59 -0400 Subject: [PATCH 024/100] FrameMapper: Eliminate is_open member variable It was being used uninitialized because it's never actually set, therefore it serves no purpose. --- include/FrameMapper.h | 1 - src/FrameMapper.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 8be4ec1b..ff4ccd71 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -138,7 +138,6 @@ namespace openshot */ class FrameMapper : public ReaderBase { private: - bool is_open; bool field_toggle; // Internal odd / even toggle (used when building the mapping) Fraction original; // The original frame rate Fraction target; // The target frame rate diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 7c4d04bb..e80f355c 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -61,9 +61,9 @@ FrameMapper::FrameMapper(ReaderBase *reader, Fraction target, PulldownType targe // Destructor FrameMapper::~FrameMapper() { - if (is_open) - // Auto Close if not already - Close(); + + // Auto Close if not already + Close(); reader = NULL; } From fcf5cc628ca97e07da2efb0b001cc9e3cde81275 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 22 Mar 2020 12:40:31 -0400 Subject: [PATCH 025/100] DummyReader: Initialize is_open --- src/DummyReader.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 8fd98bcb..5613a696 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -33,14 +33,16 @@ using namespace openshot; // Blank constructor for DummyReader, with default settings. -DummyReader::DummyReader() { +DummyReader::DummyReader() : is_open(false) { // Call actual constructor with default values DummyReader(Fraction(24,1), 1280, 768, 44100, 2, 30.0); } // Constructor for DummyReader. Pass a framerate and samplerate. -DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration) { +DummyReader::DummyReader(Fraction fps, int width, int height, + int sample_rate, int channels, float duration) + : is_open(false) { // Set key info settings info.has_audio = false; From bb20a9b36993d27c3c5cb5944ff8217e0a786445 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Mon, 23 Mar 2020 05:26:12 -0400 Subject: [PATCH 026/100] ruby/CMakeLists: Lowercase commands --- src/bindings/ruby/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 8be7d792..c3c113aa 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -25,8 +25,8 @@ ################################################################################ ############### RUBY BINDINGS ################ -FIND_PACKAGE(SWIG 3.0 REQUIRED) -INCLUDE(${SWIG_USE_FILE}) +find_package(SWIG 3.0 REQUIRED) +include(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs if (POLICY CMP0078) @@ -42,8 +42,8 @@ if (NOT RUBY_FOUND) endif() ### Include the Ruby header files -INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${RUBY_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) ### Enable C++ in SWIG set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) @@ -105,5 +105,5 @@ message(STATUS "RUBY_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${RUBY_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ # Install Ruby bindings install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} - DESTINATION ${RUBY_MODULE_PATH} ) + DESTINATION ${RUBY_MODULE_PATH} ) From 2684015245d04ce3c1cb2ccd31014d3b5b7a8936 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Mon, 23 Mar 2020 05:30:32 -0400 Subject: [PATCH 027/100] python/CMakeLists: Lowercase commands, indents --- src/bindings/python/CMakeLists.txt | 62 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 42a15c8e..ea1292fa 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -26,34 +26,34 @@ ############### SWIG PYTHON BINDINGS ################ -FIND_PACKAGE(SWIG 3.0 REQUIRED) -INCLUDE(${SWIG_USE_FILE}) +find_package(SWIG 3.0 REQUIRED) +include(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs if (POLICY CMP0078) - cmake_policy(SET CMP0078 OLD) + cmake_policy(SET CMP0078 OLD) endif() if (POLICY CMP0086) - cmake_policy(SET CMP0086 OLD) + cmake_policy(SET CMP0086 OLD) endif() FIND_PACKAGE(PythonInterp 3) FIND_PACKAGE(PythonLibs 3) if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) - ### Include Python header files - INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + ### Include Python header files + include_directories(${PYTHON_INCLUDE_PATH}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - ### Enable C++ support in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + ### Enable C++ support in SWIG + set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) + set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - ### Suppress a ton of warnings in the generated SWIG C++ code - set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ + ### Suppress a ton of warnings in the generated SWIG C++ code + set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") - separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) - set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) + separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) + set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) ### Take include dirs from target, automatically if possible if (CMAKE_VERSION VERSION_GREATER 3.13) @@ -62,19 +62,19 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) endif () - ### Add the SWIG interface file (which defines all the SWIG methods) - if (CMAKE_VERSION VERSION_LESS 3.8.0) - swig_add_module(pyopenshot python openshot.i) - else() - swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) - endif() + ### Add the SWIG interface file (which defines all the SWIG methods) + if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(pyopenshot python openshot.i) + else() + swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) + endif() - ### Set output name of target - set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES + ### Set output name of target + set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES PREFIX "_" OUTPUT_NAME "openshot") - ### Link the new python wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} PUBLIC + ### Link the new python wrapper library with libopenshot + target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} PUBLIC ${PYTHON_LIBRARIES} openshot) ######### INSTALL PATH ######## @@ -88,12 +88,12 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) endif() if (UNIX AND NOT APPLE) - ### Check if the following Debian-friendly python module path exists - set(PYTHON_MODULE_PATH "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") + ### Check if the following Debian-friendly python module path exists + set(PYTHON_MODULE_PATH "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") + if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") ### Calculate the python module path (using distutils) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ from distutils.sysconfig import get_python_lib; \ print( get_python_lib( plat_specific=True, prefix='' ) )" OUTPUT_VARIABLE PYTHON_MODULE_PATH @@ -104,9 +104,9 @@ print( get_python_lib( plat_specific=True, prefix='' ) )" message(STATUS "PYTHON_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") - ############### INSTALL HEADERS & LIBRARY ################ - ### Install Python bindings - install(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} + ############### INSTALL HEADERS & LIBRARY ################ + ### Install Python bindings + install(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} DESTINATION ${PYTHON_MODULE_PATH} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py DESTINATION ${PYTHON_MODULE_PATH} ) From 94e9ad3eade8915460c4ae0090ee38ce02e8c7af Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Mon, 23 Mar 2020 08:13:46 -0400 Subject: [PATCH 028/100] bindings: Remove relative header paths (#469) * bindings: Remove relative header paths Use the include paths set on the command line the way they're supposed to be used. * Also remove some redundant include paths * Fix SWIG include dirs --- CMakeLists.txt | 4 - src/bindings/python/CMakeLists.txt | 132 +++++++++++--------- src/bindings/python/openshot.i | 192 ++++++++++++++--------------- src/bindings/ruby/CMakeLists.txt | 23 ++-- src/bindings/ruby/openshot.i | 192 ++++++++++++++--------------- 5 files changed, 276 insertions(+), 267 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0e8a5fe..124e9e5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,10 +113,6 @@ IF (WIN32) SET_PROPERTY(GLOBAL PROPERTY WIN32 "WIN32") ENDIF(WIN32) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_BINARY_DIR}/include) - ############## Code Coverage ######################### if (DISABLE_TESTS AND ENABLE_COVERAGE) message(WARNING "ENABLE_COVERAGE requires tests, overriding DISABLE_TESTS") diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index ea1292fa..6d7ce79e 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -37,78 +37,88 @@ if (POLICY CMP0086) cmake_policy(SET CMP0086 OLD) endif() -FIND_PACKAGE(PythonInterp 3) -FIND_PACKAGE(PythonLibs 3) -if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) +find_package(PythonInterp 3) +find_package(PythonLibs 3) - ### Include Python header files - include_directories(${PYTHON_INCLUDE_PATH}) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +if (NOT PYTHONLIBS_FOUND OR NOT PYTHONINTERP_FOUND) + return() +endif() - ### Enable C++ support in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) +### Include Python header files +include_directories(${PYTHON_INCLUDE_PATH}) - ### Suppress a ton of warnings in the generated SWIG C++ code - set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ --Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") - separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) - set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) +if (CMAKE_VERSION VERSION_LESS 3.12) + ### Include project headers + include_directories( + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_BINARY_DIR}/include") +endif() - ### Take include dirs from target, automatically if possible - if (CMAKE_VERSION VERSION_GREATER 3.13) - set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) - else () - set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) - endif () +### Enable C++ support in SWIG +set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - ### Add the SWIG interface file (which defines all the SWIG methods) - if (CMAKE_VERSION VERSION_LESS 3.8.0) - swig_add_module(pyopenshot python openshot.i) - else() - swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) +### Suppress a ton of warnings in the generated SWIG C++ code +set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \ + -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ + -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") +separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) +set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) + +### Take include dirs from target, automatically if possible +if (CMAKE_VERSION VERSION_GREATER 3.13) + set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) +elseif (CMAKE_VERSION VERSION_GREATER 3.12) + set_property(SOURCE openshot.i PROPERTY + INCLUDE_DIRECTORIES $) +endif () + +### Add the SWIG interface file (which defines all the SWIG methods) +if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(pyopenshot python openshot.i) +else() + swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) +endif() + +### Set output name of target +set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES + PREFIX "_" OUTPUT_NAME "openshot") + +### Link the new python wrapper library with libopenshot +target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} PUBLIC + ${PYTHON_LIBRARIES} openshot) + +######### INSTALL PATH ######## +if (NOT DEFINED PYTHON_MODULE_PATH AND DEFINED $ENV{PYTHON_MODULE_PATH}) + set(PYTHON_MODULE_PATH $ENV{PYTHON_MODULE_PATH}) +endif() + +if (NOT DEFINED PYTHON_MODULE_PATH) + if (WIN32 OR APPLE) + set (PYTHON_MODULE_PATH "python") endif() - ### Set output name of target - set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES - PREFIX "_" OUTPUT_NAME "openshot") + if (UNIX AND NOT APPLE) + ### Check if the following Debian-friendly python module path exists + set(PYTHON_MODULE_PATH + "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - ### Link the new python wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} PUBLIC - ${PYTHON_LIBRARIES} openshot) - - ######### INSTALL PATH ######## - if (NOT DEFINED PYTHON_MODULE_PATH AND DEFINED $ENV{PYTHON_MODULE_PATH}) - set(PYTHON_MODULE_PATH $ENV{PYTHON_MODULE_PATH}) - endif() - - if (NOT DEFINED PYTHON_MODULE_PATH) - if (WIN32 OR APPLE) - set (PYTHON_MODULE_PATH "python") - endif() - - if (UNIX AND NOT APPLE) - ### Check if the following Debian-friendly python module path exists - set(PYTHON_MODULE_PATH "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") - - ### Calculate the python module path (using distutils) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ from distutils.sysconfig import get_python_lib; \ print( get_python_lib( plat_specific=True, prefix='' ) )" - OUTPUT_VARIABLE PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - endif() + OUTPUT_VARIABLE PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() endif() +endif() - message(STATUS "PYTHON_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") +message(STATUS "PYTHON_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${PYTHON_MODULE_PATH}") - ############### INSTALL HEADERS & LIBRARY ################ - ### Install Python bindings - install(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} - DESTINATION ${PYTHON_MODULE_PATH} ) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py - DESTINATION ${PYTHON_MODULE_PATH} ) - -endif () +############### INSTALL HEADERS & LIBRARY ################ +### Install Python bindings +install(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} + DESTINATION ${PYTHON_MODULE_PATH} ) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py + DESTINATION ${PYTHON_MODULE_PATH} ) diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index 44b1953e..53e514c1 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -59,57 +59,57 @@ %{ #include "OpenShotVersion.h" -#include "../../../include/ReaderBase.h" -#include "../../../include/WriterBase.h" -#include "../../../include/CacheBase.h" -#include "../../../include/CacheDisk.h" -#include "../../../include/CacheMemory.h" -#include "../../../include/ChannelLayouts.h" -#include "../../../include/ChunkReader.h" -#include "../../../include/ChunkWriter.h" -#include "../../../include/ClipBase.h" -#include "../../../include/Clip.h" -#include "../../../include/Coordinate.h" -#include "../../../include/Color.h" -#include "../../../include/DummyReader.h" -#include "../../../include/EffectBase.h" -#include "../../../include/Effects.h" -#include "../../../include/EffectInfo.h" -#include "../../../include/Enums.h" -#include "../../../include/Exceptions.h" -#include "../../../include/FFmpegReader.h" -#include "../../../include/FFmpegWriter.h" -#include "../../../include/Fraction.h" -#include "../../../include/Frame.h" -#include "../../../include/FrameMapper.h" -#include "../../../include/PlayerBase.h" -#include "../../../include/Point.h" -#include "../../../include/Profiles.h" -#include "../../../include/QtHtmlReader.h" -#include "../../../include/QtImageReader.h" -#include "../../../include/QtPlayer.h" -#include "../../../include/QtTextReader.h" -#include "../../../include/KeyFrame.h" -#include "../../../include/RendererBase.h" -#include "../../../include/Settings.h" -#include "../../../include/Timeline.h" -#include "../../../include/ZmqLogger.h" -#include "../../../include/AudioDeviceInfo.h" +#include "ReaderBase.h" +#include "WriterBase.h" +#include "CacheBase.h" +#include "CacheDisk.h" +#include "CacheMemory.h" +#include "ChannelLayouts.h" +#include "ChunkReader.h" +#include "ChunkWriter.h" +#include "ClipBase.h" +#include "Clip.h" +#include "Coordinate.h" +#include "Color.h" +#include "DummyReader.h" +#include "EffectBase.h" +#include "Effects.h" +#include "EffectInfo.h" +#include "Enums.h" +#include "Exceptions.h" +#include "FFmpegReader.h" +#include "FFmpegWriter.h" +#include "Fraction.h" +#include "Frame.h" +#include "FrameMapper.h" +#include "PlayerBase.h" +#include "Point.h" +#include "Profiles.h" +#include "QtHtmlReader.h" +#include "QtImageReader.h" +#include "QtPlayer.h" +#include "QtTextReader.h" +#include "KeyFrame.h" +#include "RendererBase.h" +#include "Settings.h" +#include "Timeline.h" +#include "ZmqLogger.h" +#include "AudioDeviceInfo.h" %} #ifdef USE_BLACKMAGIC %{ - #include "../../../include/DecklinkReader.h" - #include "../../../include/DecklinkWriter.h" + #include "DecklinkReader.h" + #include "DecklinkWriter.h" %} #endif #ifdef USE_IMAGEMAGICK %{ - #include "../../../include/ImageReader.h" - #include "../../../include/ImageWriter.h" - #include "../../../include/TextReader.h" + #include "ImageReader.h" + #include "ImageWriter.h" + #include "TextReader.h" %} #endif @@ -166,68 +166,68 @@ } %include "OpenShotVersion.h" -%include "../../../include/ReaderBase.h" -%include "../../../include/WriterBase.h" -%include "../../../include/CacheBase.h" -%include "../../../include/CacheDisk.h" -%include "../../../include/CacheMemory.h" -%include "../../../include/ChannelLayouts.h" -%include "../../../include/ChunkReader.h" -%include "../../../include/ChunkWriter.h" -%include "../../../include/ClipBase.h" -%include "../../../include/Clip.h" -%include "../../../include/Coordinate.h" -%include "../../../include/Color.h" +%include "ReaderBase.h" +%include "WriterBase.h" +%include "CacheBase.h" +%include "CacheDisk.h" +%include "CacheMemory.h" +%include "ChannelLayouts.h" +%include "ChunkReader.h" +%include "ChunkWriter.h" +%include "ClipBase.h" +%include "Clip.h" +%include "Coordinate.h" +%include "Color.h" #ifdef USE_BLACKMAGIC - %include "../../../include/DecklinkReader.h" - %include "../../../include/DecklinkWriter.h" + %include "DecklinkReader.h" + %include "DecklinkWriter.h" #endif -%include "../../../include/DummyReader.h" -%include "../../../include/EffectBase.h" -%include "../../../include/Effects.h" -%include "../../../include/EffectInfo.h" -%include "../../../include/Enums.h" -%include "../../../include/Exceptions.h" -%include "../../../include/FFmpegReader.h" -%include "../../../include/FFmpegWriter.h" -%include "../../../include/Fraction.h" -%include "../../../include/Frame.h" -%include "../../../include/FrameMapper.h" -%include "../../../include/PlayerBase.h" -%include "../../../include/Point.h" -%include "../../../include/Profiles.h" -%include "../../../include/QtHtmlReader.h" -%include "../../../include/QtImageReader.h" -%include "../../../include/QtPlayer.h" -%include "../../../include/QtTextReader.h" -%include "../../../include/KeyFrame.h" -%include "../../../include/RendererBase.h" -%include "../../../include/Settings.h" -%include "../../../include/Timeline.h" -%include "../../../include/ZmqLogger.h" -%include "../../../include/AudioDeviceInfo.h" +%include "DummyReader.h" +%include "EffectBase.h" +%include "Effects.h" +%include "EffectInfo.h" +%include "Enums.h" +%include "Exceptions.h" +%include "FFmpegReader.h" +%include "FFmpegWriter.h" +%include "Fraction.h" +%include "Frame.h" +%include "FrameMapper.h" +%include "PlayerBase.h" +%include "Point.h" +%include "Profiles.h" +%include "QtHtmlReader.h" +%include "QtImageReader.h" +%include "QtPlayer.h" +%include "QtTextReader.h" +%include "KeyFrame.h" +%include "RendererBase.h" +%include "Settings.h" +%include "Timeline.h" +%include "ZmqLogger.h" +%include "AudioDeviceInfo.h" #ifdef USE_IMAGEMAGICK - %include "../../../include/ImageReader.h" - %include "../../../include/ImageWriter.h" - %include "../../../include/TextReader.h" + %include "ImageReader.h" + %include "ImageWriter.h" + %include "TextReader.h" #endif /* Effects */ -%include "../../../include/effects/Bars.h" -%include "../../../include/effects/Blur.h" -%include "../../../include/effects/Brightness.h" -%include "../../../include/effects/ChromaKey.h" -%include "../../../include/effects/ColorShift.h" -%include "../../../include/effects/Crop.h" -%include "../../../include/effects/Deinterlace.h" -%include "../../../include/effects/Hue.h" -%include "../../../include/effects/Mask.h" -%include "../../../include/effects/Negate.h" -%include "../../../include/effects/Pixelate.h" -%include "../../../include/effects/Saturation.h" -%include "../../../include/effects/Shift.h" -%include "../../../include/effects/Wave.h" +%include "effects/Bars.h" +%include "effects/Blur.h" +%include "effects/Brightness.h" +%include "effects/ChromaKey.h" +%include "effects/ColorShift.h" +%include "effects/Crop.h" +%include "effects/Deinterlace.h" +%include "effects/Hue.h" +%include "effects/Mask.h" +%include "effects/Negate.h" +%include "effects/Pixelate.h" +%include "effects/Saturation.h" +%include "effects/Shift.h" +%include "effects/Wave.h" /* Wrap std templates (list, vector, etc...) */ diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index c3c113aa..dc571a81 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -43,15 +43,22 @@ endif() ### Include the Ruby header files include_directories(${RUBY_INCLUDE_DIRS}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +if (CMAKE_VERSION VERSION_LESS 3.12) + ### Include Ruby header files and project headers + include_directories( + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_BINARY_DIR}/include") +endif() ### Enable C++ in SWIG set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) ### Suppress a ton of warnings in the generated SWIG C++ code -set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ --Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") +set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \ + -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ + -Wno-unused-parameter -Wno-catch-value -Wno-sign-compare -Wno-ignored-qualifiers") separate_arguments(sw_flags UNIX_COMMAND ${SWIG_CXX_FLAGS}) set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) @@ -59,7 +66,8 @@ set_property(SOURCE openshot.i PROPERTY GENERATED_COMPILE_OPTIONS ${sw_flags}) if (CMAKE_VERSION VERSION_GREATER 3.13) set_property(SOURCE openshot.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES True) else () - set_property(SOURCE openshot.i PROPERTY INCLUDE_DIRECTORIES $) + set_property(SOURCE openshot.i PROPERTY + INCLUDE_DIRECTORIES $) endif () ### Add the SWIG interface file (which defines all the SWIG methods) @@ -69,10 +77,6 @@ else() swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) endif() -### Set name of target (with no prefix, since Ruby does not like that) -set_target_properties(${SWIG_MODULE_rbopenshot_REAL_NAME} PROPERTIES - PREFIX "" OUTPUT_NAME "openshot") - ### Link the new Ruby wrapper library with libopenshot target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} PUBLIC ${RUBY_LIBRARY} openshot) @@ -101,9 +105,8 @@ if (NOT DEFINED RUBY_MODULE_PATH) endif() message(STATUS "RUBY_MODULE_PATH: ${CMAKE_INSTALL_PREFIX}/${RUBY_MODULE_PATH}") - + ############### INSTALL HEADERS & LIBRARY ################ # Install Ruby bindings install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} DESTINATION ${RUBY_MODULE_PATH} ) - diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index a08ac9ae..2f24d220 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -70,42 +70,42 @@ namespace std { #undef RSHIFT #endif #include "OpenShotVersion.h" -#include "../../../include/ReaderBase.h" -#include "../../../include/WriterBase.h" -#include "../../../include/CacheBase.h" -#include "../../../include/CacheDisk.h" -#include "../../../include/CacheMemory.h" -#include "../../../include/ChannelLayouts.h" -#include "../../../include/ChunkReader.h" -#include "../../../include/ChunkWriter.h" -#include "../../../include/ClipBase.h" -#include "../../../include/Clip.h" -#include "../../../include/Coordinate.h" -#include "../../../include/Color.h" -#include "../../../include/DummyReader.h" -#include "../../../include/EffectBase.h" -#include "../../../include/Effects.h" -#include "../../../include/EffectInfo.h" -#include "../../../include/Enums.h" -#include "../../../include/Exceptions.h" -#include "../../../include/FFmpegReader.h" -#include "../../../include/FFmpegWriter.h" -#include "../../../include/Fraction.h" -#include "../../../include/Frame.h" -#include "../../../include/FrameMapper.h" -#include "../../../include/PlayerBase.h" -#include "../../../include/Point.h" -#include "../../../include/Profiles.h" -#include "../../../include/QtHtmlReader.h" -#include "../../../include/QtImageReader.h" -#include "../../../include/QtPlayer.h" -#include "../../../include/QtTextReader.h" -#include "../../../include/KeyFrame.h" -#include "../../../include/RendererBase.h" -#include "../../../include/Settings.h" -#include "../../../include/Timeline.h" -#include "../../../include/ZmqLogger.h" -#include "../../../include/AudioDeviceInfo.h" +#include "ReaderBase.h" +#include "WriterBase.h" +#include "CacheBase.h" +#include "CacheDisk.h" +#include "CacheMemory.h" +#include "ChannelLayouts.h" +#include "ChunkReader.h" +#include "ChunkWriter.h" +#include "ClipBase.h" +#include "Clip.h" +#include "Coordinate.h" +#include "Color.h" +#include "DummyReader.h" +#include "EffectBase.h" +#include "Effects.h" +#include "EffectInfo.h" +#include "Enums.h" +#include "Exceptions.h" +#include "FFmpegReader.h" +#include "FFmpegWriter.h" +#include "Fraction.h" +#include "Frame.h" +#include "FrameMapper.h" +#include "PlayerBase.h" +#include "Point.h" +#include "Profiles.h" +#include "QtHtmlReader.h" +#include "QtImageReader.h" +#include "QtPlayer.h" +#include "QtTextReader.h" +#include "KeyFrame.h" +#include "RendererBase.h" +#include "Settings.h" +#include "Timeline.h" +#include "ZmqLogger.h" +#include "AudioDeviceInfo.h" /* Move FFmpeg's RSHIFT to FF_RSHIFT, if present */ #ifdef RSHIFT @@ -120,42 +120,42 @@ namespace std { #ifdef USE_BLACKMAGIC %{ - #include "../../../include/DecklinkReader.h" - #include "../../../include/DecklinkWriter.h" + #include "DecklinkReader.h" + #include "DecklinkWriter.h" %} #endif #ifdef USE_IMAGEMAGICK %{ - #include "../../../include/ImageReader.h" - #include "../../../include/ImageWriter.h" - #include "../../../include/TextReader.h" + #include "ImageReader.h" + #include "ImageWriter.h" + #include "TextReader.h" %} #endif %include "OpenShotVersion.h" -%include "../../../include/ReaderBase.h" -%include "../../../include/WriterBase.h" -%include "../../../include/CacheBase.h" -%include "../../../include/CacheDisk.h" -%include "../../../include/CacheMemory.h" -%include "../../../include/ChannelLayouts.h" -%include "../../../include/ChunkReader.h" -%include "../../../include/ChunkWriter.h" -%include "../../../include/ClipBase.h" -%include "../../../include/Clip.h" -%include "../../../include/Coordinate.h" -%include "../../../include/Color.h" +%include "ReaderBase.h" +%include "WriterBase.h" +%include "CacheBase.h" +%include "CacheDisk.h" +%include "CacheMemory.h" +%include "ChannelLayouts.h" +%include "ChunkReader.h" +%include "ChunkWriter.h" +%include "ClipBase.h" +%include "Clip.h" +%include "Coordinate.h" +%include "Color.h" #ifdef USE_BLACKMAGIC - %include "../../../include/DecklinkReader.h" - %include "../../../include/DecklinkWriter.h" + %include "DecklinkReader.h" + %include "DecklinkWriter.h" #endif -%include "../../../include/DummyReader.h" -%include "../../../include/EffectBase.h" -%include "../../../include/Effects.h" -%include "../../../include/EffectInfo.h" -%include "../../../include/Enums.h" -%include "../../../include/Exceptions.h" +%include "DummyReader.h" +%include "EffectBase.h" +%include "Effects.h" +%include "EffectInfo.h" +%include "Enums.h" +%include "Exceptions.h" /* Ruby and FFmpeg define competing RSHIFT macros, * so we move Ruby's out of the way for now. We'll @@ -166,8 +166,8 @@ namespace std { #undef RSHIFT #endif -%include "../../../include/FFmpegReader.h" -%include "../../../include/FFmpegWriter.h" +%include "FFmpegReader.h" +%include "FFmpegWriter.h" /* Move FFmpeg's RSHIFT to FF_RSHIFT, if present */ #ifdef RSHIFT @@ -179,45 +179,45 @@ namespace std { #define RSHIFT(a, b) RB_RSHIFT(a, b) #endif -%include "../../../include/Fraction.h" -%include "../../../include/Frame.h" -%include "../../../include/FrameMapper.h" -%include "../../../include/PlayerBase.h" -%include "../../../include/Point.h" -%include "../../../include/Profiles.h" -%include "../../../include/QtHtmlReader.h" -%include "../../../include/QtImageReader.h" -%include "../../../include/QtPlayer.h" -%include "../../../include/QtTextReader.h" -%include "../../../include/KeyFrame.h" -%include "../../../include/RendererBase.h" -%include "../../../include/Settings.h" -%include "../../../include/Timeline.h" -%include "../../../include/ZmqLogger.h" -%include "../../../include/AudioDeviceInfo.h" +%include "Fraction.h" +%include "Frame.h" +%include "FrameMapper.h" +%include "PlayerBase.h" +%include "Point.h" +%include "Profiles.h" +%include "QtHtmlReader.h" +%include "QtImageReader.h" +%include "QtPlayer.h" +%include "QtTextReader.h" +%include "KeyFrame.h" +%include "RendererBase.h" +%include "Settings.h" +%include "Timeline.h" +%include "ZmqLogger.h" +%include "AudioDeviceInfo.h" #ifdef USE_IMAGEMAGICK - %include "../../../include/ImageReader.h" - %include "../../../include/ImageWriter.h" - %include "../../../include/TextReader.h" + %include "ImageReader.h" + %include "ImageWriter.h" + %include "TextReader.h" #endif /* Effects */ -%include "../../../include/effects/Bars.h" -%include "../../../include/effects/Blur.h" -%include "../../../include/effects/Brightness.h" -%include "../../../include/effects/ChromaKey.h" -%include "../../../include/effects/ColorShift.h" -%include "../../../include/effects/Crop.h" -%include "../../../include/effects/Deinterlace.h" -%include "../../../include/effects/Hue.h" -%include "../../../include/effects/Mask.h" -%include "../../../include/effects/Negate.h" -%include "../../../include/effects/Pixelate.h" -%include "../../../include/effects/Saturation.h" -%include "../../../include/effects/Shift.h" -%include "../../../include/effects/Wave.h" +%include "effects/Bars.h" +%include "effects/Blur.h" +%include "effects/Brightness.h" +%include "effects/ChromaKey.h" +%include "effects/ColorShift.h" +%include "effects/Crop.h" +%include "effects/Deinterlace.h" +%include "effects/Hue.h" +%include "effects/Mask.h" +%include "effects/Negate.h" +%include "effects/Pixelate.h" +%include "effects/Saturation.h" +%include "effects/Shift.h" +%include "effects/Wave.h" /* Wrap std templates (list, vector, etc...) */ From 4fad197fbe0ba1239c17a26ace77bb4d2f133e66 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Mon, 23 Mar 2020 08:16:02 -0400 Subject: [PATCH 029/100] Add version gating for Zmq and Qt deprecations (#470) * ZmqLogger: Avoid deprecated send() in later ZMQ * QtImageReader: byteCount() deprecated in QT 5.10+ --- src/QtImageReader.cpp | 7 ++++++- src/ZmqLogger.cpp | 12 +++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 864af23d..cf64ef93 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -111,7 +111,12 @@ void QtImageReader::Open() info.has_audio = false; info.has_video = true; info.has_single_image = true; - info.file_size = image->byteCount(); + #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + // byteCount() is deprecated from Qt 5.10 + info.file_size = image->sizeInBytes(); + #else + info.file_size = image->byteCount(); + #endif info.vcodec = "QImage"; info.width = image->width(); info.height = image->height(); diff --git a/src/ZmqLogger.cpp b/src/ZmqLogger.cpp index 89d2798a..f607d08f 100644 --- a/src/ZmqLogger.cpp +++ b/src/ZmqLogger.cpp @@ -120,14 +120,20 @@ void ZmqLogger::Log(string message) // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 1) // Send message over socket (ZeroMQ) + zmq::message_t reply(message); + + // Set flags for immediate delivery (new API) + publisher->send(reply, zmq::send_flags::dontwait); +#else zmq::message_t reply (message.length()); memcpy (reply.data(), message.c_str(), message.length()); publisher->send(reply); +#endif - // Write to log file (if opened, and force it to write to disk in case of a crash) - if (log_file.is_open()) - log_file << message << std::flush; + // Also log to file, if open + LogToFile(message); } // Log message to a file (if path set) From 54f5fea2013cc3410071be911634304624ae8c21 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 25 Mar 2020 11:42:19 -0400 Subject: [PATCH 030/100] ZeroMQ's std::string support is too new --- src/ZmqLogger.cpp | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/ZmqLogger.cpp b/src/ZmqLogger.cpp index f607d08f..0be04bfa 100644 --- a/src/ZmqLogger.cpp +++ b/src/ZmqLogger.cpp @@ -71,7 +71,7 @@ ZmqLogger *ZmqLogger::Instance() } // Set the connection for this logger -void ZmqLogger::Connection(string new_connection) +void ZmqLogger::Connection(std::string new_connection) { // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); @@ -102,7 +102,7 @@ void ZmqLogger::Connection(string new_connection) publisher->bind(connection.c_str()); } catch (zmq::error_t &e) { - cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << endl; + std::cout << "ZmqLogger::Connection - Error binding to " << connection << ". Switching to an available port." << std::endl; connection = "tcp://*:*"; publisher->bind(connection.c_str()); } @@ -111,7 +111,7 @@ void ZmqLogger::Connection(string new_connection) usleep(250000); } -void ZmqLogger::Log(string message) +void ZmqLogger::Log(std::string message) { if (!enabled) // Don't do anything @@ -120,15 +120,14 @@ void ZmqLogger::Log(string message) // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 1) // Send message over socket (ZeroMQ) - zmq::message_t reply(message); + zmq::message_t reply (message.length()); + std::memcpy (reply.data(), message.c_str(), message.length()); +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 1) // Set flags for immediate delivery (new API) publisher->send(reply, zmq::send_flags::dontwait); #else - zmq::message_t reply (message.length()); - memcpy (reply.data(), message.c_str(), message.length()); publisher->send(reply); #endif @@ -137,14 +136,14 @@ void ZmqLogger::Log(string message) } // Log message to a file (if path set) -void ZmqLogger::LogToFile(string message) +void ZmqLogger::LogToFile(std::string message) { // Write to log file (if opened, and force it to write to disk in case of a crash) if (log_file.is_open()) log_file << message << std::flush; } -void ZmqLogger::Path(string new_path) +void ZmqLogger::Path(std::string new_path) { // Update path file_path = new_path; @@ -154,14 +153,14 @@ void ZmqLogger::Path(string new_path) log_file.close(); // Open file (write + append) - log_file.open (file_path.c_str(), ios::out | ios::app); + log_file.open (file_path.c_str(), std::ios::out | std::ios::app); // Get current time and log first message - time_t now = time(0); - tm* localtm = localtime(&now); - log_file << "------------------------------------------" << endl; - log_file << "libopenshot logging: " << asctime(localtm); - log_file << "------------------------------------------" << endl; + std::time_t now = std::time(0); + std::tm* localtm = std::localtime(&now); + log_file << "------------------------------------------" << std::endl; + log_file << "libopenshot logging: " << std::asctime(localtm); + log_file << "------------------------------------------" << std::endl; } void ZmqLogger::Close() @@ -182,13 +181,13 @@ void ZmqLogger::Close() } // Append debug information -void ZmqLogger::AppendDebugMethod(string method_name, - string arg1_name, float arg1_value, - string arg2_name, float arg2_value, - string arg3_name, float arg3_value, - string arg4_name, float arg4_value, - string arg5_name, float arg5_value, - string arg6_name, float arg6_value) +void ZmqLogger::AppendDebugMethod(std::string method_name, + std::string arg1_name, float arg1_value, + std::string arg2_name, float arg2_value, + std::string arg3_name, float arg3_value, + std::string arg4_name, float arg4_value, + std::string arg5_name, float arg5_value, + std::string arg6_name, float arg6_value) { if (!enabled) // Don't do anything @@ -198,8 +197,8 @@ void ZmqLogger::AppendDebugMethod(string method_name, // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); - stringstream message; - message << fixed << setprecision(4); + std::stringstream message; + message << std::fixed << std::setprecision(4); message << method_name << " ("; // Add attributes to method JSON From adf6165083fd2f227d354094b3764a117ca7bb9a Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 25 Mar 2020 11:57:22 -0400 Subject: [PATCH 031/100] Add version reporting to FindZeroMQ --- cmake/Modules/FindZeroMQ.cmake | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindZeroMQ.cmake b/cmake/Modules/FindZeroMQ.cmake index 6c366919..1f1dc083 100644 --- a/cmake/Modules/FindZeroMQ.cmake +++ b/cmake/Modules/FindZeroMQ.cmake @@ -5,14 +5,16 @@ pkg_check_modules(PC_LIBZMQ QUIET libzmq) set(ZeroMQ_VERSION ${PC_LIBZMQ_VERSION}) find_path(ZeroMQ_INCLUDE_DIR zmq.h - PATHS ${ZeroMQ_DIR}/include - ${PC_LIBZMQ_INCLUDE_DIRS}) + PATHS + ${ZeroMQ_DIR}/include + ${PC_LIBZMQ_INCLUDE_DIRS}) find_library(ZeroMQ_LIBRARY - NAMES zmq - PATHS ${ZeroMQ_DIR}/lib - ${PC_LIBZMQ_LIBDIR} - ${PC_LIBZMQ_LIBRARY_DIRS}) + NAMES zmq + PATHS + ${ZeroMQ_DIR}/lib + ${PC_LIBZMQ_LIBDIR} + ${PC_LIBZMQ_LIBRARY_DIRS}) if(ZeroMQ_LIBRARY) set(ZeroMQ_FOUND ON) @@ -31,4 +33,9 @@ endif() include ( FindPackageHandleStandardArgs ) # handle the QUIETLY and REQUIRED arguments and set ZMQ_FOUND to TRUE # if all listed variables are TRUE -find_package_handle_standard_args ( ZeroMQ DEFAULT_MSG ZeroMQ_LIBRARIES ZeroMQ_INCLUDE_DIRS ) +find_package_handle_standard_args(ZeroMQ + REQUIRED_VARS + ZeroMQ_LIBRARIES + ZeroMQ_INCLUDE_DIRS + VERSION_VAR + ZeroMQ_VERSION) From 0a5dfd93ad1e576c734541526d2bab3cb1213ceb Mon Sep 17 00:00:00 2001 From: Chiller Dragon Date: Thu, 26 Mar 2020 01:58:11 +0100 Subject: [PATCH 032/100] Fix zmq version check (#478) --- src/ZmqLogger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZmqLogger.cpp b/src/ZmqLogger.cpp index f607d08f..211f1119 100644 --- a/src/ZmqLogger.cpp +++ b/src/ZmqLogger.cpp @@ -120,7 +120,7 @@ void ZmqLogger::Log(string message) // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(loggerCriticalSection); -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 1) +#if ZMQ_VERSION > ZMQ_MAKE_VERSION(4, 3, 1) // Send message over socket (ZeroMQ) zmq::message_t reply(message); From 5e899bf207b280e334da8fec6349f90898150609 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Wed, 25 Mar 2020 23:07:03 -0400 Subject: [PATCH 033/100] Add SWIG/Ruby compatibility check & warning (#480) --- src/bindings/ruby/CMakeLists.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index dc571a81..2faa10fc 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -41,6 +41,23 @@ if (NOT RUBY_FOUND) return() endif() +### Ruby 2.7.0 made API changes that are incompatible with versions of +### SWIG prior to 4.0.3 +option(SILENCE_RUBY_VERSION_WARNING + "Don't warn about possible SWIG incompatibilities with Ruby 2.7.0+" OFF) + +if (${RUBY_VERSION} VERSION_GREATER 2.6.9 AND ${SWIG_VERSION} VERSION_LESS 4.0.3) + if (NOT ${SILENCE_RUBY_VERSION_WARNING}) + message(WARNING " +Ruby 2.7.0+ detected, building the libopenshot Ruby API bindings \ +requires a pre-release version of SWIG 4.0.3 with this commit: \ +https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4") + message(STATUS " +To disable this warning, add -DSILENCE_RUBY_VERSION_WARNING:BOOL=1 to the cmake \ +command line, or enable the option in the CMake GUI.") + endif() +endif() + ### Include the Ruby header files include_directories(${RUBY_INCLUDE_DIRS}) From 455b6e92bff6de715e3a8f3349f43cc54bf1a8ff Mon Sep 17 00:00:00 2001 From: SuslikV Date: Thu, 26 Mar 2020 10:17:22 +0200 Subject: [PATCH 034/100] Fix float to int16_t conversion in resampler The backward conversion int16_t to float in libopenshot has range (1.0; -1.0], thus conversion -1.0f to int16_t should be secured. Float values can exceed the (1.0; -1.0) range. This can cause distortion in audio instead of limiting values at max/min for the int16_t. --- src/FrameMapper.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 7c4d04bb..4b213f81 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -785,10 +785,23 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig // Create a new array (to hold all S16 audio samples for the current queued frames) int16_t* frame_samples = (int16_t*) av_malloc(sizeof(int16_t)*total_frame_samples); - // Translate audio sample values back to 16 bit integers - for (int s = 0; s < total_frame_samples; s++) - // Translate sample value and copy into buffer - frame_samples[s] = int(frame_samples_float[s] * (1 << 15)); + // Translate audio sample values back to 16 bit integers with saturation + float valF; + int16_t conv; + const int16_t max16 = 32767; + const int16_t min16 = -32768; + for (int s = 0; s < total_frame_samples; s++) { + valF = frame_samples_float[s] * (1 << 15); + if (valF > max16) + conv = max16; + else if (valF < min16) + conv = min16; + else + conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + + // Copy into buffer + frame_samples[s] = conv; + } // Deallocate float array From fda135725bbf518628fb4daa8af6e9eebd28ff9c Mon Sep 17 00:00:00 2001 From: Chiller Dragon Date: Thu, 26 Mar 2020 13:39:49 +0100 Subject: [PATCH 035/100] Ignore ctags file (#482) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c02a2fb9..58848653 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ .project .cproject /.metadata/ +tags *~ From 2701cf9079919ae3c3db2ece872c9e2fcaf558a4 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 26 Mar 2020 20:12:10 -0400 Subject: [PATCH 036/100] Add frame rate test to FFmpegReader_Tests --- tests/FFmpegReader_Tests.cpp | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 0a8620c9..6475e5ca 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -36,13 +36,16 @@ using namespace std; using namespace openshot; -TEST(FFmpegReader_Invalid_Path) +SUITE(FFmpegReader) +{ + +TEST(Invalid_Path) { // Check invalid path CHECK_THROW(FFmpegReader(""), InvalidFile); } -TEST(FFmpegReader_GetFrame_Before_Opening) +TEST(GetFrame_Before_Opening) { // Create a reader stringstream path; @@ -53,7 +56,7 @@ TEST(FFmpegReader_GetFrame_Before_Opening) CHECK_THROW(r.GetFrame(1), ReaderClosed); } -TEST(FFmpegReader_Check_Audio_File) +TEST(Check_Audio_File) { // Create a reader stringstream path; @@ -83,7 +86,7 @@ TEST(FFmpegReader_Check_Audio_File) r.Close(); } -TEST(FFmpegReader_Check_Video_File) +TEST(Check_Video_File) { // Create a reader stringstream path; @@ -129,7 +132,7 @@ TEST(FFmpegReader_Check_Video_File) r.Close(); } -TEST(FFmpegReader_Seek) +TEST(Seek) { // Create a reader stringstream path; @@ -186,7 +189,23 @@ TEST(FFmpegReader_Seek) } -TEST(FFmpegReader_Multiple_Open_and_Close) +TEST(Frame_Rate) +{ + // Create a reader + stringstream path; + path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; + FFmpegReader r(path.str()); + r.Open(); + + // Verify detected frame rate + openshot::Fraction rate = r.info.fps; + CHECK_EQUAL(24, rate.num); + CHECK_EQUAL(1, rate.den); + + r.Close(); +} + +TEST(Multiple_Open_and_Close) { // Create a reader stringstream path; @@ -221,3 +240,6 @@ TEST(FFmpegReader_Multiple_Open_and_Close) // Close reader r.Close(); } + +} // SUITE(FFmpegReader) + From c95333bf0afbd5e66ffbb46f03416fcdfa217eb2 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Fri, 27 Mar 2020 19:06:23 -0400 Subject: [PATCH 037/100] Fix Win64 Gitlab builds (#485) --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6b2645d8..925bf020 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -72,7 +72,6 @@ windows-builder-x64: - cd build - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -G "MSYS Makefiles" -DCMAKE_MAKE_PROGRAM=mingw32-make -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - mingw32-make install - - Move-Item -Force -path "install-x64\lib\python3.7\site-packages\*openshot*" -destination "install-x64\python\" - New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - $PREV_GIT_LABEL=(git describe --tags --abbrev=0 '@^') - git log "$PREV_GIT_LABEL..@" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" From 166f69389b6d8a601b51e8d559c418f56a144bba Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Fri, 27 Mar 2020 19:07:23 -0400 Subject: [PATCH 038/100] Travis: Do some YAML syntax linting (#484) --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fca321d6..c93822fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: cpp compiler: gcc +os: linux +dist: xenial # This section uses a rather esoteric (and tricky!) feature of YAML, # &aliases and *anchors, to build package lists out of sublists without @@ -32,7 +34,7 @@ addons: - libavresample-dev - libswresample-dev -matrix: +jobs: include: - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" From 140e0828b73ab0f4533e661cc52b9f2fcdeb30bf Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 31 Mar 2020 19:00:12 -0400 Subject: [PATCH 039/100] INSTALL.md: Formatting, markdown cleanup --- INSTALL.md | 198 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 119 insertions(+), 79 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 474fb9c2..9d25603b 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,90 +2,120 @@ Operating system specific install instructions are located in: -* doc/INSTALL-LINUX.md -* doc/INSTALL-MAC.md -* doc/INSTALL-WINDOWS.md +* [doc/INSTALL-LINUX.md][INSTALL-LINUX] +* [doc/INSTALL-MAC.md][INSTALL-MAC] +* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS] ## Getting Started -The best way to get started with libopenshot, is to learn about our build system, obtain all the source code, -install a development IDE and tools, and better understand our dependencies. So, please read through the -following sections, and follow the instructions. And keep in mind, that your computer is likely different -than the one used when writing these instructions. Your file paths and versions of applications might be +The best way to get started with libopenshot, is to learn about our build system, obtain all the source code, +install a development IDE and tools, and better understand our dependencies. So, please read through the +following sections, and follow the instructions. And keep in mind, that your computer is likely different +than the one used when writing these instructions. Your file paths and versions of applications might be slightly different, so keep an eye out for subtle file path differences in the commands you type. ## Build Tools -CMake is the backbone of our build system. It is a cross-platform build system, which checks for dependencies, -locates header files and libraries, generates makefiles, and supports the cross-platform compiling of -libopenshot and libopenshot-audio. CMake uses an out-of-source build concept, where all temporary build -files, such as makefiles, object files, and even the final binaries, are created outside of the source -code folder, inside a /build/ sub-folder. This prevents the build process from cluttering up the source -code. These instructions have only been tested with the GNU compiler (including MSYS2/MinGW for Windows). +CMake is the backbone of our build system. +It is a cross-platform build system, which checks for dependencies, +locates header files and libraries, and generates a build system in various formats. +We use CMake's Makefile generators to compile libopenshot and libopenshot-audio. -## Dependencies +CMake uses an out-of-source build concept. +This means that the build system, all temporary files, and all generated products are kept separate from the source code. +This includes Makefiles, object files, and even the final binaries. +While it is possible to build in-tree, we highly recommend you use a `/build/` sub-folder to compile each library. +This prevents the build process from cluttering up the source +code. +These instructions have only been tested with the GNU compiler suite (including MSYS2/MinGW for Windows), and the Clang compiler (including AppleClang on MacOS). -The following libraries are required to build libopenshot. Instructions on how to install these -dependencies vary for each operating system. Libraries and Executables have been labeled in the -list below to help distinguish between them. +### Dependencies -* ### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) - * http://www.ffmpeg.org/ `(Library)` +The following libraries are required to build libopenshot. +Instructions on how to install these dependencies vary for each operating system. +Libraries and Executables have been labeled in the list below to help distinguish between them. + +#### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) + + * http://www.ffmpeg.org/ **(Library)** * This library is used to decode and encode video, audio, and image files. It is also used to obtain information about media files, such as frame rate, sample rate, aspect ratio, and other common attributes. -* ### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) - * http://www.imagemagick.org/script/magick++.php `(Library)` +#### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) + * http://www.imagemagick.org/script/magick++.php **(Library)** * This library is **optional**, and used to decode and encode images. -* ### OpenShot Audio Library (libopenshot-audio) - * https://github.com/OpenShot/libopenshot-audio/ `(Library)` +#### OpenShot Audio Library (libopenshot-audio) + * https://github.com/OpenShot/libopenshot-audio/ **(Library)** * This library is used to mix, resample, host plug-ins, and play audio. It is based on the JUCE project, which is an outstanding audio library used by many different applications -* ### Qt 5 (libqt5) - * http://www.qt.io/qt5/ `(Library)` +#### Qt 5 (libqt5) + * http://www.qt.io/qt5/ **(Library)** * Qt5 is used to display video, store image data, composite images, apply image effects, and many other utility functions, such as file system manipulation, high resolution timers, etc... -* ### CMake (cmake) - * http://www.cmake.org/ `(Executable)` - * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process. - -* ### SWIG (swig) - * http://www.swig.org/ `(Executable)` - * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages. - -* ### Python 3 (libpython) - * http://www.python.org/ `(Executable and Library)` - * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot). - -* ### Doxygen (doxygen) - * http://www.stack.nl/~dimitri/doxygen/ `(Executable)` - * This executable is used to auto-generate the documentation used by libopenshot. - -* ### UnitTest++ (libunittest++) - * https://github.com/unittest-cpp/ `(Library)` - * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. - -* ### ZeroMQ (libzmq) - * http://zeromq.org/ `(Library)` +#### ZeroMQ (libzmq) + * http://zeromq.org/ **(Library)** * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot. -* ### OpenMP (-fopenmp) - * http://openmp.org/wp/ `(Compiler Flag)` +#### OpenMP (`-fopenmp`) + * http://openmp.org/wp/ **(Compiler Flag)** * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors. -## CMake Flags (Optional) -There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup. To add a build flag, follow this general syntax: $ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 ../ +#### CMake (`cmake`) + * http://www.cmake.org/ **(Executable)** + * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process. -* MAGICKCORE_HDRI_ENABLE (default 0) -* MAGICKCORE_QUANTUM_DEPTH (default 0) -* OPENSHOT_IMAGEMAGICK_COMPATIBILITY (default 0) -* DISABLE_TESTS (default 0) -* CMAKE_PREFIX_PATH (`/location/to/missing/library/`) -* PYTHON_INCLUDE_DIR (`/location/to/python/include/`) -* PYTHON_LIBRARY (`/location/to/python/lib.a`) -* PYTHON_FRAMEWORKS (`/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/`) -* CMAKE_CXX_COMPILER (`/location/to/mingw/g++`) -* CMAKE_C_COMPILER (`/location/to/mingw/gcc`) +#### SWIG (`swig`) + * http://www.swig.org/ **(Executable)** + * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages. + +#### Python 3 (libpython) + * http://www.python.org/ **(Executable and Library)** + * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot). + +#### Doxygen (doxygen) + * http://www.stack.nl/~dimitri/doxygen/ **(Executable)** + * This executable is used to auto-generate the documentation used by libopenshot. + +#### UnitTest++ (libunittest++) + * https://github.com/unittest-cpp/ **(Library)** + * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. + + +### CMake Flags (Optional) +There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup. + +To add a build flag, follow this general syntax: + +```sh +$ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 .. +``` + +Following are some of the flags you might need to set when generating your build system. + +##### Optional behavior: +* `-DENABLE_TESTS=0` (default: `ON`) +* `-DENABLE_COVERAGE=1` (default: `OFF`) +* `-DENABLE_DOCS=0` (default: `ON` if doxygen found) + +##### Compiler configuration: +* `-DCMAKE_BUILD_TYPE=Debug` (default: `Release`) +* `-DCMAKE_CXX_FLAGS="-Wall -Wextra"` (default: auto for build type) +* `-DCMAKE_CXX_COMPILER=/path/to/g++` +* `-DCMAKE_C_COMPILER=/path/to/gcc` (used by CMake for OS probes) + +##### Dependency configuration: +* `-DCMAKE_PREFIX_PATH=/extra/path/to/search/for/libraries/` +* `-DUSE_SYSTEM_JSONCPP=0` (default: auto if discovered) +* `-DImageMagick_FOUND=0` (default: auto if discovered) + +##### To compile bindings for a specific Python installation: +* `-DPYTHON_INCLUDE_DIR=/location/of/python/includes/` +* `-DPYTHON_LIBRARY=/location/of/libpython*.so` +* `-DPYTHON_FRAMEWORKS=/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/` (MacOS only) + +##### Only used when building with ImageMagick enabled: +* `-DMAGICKCORE_HDRI_ENABLE=1` (default `0`) +* `-DMAGICKCORE_QUANTUM_DEPTH=8` (default `16`) ## Obtaining Source Code @@ -96,30 +126,36 @@ git clone https://github.com/OpenShot/libopenshot.git git clone https://github.com/OpenShot/libopenshot-audio.git ``` -## Folder Structure (libopenshot) +### Folder Structure (libopenshot) The source code is divided up into the following folders. -* ### build/ - * This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). +#### `build/` +This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). -* ### cmake/ - * This folder contains custom modules not included by default in cmake, used to find dependency libraries and headers and determine if these libraries are installed. +#### `cmake/` +This folder contains custom modules not included by default in cmake. +CMake find modules are used to discover dependency libraries on the system, and to incorporate their headers and object files. +CMake code modules are used to implement build features such as test coverage scanning. -* ### doc/ - * This folder contains documentation and related files, such as logos and images required by the doxygen auto-generated documentation. +#### `doc/` +This folder contains documentation and related files. +This includes logos and images required by the doxygen-generated API documentation. -* ### include/ - * This folder contains all headers (*.h) used by libopenshot. +#### `include/` +This folder contains all headers (*.h) used by libopenshot. -* ### src/ - * This folder contains all source code (*.cpp) used by libopenshot. +#### `src/` +This folder contains all source code (*.cpp) used by libopenshot. -* ### tests/ - * This folder contains all unit test code. Each class has it’s own test file (*.cpp), and uses UnitTest++ macros to keep the test code simple and manageable. +#### `tests/` +This folder contains all unit test code. +Each test file (`_Tests.cpp`) contains the tests for the named class. +We use UnitTest++ macros to keep the test code simple and manageable. -* ### thirdparty/ - * This folder contains code not written by the OpenShot team. For example, jsoncpp, an open-source JSON parser. +#### `thirdparty/` +This folder contains code not written by the OpenShot team. +For example, `jsoncpp`, an open-source JSON parser. ## Linux Build Instructions (libopenshot-audio) To compile libopenshot-audio, we need to go through a few additional steps to manually build and install it. Launch a terminal and enter: @@ -148,6 +184,10 @@ make install For more detailed instructions, please see: -* doc/INSTALL-LINUX.md -* doc/INSTALL-MAC.md -* doc/INSTALL-WINDOWS.md +* [doc/INSTALL-LINUX.md][INSTALL-LINUX] +* [doc/INSTALL-MAC.md][INSTALL-MAC] +* [doc/INSTALL-WINDOWS.md][INSTALL-WINDOWS] + +[INSTALL-LINUX]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-LINUX.md +[INSTALL-MAC]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-MAC.md +[INSTALL-WINDOWS]: https://github.com/OpenShot/libopenshot/blob/develop/doc/INSTALL-WINDOWS.md From 2bea436f3ea1a3e35f97af4af908750e2bf236d0 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 13 Apr 2020 16:55:29 -0500 Subject: [PATCH 040/100] Adding keyframable origin point (for shear and rotation) --- include/Clip.h | 24 +++++++++++++----------- src/Clip.cpp | 10 ++++++++++ src/Timeline.cpp | 33 +++++++++++++++------------------ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/include/Clip.h b/include/Clip.h index 68d4622a..488f7efa 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -140,11 +140,11 @@ namespace openshot { void reverse_buffer(juce::AudioSampleBuffer* buffer); public: - openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent - openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent - openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to - openshot::FrameDisplayType display; ///< The format to display the frame number (if any) - openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips + openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent + openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent + openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to + openshot::FrameDisplayType display; ///< The format to display the frame number (if any) + openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips /// Default Constructor Clip(); @@ -208,15 +208,19 @@ namespace openshot { bool Waveform() { return waveform; } ///< Get the waveform property of this clip void Waveform(bool value) { waveform = value; } ///< Set the waveform property of this clip - // Scale and Location curves + // Scale, Location, and Alpha curves openshot::Keyframe scale_x; ///< Curve representing the horizontal scaling in percent (0 to 1) openshot::Keyframe scale_y; ///< Curve representing the vertical scaling in percent (0 to 1) openshot::Keyframe location_x; ///< Curve representing the relative X position in percent based on the gravity (-1 to 1) openshot::Keyframe location_y; ///< Curve representing the relative Y position in percent based on the gravity (-1 to 1) - - // Alpha and Rotation curves openshot::Keyframe alpha; ///< Curve representing the alpha (1 to 0) + + // Rotation and Shear curves (origin point (x,y) is adjustable for both rotation and shear) openshot::Keyframe rotation; ///< Curve representing the rotation (0 to 360) + openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right) + openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up) + openshot::Keyframe origin_x; ///< Curve representing X origin point (0.0=0% (left), 1.0=100% (right)) + openshot::Keyframe origin_y; ///< Curve representing Y origin point (0.0=0% (top), 1.0=100% (bottom)) // Time and Volume curves openshot::Keyframe time; ///< Curve representing the frames over time to play (used for speed and direction of video) @@ -232,9 +236,7 @@ namespace openshot { openshot::Keyframe crop_x; ///< Curve representing X offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%) openshot::Keyframe crop_y; ///< Curve representing Y offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%) - // Shear and perspective curves - openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right) - openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up) + // Perspective curves openshot::Keyframe perspective_c1_x; ///< Curves representing X for coordinate 1 openshot::Keyframe perspective_c1_y; ///< Curves representing Y for coordinate 1 openshot::Keyframe perspective_c2_x; ///< Curves representing X for coordinate 2 diff --git a/src/Clip.cpp b/src/Clip.cpp index 1968bb3b..f4920ccd 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -89,6 +89,8 @@ void Clip::init_settings() // Init shear and perspective curves shear_x = Keyframe(0.0); shear_y = Keyframe(0.0); + origin_x = Keyframe(0.5); + origin_y = Keyframe(0.5); perspective_c1_x = Keyframe(-1.0); perspective_c1_y = Keyframe(-1.0); perspective_c2_x = Keyframe(-1.0); @@ -718,6 +720,8 @@ std::string Clip::PropertiesJSON(int64_t requested_frame) const { root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", &shear_x, -1.0, 1.0, false, requested_frame); root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", &shear_y, -1.0, 1.0, false, requested_frame); root["rotation"] = add_property_json("Rotation", rotation.GetValue(requested_frame), "float", "", &rotation, -360, 360, false, requested_frame); + root["origin_x"] = add_property_json("Origin X", origin_x.GetValue(requested_frame), "float", "", &origin_x, 0.0, 1.0, false, requested_frame); + root["origin_y"] = add_property_json("Origin Y", origin_y.GetValue(requested_frame), "float", "", &origin_y, 0.0, 1.0, false, requested_frame); root["volume"] = add_property_json("Volume", volume.GetValue(requested_frame), "float", "", &volume, 0.0, 1.0, false, requested_frame); root["time"] = add_property_json("Time", time.GetValue(requested_frame), "float", "", &time, 0.0, 30 * 60 * 60 * 48, false, requested_frame); root["channel_filter"] = add_property_json("Channel Filter", channel_filter.GetValue(requested_frame), "int", "", &channel_filter, -1, 10, false, requested_frame); @@ -774,6 +778,8 @@ Json::Value Clip::JsonValue() const { root["crop_y"] = crop_y.JsonValue(); root["shear_x"] = shear_x.JsonValue(); root["shear_y"] = shear_y.JsonValue(); + root["origin_x"] = origin_x.JsonValue(); + root["origin_y"] = origin_y.JsonValue(); root["channel_filter"] = channel_filter.JsonValue(); root["channel_mapping"] = channel_mapping.JsonValue(); root["has_audio"] = has_audio.JsonValue(); @@ -871,6 +877,10 @@ void Clip::SetJsonValue(const Json::Value root) { shear_x.SetJsonValue(root["shear_x"]); if (!root["shear_y"].isNull()) shear_y.SetJsonValue(root["shear_y"]); + if (!root["origin_x"].isNull()) + origin_x.SetJsonValue(root["origin_x"]); + if (!root["origin_y"].isNull()) + origin_y.SetJsonValue(root["origin_y"]); if (!root["channel_filter"].isNull()) channel_filter.SetJsonValue(root["channel_filter"]); if (!root["channel_mapping"].isNull()) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 61ce31e3..079d2346 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -677,6 +677,8 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in y += (Settings::Instance()->MAX_HEIGHT * source_clip->location_y.GetValue(clip_frame_number)); // move in percentage of final height float shear_x = source_clip->shear_x.GetValue(clip_frame_number); float shear_y = source_clip->shear_y.GetValue(clip_frame_number); + float origin_x = source_clip->origin_x.GetValue(clip_frame_number); + float origin_y = source_clip->origin_y.GetValue(clip_frame_number); bool transformed = false; QTransform transform; @@ -684,21 +686,22 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in // Transform source image (if needed) ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Build QTransform - if needed)", "source_frame->number", source_frame->number, "x", x, "y", y, "r", r, "sx", sx, "sy", sy); - if (!isEqual(r, 0)) { - // ROTATE CLIP - float origin_x = x + (scaled_source_width / 2.0); - float origin_y = y + (scaled_source_height / 2.0); - transform.translate(origin_x, origin_y); - transform.rotate(r); - transform.translate(-origin_x,-origin_y); + if (!isEqual(x, 0) || !isEqual(y, 0)) { + // TRANSLATE/MOVE CLIP + transform.translate(x, y); transformed = true; } - if (!isEqual(x, 0) || !isEqual(y, 0)) { - // TRANSLATE/MOVE CLIP - transform.translate(x, y); - transformed = true; - } + if (!isEqual(r, 0) || !isEqual(shear_x, 0) || !isEqual(shear_y, 0)) { + // ROTATE CLIP (around origin_x, origin_y) + float origin_x_value = (scaled_source_width * origin_x); + float origin_y_value = (scaled_source_height * origin_y); + transform.translate(origin_x_value, origin_y_value); + transform.rotate(r); + transform.shear(shear_x, shear_y); + transform.translate(-origin_x_value,-origin_y_value); + transformed = true; + } // SCALE CLIP (if needed) float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx; @@ -709,12 +712,6 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in transformed = true; } - if (!isEqual(shear_x, 0) || !isEqual(shear_y, 0)) { - // SHEAR HEIGHT/WIDTH - transform.shear(shear_x, shear_y); - transformed = true; - } - // Debug output ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Transform: Composite Image Layer: Prepare)", "source_frame->number", source_frame->number, "new_frame->GetImage()->width()", new_frame->GetImage()->width(), "transformed", transformed); From f354850984e1a6dc64ecc33524129de1a8a5b080 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 15 Apr 2020 21:44:17 -0400 Subject: [PATCH 041/100] Effects: Mark overridden methods accordingly --- include/effects/Bars.h | 6 +++--- include/effects/Blur.h | 6 +++--- include/effects/Brightness.h | 6 +++--- include/effects/ChromaKey.h | 6 +++--- include/effects/ColorShift.h | 6 +++--- include/effects/Crop.h | 6 +++--- include/effects/Deinterlace.h | 6 +++--- include/effects/Hue.h | 6 +++--- include/effects/Mask.h | 6 +++--- include/effects/Negate.h | 6 +++--- include/effects/Pixelate.h | 6 +++--- include/effects/Saturation.h | 6 +++--- include/effects/Shift.h | 6 +++--- include/effects/Wave.h | 6 +++--- 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/include/effects/Bars.h b/include/effects/Bars.h index fa9df6f8..7c92255a 100644 --- a/include/effects/Bars.h +++ b/include/effects/Bars.h @@ -86,13 +86,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Blur.h b/include/effects/Blur.h index c254b8cd..60a0cd08 100644 --- a/include/effects/Blur.h +++ b/include/effects/Blur.h @@ -98,13 +98,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h index 69f2cf34..5f25b94a 100644 --- a/include/effects/Brightness.h +++ b/include/effects/Brightness.h @@ -86,13 +86,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h index dbc81e9c..fcc8c3b1 100644 --- a/include/effects/ChromaKey.h +++ b/include/effects/ChromaKey.h @@ -83,13 +83,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object // Get all properties for a specific frame std::string PropertiesJSON(int64_t requested_frame) const override; diff --git a/include/effects/ColorShift.h b/include/effects/ColorShift.h index ada2acd6..4ef56dc6 100644 --- a/include/effects/ColorShift.h +++ b/include/effects/ColorShift.h @@ -90,13 +90,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Crop.h b/include/effects/Crop.h index 2d4a2b2e..f5ba07f2 100644 --- a/include/effects/Crop.h +++ b/include/effects/Crop.h @@ -85,13 +85,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h index eff7b2fe..97c77853 100644 --- a/include/effects/Deinterlace.h +++ b/include/effects/Deinterlace.h @@ -79,13 +79,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object // Get all properties for a specific frame std::string PropertiesJSON(int64_t requested_frame) const override; diff --git a/include/effects/Hue.h b/include/effects/Hue.h index 9d86d5c2..833bf087 100644 --- a/include/effects/Hue.h +++ b/include/effects/Hue.h @@ -76,13 +76,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Mask.h b/include/effects/Mask.h index 390ffa36..8156b843 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -98,13 +98,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Negate.h b/include/effects/Negate.h index 6206a660..c691a86c 100644 --- a/include/effects/Negate.h +++ b/include/effects/Negate.h @@ -67,13 +67,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object // Get all properties for a specific frame std::string PropertiesJSON(int64_t requested_frame) const override; diff --git a/include/effects/Pixelate.h b/include/effects/Pixelate.h index 9348ce86..4cdd440f 100644 --- a/include/effects/Pixelate.h +++ b/include/effects/Pixelate.h @@ -85,13 +85,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h index e8d0d940..f272305f 100644 --- a/include/effects/Saturation.h +++ b/include/effects/Saturation.h @@ -83,13 +83,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Shift.h b/include/effects/Shift.h index 765da755..7a7efbea 100644 --- a/include/effects/Shift.h +++ b/include/effects/Shift.h @@ -79,13 +79,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/effects/Wave.h b/include/effects/Wave.h index ad516bde..d4759c24 100644 --- a/include/effects/Wave.h +++ b/include/effects/Wave.h @@ -85,13 +85,13 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number); + std::shared_ptr GetFrame(std::shared_ptr frame, int64_t frame_number) override; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) From f62f2bac6bf96aa6c22d079eee932eb0d8f89c7e Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 15 Apr 2020 21:45:04 -0400 Subject: [PATCH 042/100] Overrides for derived-class methods --- include/ChunkReader.h | 16 ++++++++-------- include/Clip.h | 4 ++-- include/DummyReader.h | 16 ++++++++-------- include/FFmpegReader.h | 16 ++++++++-------- include/FrameMapper.h | 16 ++++++++-------- include/ImageReader.h | 18 +++++++++--------- include/QtHtmlReader.h | 16 ++++++++-------- include/QtImageReader.h | 16 ++++++++-------- include/QtTextReader.h | 16 ++++++++-------- include/TextReader.h | 16 ++++++++-------- include/Timeline.h | 16 ++++++++-------- 11 files changed, 83 insertions(+), 83 deletions(-) diff --git a/include/ChunkReader.h b/include/ChunkReader.h index 4d72c31d..cd7cd67f 100644 --- a/include/ChunkReader.h +++ b/include/ChunkReader.h @@ -132,7 +132,7 @@ namespace openshot ChunkReader(std::string path, ChunkVersion chunk_version); /// Close the reader - void Close(); + void Close() override; /// @brief Get the chunk size (number of frames to write in each chunk) /// @returns The number of frames in this chunk @@ -143,27 +143,27 @@ namespace openshot void SetChunkSize(int64_t new_size) { chunk_size = new_size; }; /// Get the cache object used by this reader (always return NULL for this reader) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// @brief Get an openshot::Frame object for a specific frame number of this reader. /// @returns The requested frame (containing the image and audio) /// @param requested_frame The frame number you want to retrieve - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "ChunkReader"; }; + std::string Name() override { return "ChunkReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open the reader. This is required before you can access frames or data from the reader. - void Open(); + void Open() override; }; } diff --git a/include/Clip.h b/include/Clip.h index 68d4622a..1f4cd385 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -192,9 +192,9 @@ namespace openshot { /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) diff --git a/include/DummyReader.h b/include/DummyReader.h index fd17bed1..4c935103 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -68,32 +68,32 @@ namespace openshot virtual ~DummyReader(); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this reader) - CacheMemory* GetCache() { return NULL; }; + CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "DummyReader"; }; + std::string Name() override { return "DummyReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index e9cee579..ec082965 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -246,31 +246,31 @@ namespace openshot { virtual ~FFmpegReader(); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader - CacheMemory *GetCache() { return &final_cache; }; + CacheMemory *GetCache() override { return &final_cache; }; /// Get a shared pointer to a openshot::Frame object for a specific frame number of this reader. /// /// @returns The requested frame of video /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "FFmpegReader"; }; + std::string Name() override { return "FFmpegReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 8be4ec1b..c98d7b71 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -176,13 +176,13 @@ namespace openshot void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout); /// Close the openshot::FrameMapper and internal reader - void Close(); + void Close() override; /// Get a frame based on the target frame rate and the new frame number of a frame MappedFrame GetMappedFrame(int64_t TargetFrameNumber); /// Get the cache object used by this reader - CacheMemory* GetCache() { return &final_cache; }; + CacheMemory* GetCache() override { return &final_cache; }; /// @brief This method is required for all derived classes of ReaderBase, and return the /// openshot::Frame object, which contains the image and audio information for that @@ -190,22 +190,22 @@ namespace openshot /// /// @returns The requested frame of video /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen(); + bool IsOpen() override; /// Return the type name of the class - std::string Name() { return "FrameMapper"; }; + std::string Name() override { return "FrameMapper"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open the internal reader - void Open(); + void Open() override; /// Print all of the original frames and which new frames they map to void PrintMapping(); diff --git a/include/ImageReader.h b/include/ImageReader.h index bb19dd3d..5aafcc8f 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -87,32 +87,32 @@ namespace openshot ImageReader(std::string path, bool inspect_reader); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - CacheMemory* GetCache() { return NULL; }; + CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "ImageReader"; }; + std::string Name() override { return "ImageReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object - Json::Value JsonValue() const; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object + Json::Value JsonValue() const override; ///< Generate Json::Value for this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/QtHtmlReader.h b/include/QtHtmlReader.h index d7052d49..3d426afb 100644 --- a/include/QtHtmlReader.h +++ b/include/QtHtmlReader.h @@ -112,32 +112,32 @@ namespace openshot QtHtmlReader(int width, int height, int x_offset, int y_offset, GravityType gravity, std::string html, std::string css, std::string background_color); /// Close Reader - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "QtHtmlReader"; }; + std::string Name() override { return "QtHtmlReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open Reader - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/QtImageReader.h b/include/QtImageReader.h index 3e456e39..3848065a 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -85,32 +85,32 @@ namespace openshot virtual ~QtImageReader(); /// Close File - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - CacheMemory* GetCache() { return NULL; }; + CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "QtImageReader"; }; + std::string Name() override { return "QtImageReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open File - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/QtTextReader.h b/include/QtTextReader.h index d226e920..2fd203ad 100644 --- a/include/QtTextReader.h +++ b/include/QtTextReader.h @@ -123,32 +123,32 @@ namespace openshot void SetTextBackgroundColor(std::string color); /// Close Reader - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "QtTextReader"; }; + std::string Name() override { return "QtTextReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open Reader - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/TextReader.h b/include/TextReader.h index b6dbf5cd..b5488f5f 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -123,32 +123,32 @@ namespace openshot void SetTextBackgroundColor(std::string color); /// Close Reader - void Close(); + void Close() override; /// Get the cache object used by this reader (always returns NULL for this object) - openshot::CacheMemory* GetCache() { return NULL; }; + openshot::CacheMemory* GetCache() override { return NULL; }; /// Get an openshot::Frame object for a specific frame number of this reader. All numbers /// return the same Frame, since they all share the same image data. /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; /// Determine if reader is open or closed - bool IsOpen() { return is_open; }; + bool IsOpen() override { return is_open; }; /// Return the type name of the class - std::string Name() { return "TextReader"; }; + std::string Name() override { return "TextReader"; }; /// Get and Set JSON methods std::string Json() const override; ///< Generate JSON string of this object - void SetJson(const std::string value); ///< Load JSON string into this object + void SetJson(const std::string value) override; ///< Load JSON string into this object Json::Value JsonValue() const override; ///< Generate Json::Value for this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + void SetJsonValue(const Json::Value root) override; ///< Load Json::Value into this object /// Open Reader - which is called by the constructor automatically - void Open(); + void Open() override; }; } diff --git a/include/Timeline.h b/include/Timeline.h index 56a89586..932b04ac 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -242,13 +242,13 @@ namespace openshot { std::list Clips() { return clips; }; /// Close the timeline reader (and any resources it was consuming) - void Close(); + void Close() override; /// Return the list of effects on the timeline std::list Effects() { return effects; }; /// Get the cache object used by this reader - CacheBase* GetCache() { return final_cache; }; + CacheBase* GetCache() override { return final_cache; }; /// Set the cache object used by this reader. You must now manage the lifecycle /// of this cache object though (Timeline will not delete it for you). @@ -258,7 +258,7 @@ namespace openshot { /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - std::shared_ptr GetFrame(int64_t requested_frame); + std::shared_ptr GetFrame(int64_t requested_frame) override; // Curves for the viewport Keyframe viewport_scale; ///MAX_WIDTH and Settings::Instance()->MAX_HEIGHT. @@ -291,7 +291,7 @@ namespace openshot { void ApplyJsonDiff(std::string value); /// Open the reader (and start consuming resources) - void Open(); + void Open() override; /// @brief Remove an openshot::Clip from the timeline /// @param clip Remove an openshot::Clip from the timeline. From ad3b1b46992757a878d85a56cf0304853dfd85c9 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 16 Apr 2020 19:36:52 -0400 Subject: [PATCH 043/100] Make debug handling match libopenshot-audio (#499) --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 124e9e5a..bb3fe8cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,6 +129,16 @@ if (ENABLE_COVERAGE) endif() add_feature_info("Coverage" ENABLE_COVERAGE "analyze test coverage and generate report") +# Juce requires either DEBUG or NDEBUG to be defined on MacOS. +# -DNDEBUG is set by cmake for all release configs, so add +# -DDEBUG for debug builds. We'll do this for all OSes, even +# though only MacOS requires it. +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") +# Make sure we've picked some build type, default to debug +if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE "Debug") +endif() + ############## PROCESS src/ DIRECTORIES ############## add_subdirectory(src) From a972b2e67223dabf92564a42718ac2efdd6801c2 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 16 Apr 2020 20:04:13 -0400 Subject: [PATCH 044/100] INSTALL doc: Correct some CMake flags, reorder --- INSTALL.md | 105 ++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 9d25603b..f2d0dda7 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -14,22 +14,7 @@ following sections, and follow the instructions. And keep in mind, that your com than the one used when writing these instructions. Your file paths and versions of applications might be slightly different, so keep an eye out for subtle file path differences in the commands you type. -## Build Tools - -CMake is the backbone of our build system. -It is a cross-platform build system, which checks for dependencies, -locates header files and libraries, and generates a build system in various formats. -We use CMake's Makefile generators to compile libopenshot and libopenshot-audio. - -CMake uses an out-of-source build concept. -This means that the build system, all temporary files, and all generated products are kept separate from the source code. -This includes Makefiles, object files, and even the final binaries. -While it is possible to build in-tree, we highly recommend you use a `/build/` sub-folder to compile each library. -This prevents the build process from cluttering up the source -code. -These instructions have only been tested with the GNU compiler suite (including MSYS2/MinGW for Windows), and the Clang compiler (including AppleClang on MacOS). - -### Dependencies +## Dependencies The following libraries are required to build libopenshot. Instructions on how to install these dependencies vary for each operating system. @@ -80,43 +65,6 @@ Libraries and Executables have been labeled in the list below to help distinguis * https://github.com/unittest-cpp/ **(Library)** * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. - -### CMake Flags (Optional) -There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup. - -To add a build flag, follow this general syntax: - -```sh -$ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 .. -``` - -Following are some of the flags you might need to set when generating your build system. - -##### Optional behavior: -* `-DENABLE_TESTS=0` (default: `ON`) -* `-DENABLE_COVERAGE=1` (default: `OFF`) -* `-DENABLE_DOCS=0` (default: `ON` if doxygen found) - -##### Compiler configuration: -* `-DCMAKE_BUILD_TYPE=Debug` (default: `Release`) -* `-DCMAKE_CXX_FLAGS="-Wall -Wextra"` (default: auto for build type) -* `-DCMAKE_CXX_COMPILER=/path/to/g++` -* `-DCMAKE_C_COMPILER=/path/to/gcc` (used by CMake for OS probes) - -##### Dependency configuration: -* `-DCMAKE_PREFIX_PATH=/extra/path/to/search/for/libraries/` -* `-DUSE_SYSTEM_JSONCPP=0` (default: auto if discovered) -* `-DImageMagick_FOUND=0` (default: auto if discovered) - -##### To compile bindings for a specific Python installation: -* `-DPYTHON_INCLUDE_DIR=/location/of/python/includes/` -* `-DPYTHON_LIBRARY=/location/of/libpython*.so` -* `-DPYTHON_FRAMEWORKS=/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/` (MacOS only) - -##### Only used when building with ImageMagick enabled: -* `-DMAGICKCORE_HDRI_ENABLE=1` (default `0`) -* `-DMAGICKCORE_QUANTUM_DEPTH=8` (default `16`) - ## Obtaining Source Code The first step in installing libopenshot is to obtain the most recent source code. The source code is available on [GitHub](https://github.com/OpenShot/libopenshot). Use the following command to obtain the latest libopenshot source code. @@ -157,6 +105,57 @@ We use UnitTest++ macros to keep the test code simple and manageable. This folder contains code not written by the OpenShot team. For example, `jsoncpp`, an open-source JSON parser. +## Build Tools + +CMake is the backbone of our build system. +It is a cross-platform build system, which checks for dependencies, +locates header files and libraries, and generates a build system in various formats. +We use CMake's Makefile generators to compile libopenshot and libopenshot-audio. + +CMake uses an out-of-source build concept. +This means that the build system, all temporary files, and all generated products are kept separate from the source code. +This includes Makefiles, object files, and even the final binaries. +While it is possible to build in-tree, we highly recommend you use a `/build/` sub-folder to compile each library. +This prevents the build process from cluttering up the source +code. +These instructions have only been tested with the GNU compiler suite (including MSYS2/MinGW for Windows), and the Clang compiler (including AppleClang on MacOS). + +## CMake Flags (Optional) +There are many different build flags that can be passed to cmake to adjust how libopenshot is compiled. Some of these flags might be required when compiling on certain OSes, just depending on how your build environment is setup. + +To add a build flag, follow this general syntax: + +```sh +$ cmake -DMAGICKCORE_HDRI_ENABLE=1 -DENABLE_TESTS=1 .. +``` + +Following are some of the flags you might need to set when generating your build system. + +##### Optional behavior: +* `-DENABLE_TESTS=0` (default: `ON`) +* `-DENABLE_COVERAGE=1` (default: `OFF`) +* `-DENABLE_DOCS=0` (default: `ON` if doxygen found) + +##### Compiler configuration: +* `-DCMAKE_BUILD_TYPE=Release`, `-DCMAKE_BUILD_TYPE=Debug` (default: `Debug` if unset) +* `-DCMAKE_CXX_FLAGS="-Wall -Wextra"` (default: CMake builtin defaults for build type) +* `-DCMAKE_CXX_COMPILER=/path/to/g++`, `-DCMAKE_CXX_COMPILER=/path/to/clang++` +* `-DCMAKE_C_COMPILER=/path/to/gcc`, `-DCMAKE_CXX_COMPILER=/path/to/clang` (used by CMake for OS probes) + +##### Dependency configuration: +* `-DCMAKE_PREFIX_PATH=/extra/path/to/search/for/libraries/` +* `-DUSE_SYSTEM_JSONCPP=0` (default: auto if discovered) +* `-DImageMagick_FOUND=0` (default: auto if discovered) + +##### To compile bindings for a specific Python installation: +* `-DPYTHON_INCLUDE_DIR=/location/of/python/includes/` +* `-DPYTHON_LIBRARY=/location/of/libpython*.so` +* `-DPYTHON_FRAMEWORKS=/usr/local/Cellar/python3/3.3.2/Frameworks/Python.framework/` (MacOS only) + +##### Only used when building with ImageMagick enabled: +* `-DMAGICKCORE_HDRI_ENABLE=1` (default `0`) +* `-DMAGICKCORE_QUANTUM_DEPTH=8` (default `16`) + ## Linux Build Instructions (libopenshot-audio) To compile libopenshot-audio, we need to go through a few additional steps to manually build and install it. Launch a terminal and enter: From 9d261f656850f8f97bede9977e1a5cfce45275b5 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 17 Apr 2020 05:39:00 -0400 Subject: [PATCH 045/100] CMake: Rename, modernize Findjsoncpp.cmake - Rename to match package naming used elsewhere (official configs) - Add IMPORTED target creation to the Find module, along with version number detection - Switch to lowercase variable forms (e.g. jsoncpp_FOUND) --- cmake/Modules/FindJsonCpp.cmake | 64 ---------------- cmake/Modules/Findjsoncpp.cmake | 132 ++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 25 +++--- 3 files changed, 142 insertions(+), 79 deletions(-) delete mode 100644 cmake/Modules/FindJsonCpp.cmake create mode 100644 cmake/Modules/Findjsoncpp.cmake diff --git a/cmake/Modules/FindJsonCpp.cmake b/cmake/Modules/FindJsonCpp.cmake deleted file mode 100644 index 6ce9887e..00000000 --- a/cmake/Modules/FindJsonCpp.cmake +++ /dev/null @@ -1,64 +0,0 @@ -# - Try to find JsonCpp -# -# Once done this will define -# JSONCPP_INCLUDE_DIRS, where to find header, etc. -# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. -# JSONCPP_FOUND, If false, do not try to use jsoncpp. -# JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp - -# try to detect using pkg-config, and use as hints later -find_package(PkgConfig) -pkg_check_modules(PC_jsoncpp QUIET jsoncpp) - -find_path( - JSONCPP_INCLUDE_DIR - NAMES json/json.h - HINTS ${PC_jsoncpp_INCLUDE_DIRS} - DOC "jsoncpp include dir" -) - -find_library( - JSONCPP_LIBRARY - NAMES jsoncpp - HINTS ${PC_jsoncpp_LIBRARY_DIR} - DOC "jsoncpp library" -) - -set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR}) -set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) - -# debug library on windows -# same naming convention as in qt (appending debug library with d) -# boost is using the same "hack" as us with "optimized" and "debug" -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - find_library( - JSONCPP_LIBRARY_DEBUG - NAMES jsoncppd - HINTS ${PC_jsoncpp_LIBDIR} ${PC_jsoncpp_LIBRARY_DIRS} - DOC "jsoncpp debug library" - ) - - set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug ${JSONCPP_LIBRARY_DEBUG}) - -endif() - -# find JSONCPP_INCLUDE_PREFIX -find_path( - JSONCPP_INCLUDE_PREFIX - NAMES json.h - PATH_SUFFIXES jsoncpp/json json -) - -if (${JSONCPP_INCLUDE_PREFIX} MATCHES "jsoncpp") - set(JSONCPP_INCLUDE_PREFIX "jsoncpp/json") -else() - set(JSONCPP_INCLUDE_PREFIX "json") -endif() - -# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE -# if all listed variables are TRUE, hide their existence from configuration view -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(jsoncpp DEFAULT_MSG - JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) -mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) - diff --git a/cmake/Modules/Findjsoncpp.cmake b/cmake/Modules/Findjsoncpp.cmake new file mode 100644 index 00000000..bd30fea7 --- /dev/null +++ b/cmake/Modules/Findjsoncpp.cmake @@ -0,0 +1,132 @@ +# - Try to find jsoncpp +# +# IMPORTED target +# This module will create the target jsoncpp_lib if jsoncpp is found +# +# Legacy Config Variables +# The following variables are defined for backwards compatibility: +# +# JSONCPP_INCLUDE_DIRS, where to find header, etc. +# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. +# JSONCPP_FOUND, If false, do not try to use jsoncpp. +# JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp + +# try to detect using pkg-config, and use as hints later +find_package(PkgConfig) +pkg_check_modules(PC_jsoncpp QUIET jsoncpp) + +find_path( + jsoncpp_INCLUDE_DIR + NAMES json/json.h + HINTS ${PC_jsoncpp_INCLUDE_DIRS} + DOC "jsoncpp include dir" +) + +find_library( + jsoncpp_LIBRARY + NAMES jsoncpp + HINTS ${PC_jsoncpp_LIBRARY_DIR} + DOC "jsoncpp library" +) + +set(jsoncpp_INCLUDE_DIRS ${jsoncpp_INCLUDE_DIR}) +set(jsoncpp_LIBRARIES ${jsoncpp_LIBRARY}) + +if (jsoncpp_INCLUDE_DIRS AND jsoncpp_LIBRARIES) + set(jsoncpp_FOUND TRUE) +endif() + +# Create the IMPORTED target +if (jsoncpp_FOUND AND NOT TARGET jsoncpp_lib) + add_library(jsoncpp_lib UNKNOWN IMPORTED) + + set_property(TARGET jsoncpp_lib PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${JSONCPP_INCLUDE_DIR}) + + set_property(TARGET jsoncpp_lib PROPERTY + IMPORTED_LOCATION ${JSONCPP_LIBRARY}) +endif() + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + find_library( + jsoncpp_LIBRARY_DEBUG + NAMES jsoncppd + HINTS ${PC_jsoncpp_LIBDIR} ${PC_jsoncpp_LIBRARY_DIRS} + DOC "jsoncpp debug library" + ) + + set(jsoncpp_LIBRARIES optimized ${jsoncpp_LIBRARIES} debug ${jsoncpp_LIBRARY_DEBUG}) + + # Add Debug location to IMPORTED target + if(TARGET jsoncpp_lib) + set_property(TARGET jsoncpp_lib APPEND PROPERTY + IMPORTED_LOCATION_Debug ${JSONCPP_LIBRARY_DEBUG}) + endif() +endif() + +# find JSONCPP_INCLUDE_PREFIX +find_path( + jsoncpp_INCLUDE_PREFIX + NAMES json.h + PATH_SUFFIXES jsoncpp/json json +) + +if (${jsoncpp_INCLUDE_PREFIX} MATCHES "jsoncpp") + set(jsoncpp_INCLUDE_PREFIX "jsoncpp/json") +else() + set(jsoncpp_INCLUDE_PREFIX "json") +endif() + +# Check the available version +set(_version_file "${jsoncpp_INCLUDE_DIR}/${jsoncpp_INCLUDE_PREFIX}/version.h") +if (jsoncpp_INCLUDE_DIR AND EXISTS ${_version_file}) + file(STRINGS "${_version_file}" jsoncpp_version_str + REGEX "JSONCPP_VERSION_STRING.*\"[^\"]+\"") + if(jsoncpp_version_str MATCHES "JSONCPP_VERSION_STRING.*\"([^\"]+)\"") + set(jsoncpp_VERSION_STRING ${CMAKE_MATCH_1}) + endif() + unset(jsoncpp_version_str) + string(REGEX REPLACE "^([0-9]+\.[0-9]+\.[0-9]+).*$" "\\1" + jsoncpp_VERSION "${jsoncpp_VERSION_STRING}") +endif() + +if(NOT jsoncpp_VERSION) + unset(jsoncpp_VERSION) + unset(jsoncpp_VERSION_STRING) +endif() + +# Check version requirement, if specified +if(jsoncpp_FIND_VERSION AND jsoncpp_VERSION) + if("${jsoncpp_FIND_VERSION}" STREQUAL "${jsoncpp_VERSION}") + set(jsoncpp_VERSION_EXACT TRUE) + endif() + if("${jsoncpp_FIND_VERSION}" VERSION_GREATER "${jsoncpp_VERSION}") + set(jsoncpp_VERSION_COMPATIBLE FALSE) + else() + set(jsoncpp_VERSION_COMPATIBLE TRUE) + endif() +endif() + +# Legacy +set(JSONCPP_LIBRARY ${jsoncpp_LIBRARY}) +set(JSONCPP_LIBRARIES ${jsoncpp_LIBRARIES}) +set(JSONCPP_INCLUDE_DIR ${jsoncpp_INCLUDE_DIR}) +set(JSONCPP_INCLUDE_DIRS ${jsoncpp_INCLUDE_DIRS}) +set(JSONCPP_INCLUDE_PREFIX ${jsoncpp_INCLUDE_PREFIX}) +set(JSONCPP_VERSION ${jsoncpp_VERSION}) +set(JSONCPP_FOUND ${jsoncpp_FOUND}) + +# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(jsoncpp + REQUIRED_VARS + jsoncpp_INCLUDE_DIR + jsoncpp_LIBRARY + VERSION_VAR + jsoncpp_VERSION +) +mark_as_advanced (jsoncpp_INCLUDE_DIR jsoncpp_LIBRARY) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a57780b0..17b73863 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -248,34 +248,29 @@ target_include_directories(openshot ################### JSONCPP ##################### # Include jsoncpp headers (needed for JSON parsing) if (USE_SYSTEM_JSONCPP) - message(STATUS "Looking for system JsonCpp") - find_package(JsonCpp) - if (JSONCPP_FOUND AND NOT TARGET jsoncpp_lib) - # Create the expected target, for older installs that don't - add_library(jsoncpp_lib INTERFACE) - target_include_directories(jsoncpp_lib INTERFACE - ${JSONCPP_INCLUDE_DIRS}) - target_link_libraries(jsoncpp_lib INTERFACE ${JSONCPP_LIBRARY}) - endif () + message(STATUS "Looking for system jsoncpp") + # Either an installed config or our find module will + # create the IMPORTED target jsoncpp_lib if successful + find_package(jsoncpp) endif () -if (NOT JSONCPP_FOUND AND NOT DISABLE_BUNDLED_JSONCPP) - message(STATUS "Using embedded JsonCpp (not found or USE_SYSTEM_JSONCPP disabled)") +if (NOT jsoncpp_FOUND AND NOT DISABLE_BUNDLED_JSONCPP) + message(STATUS "Using embedded jsoncpp (not found or USE_SYSTEM_JSONCPP disabled)") if (NOT TARGET jsoncpp_lib) add_library(jsoncpp_lib INTERFACE) target_include_directories(jsoncpp_lib INTERFACE "${PROJECT_SOURCE_DIR}/thirdparty/jsoncpp") target_sources(jsoncpp_lib INTERFACE "${PROJECT_SOURCE_DIR}/thirdparty/jsoncpp/jsoncpp.cpp") # Because this satisfies the requirement, an installed JsonCpp is optional - set_package_properties(JsonCpp PROPERTIES TYPE OPTIONAL) + set_package_properties(jsoncpp PROPERTIES TYPE OPTIONAL) endif () - add_feature_info("JsonCpp (embedded)" TRUE "JsonCpp will be compiled from the bundled sources") + add_feature_info("jsoncpp (embedded)" TRUE "jsoncpp will be compiled from the bundled sources") endif () -if (JSONCPP_FOUND) +if (jsoncpp_FOUND) # JsonCpp is actually required, even though we probe for it optionally # (This tells feature_summary() to bail if it's not found, later) - set_package_properties(JsonCpp PROPERTIES TYPE REQUIRED) + set_package_properties(jsoncpp PROPERTIES TYPE REQUIRED) endif () # If we found any usable JsonCpp, use it. Otherwise, bail. From b766baf752cdba3df2acaadca511d8e008b4eac0 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 17 Apr 2020 09:59:41 -0400 Subject: [PATCH 046/100] Findjsoncpp: Fix target --- cmake/Modules/Findjsoncpp.cmake | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/Modules/Findjsoncpp.cmake b/cmake/Modules/Findjsoncpp.cmake index bd30fea7..75f7db4a 100644 --- a/cmake/Modules/Findjsoncpp.cmake +++ b/cmake/Modules/Findjsoncpp.cmake @@ -41,10 +41,10 @@ if (jsoncpp_FOUND AND NOT TARGET jsoncpp_lib) add_library(jsoncpp_lib UNKNOWN IMPORTED) set_property(TARGET jsoncpp_lib PROPERTY - INTERFACE_INCLUDE_DIRECTORIES ${JSONCPP_INCLUDE_DIR}) + INTERFACE_INCLUDE_DIRECTORIES ${jsoncpp_INCLUDE_DIR}) set_property(TARGET jsoncpp_lib PROPERTY - IMPORTED_LOCATION ${JSONCPP_LIBRARY}) + IMPORTED_LOCATION ${jsoncpp_LIBRARY}) endif() # debug library on windows @@ -63,14 +63,15 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # Add Debug location to IMPORTED target if(TARGET jsoncpp_lib) set_property(TARGET jsoncpp_lib APPEND PROPERTY - IMPORTED_LOCATION_Debug ${JSONCPP_LIBRARY_DEBUG}) + IMPORTED_LOCATION_Debug ${jsoncpp_LIBRARY_DEBUG}) endif() endif() -# find JSONCPP_INCLUDE_PREFIX +# find jsoncpp_INCLUDE_PREFIX find_path( jsoncpp_INCLUDE_PREFIX NAMES json.h + HINTS ${jsoncpp_INCLUDE_DIR} PATH_SUFFIXES jsoncpp/json json ) @@ -119,7 +120,7 @@ set(JSONCPP_INCLUDE_PREFIX ${jsoncpp_INCLUDE_PREFIX}) set(JSONCPP_VERSION ${jsoncpp_VERSION}) set(JSONCPP_FOUND ${jsoncpp_FOUND}) -# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE +# handle the QUIETLY and REQUIRED arguments and set jsoncpp_FOUND to TRUE # if all listed variables are TRUE, hide their existence from configuration view include(FindPackageHandleStandardArgs) find_package_handle_standard_args(jsoncpp From 9796b82857bfdadeee0fe4bc52b048644eb5d1b0 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 22 Apr 2020 01:35:09 -0400 Subject: [PATCH 047/100] Travis: Fix package list syntax, contents - Get rid of two-stage definition of apt.packages list, which was never necessary anyway. - Remove deprecated libavresample from package set for FFmpeg 4 --- .travis.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index c93822fc..24e772af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,18 +11,12 @@ addons: apt: packages: &p_common # Packages common to all Ubuntu builds - cmake - - swig - libopenshot-audio-dev - libmagick++-dev - libunittest++-dev - libzmq3-dev - qtbase5-dev - qtmultimedia5-dev - - doxygen - - graphviz - - curl - packages: &ff_common # Common set of FFmpeg packages - - *p_common - libfdk-aac-dev - libavcodec-dev - libavformat-dev @@ -31,8 +25,11 @@ addons: - libavfilter-dev - libswscale-dev - libpostproc-dev - - libavresample-dev - libswresample-dev + - swig + - doxygen + - graphviz + - curl jobs: include: @@ -50,8 +47,9 @@ jobs: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' packages: - - *ff_common + - *p_common - qt5-default + - libavresample-dev - libjsoncpp-dev - lcov - binutils-common # For c++filt @@ -70,7 +68,7 @@ jobs: - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' - sourceline: 'ppa:jonathonf/ffmpeg-4' packages: - - *ff_common + - *p_common - qt5-default - libjsoncpp-dev - libavcodec58 @@ -80,7 +78,6 @@ jobs: - libavfilter7 - libswscale5 - libpostproc55 - - libavresample4 - libswresample3 - name: "FFmpeg 3.4 Clang (Ubuntu 18.04 Bionic)" @@ -97,8 +94,9 @@ jobs: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' packages: - - *ff_common + - *p_common - qt5-default + - libavresample-dev - libomp-dev - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" @@ -115,7 +113,8 @@ jobs: - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial' - sourceline: 'ppa:jon-hedgerows/ffmpeg-backports' packages: - - *ff_common + - *p_common + - libavresample-dev - libavcodec57 - libavdevice57 - libavfilter6 @@ -139,7 +138,8 @@ jobs: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial' packages: - - *ff_common + - *p_common + - libavresample-dev script: - mkdir -p build; cd build; From f36bb334e27dd6592b40e75e43fe6edfe1e93ad0 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Wed, 22 Apr 2020 02:01:01 -0400 Subject: [PATCH 048/100] Exceptions: Rename BaseException, for python (#497) BaseException is a python standard library exception class, so it's not a great idea to redefine that name in our bindings. Renamed to ExceptionBase, which is more in keeping with our class naming system anyway. --- include/Exceptions.h | 94 ++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/include/Exceptions.h b/include/Exceptions.h index 28942050..f23cda7a 100644 --- a/include/Exceptions.h +++ b/include/Exceptions.h @@ -38,16 +38,16 @@ namespace openshot { /** * @brief Base exception class with a custom message variable. * - * A custom error message field has been added to the std::exception base class. All - * OpenShot exception classes inherit from this class. + * A std::exception-derived exception class with custom message. + * All OpenShot exception classes inherit from this class. */ - class BaseException : public std::exception //: public exception + class ExceptionBase : public std::exception //: public exception { protected: std::string m_message; public: - BaseException(std::string message) : m_message(message) { } - virtual ~BaseException() noexcept {} + ExceptionBase(std::string message) : m_message(message) { } + virtual ~ExceptionBase() noexcept {} virtual const char* what() const noexcept { // return custom message return m_message.c_str(); @@ -55,7 +55,7 @@ namespace openshot { }; /// Exception when a required chunk is missing - class ChunkNotFound : public BaseException + class ChunkNotFound : public ExceptionBase { public: int64_t frame_number; @@ -70,13 +70,13 @@ namespace openshot { * @param chunk_frame The chunk frame */ ChunkNotFound(std::string message, int64_t frame_number, int64_t chunk_number, int64_t chunk_frame) - : BaseException(message), frame_number(frame_number), chunk_number(chunk_number), chunk_frame(chunk_frame) { } + : ExceptionBase(message), frame_number(frame_number), chunk_number(chunk_number), chunk_frame(chunk_frame) { } virtual ~ChunkNotFound() noexcept {} }; /// Exception when accessing a blackmagic decklink card - class DecklinkError : public BaseException + class DecklinkError : public ExceptionBase { public: /** @@ -85,12 +85,12 @@ namespace openshot { * @param message A message to accompany the exception */ DecklinkError(std::string message) - : BaseException(message) { } + : ExceptionBase(message) { } virtual ~DecklinkError() noexcept {} }; /// Exception when decoding audio packet - class ErrorDecodingAudio : public BaseException + class ErrorDecodingAudio : public ExceptionBase { public: int64_t frame_number; @@ -101,12 +101,12 @@ namespace openshot { * @param frame_number The frame number being processed */ ErrorDecodingAudio(std::string message, int64_t frame_number) - : BaseException(message), frame_number(frame_number) { } + : ExceptionBase(message), frame_number(frame_number) { } virtual ~ErrorDecodingAudio() noexcept {} }; /// Exception when encoding audio packet - class ErrorEncodingAudio : public BaseException + class ErrorEncodingAudio : public ExceptionBase { public: int64_t frame_number; @@ -117,12 +117,12 @@ namespace openshot { * @param frame_number The frame number being processed */ ErrorEncodingAudio(std::string message, int64_t frame_number) - : BaseException(message), frame_number(frame_number) { } + : ExceptionBase(message), frame_number(frame_number) { } virtual ~ErrorEncodingAudio() noexcept {} }; /// Exception when encoding audio packet - class ErrorEncodingVideo : public BaseException + class ErrorEncodingVideo : public ExceptionBase { public: int64_t frame_number; @@ -133,12 +133,12 @@ namespace openshot { * @param frame_number The frame number being processed */ ErrorEncodingVideo(std::string message, int64_t frame_number) - : BaseException(message), frame_number(frame_number) { } + : ExceptionBase(message), frame_number(frame_number) { } virtual ~ErrorEncodingVideo() noexcept {} }; /// Exception when an invalid # of audio channels are detected - class InvalidChannels : public BaseException + class InvalidChannels : public ExceptionBase { public: std::string file_path; @@ -149,12 +149,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidChannels(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidChannels() noexcept {} }; /// Exception when no valid codec is found for a file - class InvalidCodec : public BaseException + class InvalidCodec : public ExceptionBase { public: std::string file_path; @@ -165,12 +165,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidCodec(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidCodec() noexcept {} }; /// Exception for files that can not be found or opened - class InvalidFile : public BaseException + class InvalidFile : public ExceptionBase { public: std::string file_path; @@ -181,12 +181,12 @@ namespace openshot { * @param file_path The input file being processed */ InvalidFile(std::string message, std::string file_path) - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidFile() noexcept {} }; /// Exception when no valid format is found for a file - class InvalidFormat : public BaseException + class InvalidFormat : public ExceptionBase { public: std::string file_path; @@ -197,12 +197,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidFormat(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidFormat() noexcept {} }; /// Exception for invalid JSON - class InvalidJSON : public BaseException + class InvalidJSON : public ExceptionBase { public: std::string file_path; @@ -213,12 +213,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidJSON(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidJSON() noexcept {} }; /// Exception when invalid encoding options are used - class InvalidOptions : public BaseException + class InvalidOptions : public ExceptionBase { public: std::string file_path; @@ -229,12 +229,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidOptions(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidOptions() noexcept {} }; /// Exception when invalid sample rate is detected during encoding - class InvalidSampleRate : public BaseException + class InvalidSampleRate : public ExceptionBase { public: std::string file_path; @@ -245,12 +245,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ InvalidSampleRate(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~InvalidSampleRate() noexcept {} }; /// Exception for missing JSON Change key - class InvalidJSONKey : public BaseException + class InvalidJSONKey : public ExceptionBase { public: std::string json; @@ -261,12 +261,12 @@ namespace openshot { * @param json The json data being processed */ InvalidJSONKey(std::string message, std::string json) - : BaseException(message), json(json) { } + : ExceptionBase(message), json(json) { } virtual ~InvalidJSONKey() noexcept {} }; /// Exception when no streams are found in the file - class NoStreamsFound : public BaseException + class NoStreamsFound : public ExceptionBase { public: std::string file_path; @@ -277,12 +277,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ NoStreamsFound(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~NoStreamsFound() noexcept {} }; /// Exception for frames that are out of bounds. - class OutOfBoundsFrame : public BaseException + class OutOfBoundsFrame : public ExceptionBase { public: int64_t FrameRequested; @@ -295,12 +295,12 @@ namespace openshot { * @param max_frames The maximum available frame number */ OutOfBoundsFrame(std::string message, int64_t frame_requested, int64_t max_frames) - : BaseException(message), FrameRequested(frame_requested), MaxFrames(max_frames) { } + : ExceptionBase(message), FrameRequested(frame_requested), MaxFrames(max_frames) { } virtual ~OutOfBoundsFrame() noexcept {} }; /// Exception for an out of bounds key-frame point. - class OutOfBoundsPoint : public BaseException + class OutOfBoundsPoint : public ExceptionBase { public: int PointRequested; @@ -313,12 +313,12 @@ namespace openshot { * @param max_points The maximum available point value */ OutOfBoundsPoint(std::string message, int point_requested, int max_points) - : BaseException(message), PointRequested(point_requested), MaxPoints(max_points) { } + : ExceptionBase(message), PointRequested(point_requested), MaxPoints(max_points) { } virtual ~OutOfBoundsPoint() noexcept {} }; /// Exception when memory could not be allocated - class OutOfMemory : public BaseException + class OutOfMemory : public ExceptionBase { public: std::string file_path; @@ -329,12 +329,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ OutOfMemory(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~OutOfMemory() noexcept {} }; /// Exception when a reader is closed, and a frame is requested - class ReaderClosed : public BaseException + class ReaderClosed : public ExceptionBase { public: std::string file_path; @@ -345,12 +345,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ ReaderClosed(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~ReaderClosed() noexcept {} }; /// Exception when resample fails - class ResampleError : public BaseException + class ResampleError : public ExceptionBase { public: std::string file_path; @@ -361,12 +361,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ ResampleError(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~ResampleError() noexcept {} }; /// Exception when too many seek attempts happen - class TooManySeeks : public BaseException + class TooManySeeks : public ExceptionBase { public: std::string file_path; @@ -377,12 +377,12 @@ namespace openshot { * @param file_path (optional) The input file being processed */ TooManySeeks(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~TooManySeeks() noexcept {} }; /// Exception when a writer is closed, and a frame is requested - class WriterClosed : public BaseException + class WriterClosed : public ExceptionBase { public: std::string file_path; @@ -393,7 +393,7 @@ namespace openshot { * @param file_path (optional) The output file being written */ WriterClosed(std::string message, std::string file_path="") - : BaseException(message), file_path(file_path) { } + : ExceptionBase(message), file_path(file_path) { } virtual ~WriterClosed() noexcept {} }; } From 6336f30ee3ea24ccc8fb85c26e8a3d2135cb4545 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Wed, 22 Apr 2020 02:02:55 -0400 Subject: [PATCH 049/100] Various: Remove unused variables (#467) Several data members and local variables were flagged by static analysis tools as never being used anywhere in the code. --- include/AudioBufferSource.h | 1 - include/AudioReaderSource.h | 1 - include/Clip.h | 1 - include/FFmpegWriter.h | 1 - include/ImageWriter.h | 1 - src/AudioBufferSource.cpp | 2 +- src/AudioReaderSource.cpp | 2 +- src/CacheDisk.cpp | 2 +- src/Clip.cpp | 12 +++--------- src/FFmpegReader.cpp | 5 +---- src/FFmpegWriter.cpp | 3 +-- src/ImageWriter.cpp | 2 +- src/Timeline.cpp | 3 --- src/{bindings/ruby/test.rb => examples/Example.rb} | 0 14 files changed, 9 insertions(+), 27 deletions(-) rename src/{bindings/ruby/test.rb => examples/Example.rb} (100%) diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h index 3a17feb3..ae5ce014 100644 --- a/include/AudioBufferSource.h +++ b/include/AudioBufferSource.h @@ -48,7 +48,6 @@ namespace openshot { private: int position; - int start; bool repeat; juce::AudioSampleBuffer *buffer; diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index c4e2d248..d049e1b3 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -54,7 +54,6 @@ namespace openshot int speed; /// The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) ReaderBase *reader; /// The reader to pull samples from - int64_t original_frame_number; /// The current frame to read from int64_t frame_number; /// The current frame number std::shared_ptr frame; /// The current frame object that is being read int64_t frame_position; /// The position of the current frame's buffer diff --git a/include/Clip.h b/include/Clip.h index 1f4cd385..e153acb4 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -103,7 +103,6 @@ namespace openshot { // Audio resampler (if time mapping) openshot::AudioResampler *resampler; - juce::AudioSampleBuffer *audio_cache; // File Reader object openshot::ReaderBase* reader; diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 1dfb21a9..37fa22dc 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -167,7 +167,6 @@ namespace openshot { AVCodecContext *video_codec; AVCodecContext *audio_codec; SwsContext *img_convert_ctx; - double audio_pts, video_pts; int16_t *samples; uint8_t *audio_outbuf; uint8_t *audio_encoder_buffer; diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 87e8a9a9..e483cb10 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -88,7 +88,6 @@ namespace openshot private: std::string path; int cache_size; - bool is_writing; bool is_open; int64_t write_video_count; std::vector frames; diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp index 2f3d14ca..69e5713a 100644 --- a/src/AudioBufferSource.cpp +++ b/src/AudioBufferSource.cpp @@ -35,7 +35,7 @@ using namespace openshot; // Default constructor AudioBufferSource::AudioBufferSource(juce::AudioSampleBuffer *audio_buffer) - : position(0), start(0), repeat(false), buffer(audio_buffer) + : position(0), repeat(false), buffer(audio_buffer) { } // Destructor diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index c96d0bcc..999d109d 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -35,7 +35,7 @@ using namespace openshot; // Constructor that reads samples from a reader AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64_t starting_frame_number, int buffer_size) - : reader(audio_reader), frame_number(starting_frame_number), original_frame_number(starting_frame_number), + : reader(audio_reader), frame_number(starting_frame_number), size(buffer_size), position(0), frame_position(0), estimated_frame(0), speed(1) { // Initialize an audio buffer (based on reader) diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp index 9f67ce99..bb2e12c4 100644 --- a/src/CacheDisk.cpp +++ b/src/CacheDisk.cpp @@ -228,7 +228,7 @@ std::shared_ptr CacheDisk::GetFrame(int64_t frame_number) // Load image file std::shared_ptr image = std::shared_ptr(new QImage()); - bool success = image->load(QString::fromStdString(frame_path.toStdString())); + image->load(frame_path); // Set pixel formatimage-> image = std::shared_ptr(new QImage(image->convertToFormat(QImage::Format_RGBA8888))); diff --git a/src/Clip.cpp b/src/Clip.cpp index 1968bb3b..39aad35d 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -132,14 +132,14 @@ void Clip::init_reader_rotation() { } // Default Constructor for a clip -Clip::Clip() : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) +Clip::Clip() : resampler(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); } // Constructor with reader -Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader(new_reader), allocated_reader(NULL) +Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -153,7 +153,7 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader( } // Constructor with filepath -Clip::Clip(std::string path) : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) +Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -422,7 +422,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num int delta = int(round(time.GetDelta(frame_number))); // Init audio vars - int sample_rate = reader->info.sample_rate; int channels = reader->info.channels; int number_of_samples = GetOrCreateFrame(new_frame_number)->GetAudioSamplesCount(); @@ -433,7 +432,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // SLOWING DOWN AUDIO // Resample data, and return new buffer pointer juce::AudioSampleBuffer *resampled_buffer = NULL; - int resampled_buffer_size = 0; // SLOW DOWN audio (split audio) samples = new juce::AudioSampleBuffer(channels, number_of_samples); @@ -455,9 +453,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // Resample the data (since it's the 1st slice) resampled_buffer = resampler->GetResampledBuffer(); - // Get the length of the resampled buffer (if one exists) - resampled_buffer_size = resampled_buffer->getNumSamples(); - // Just take the samples we need for the requested frame int start = (number_of_samples * (time.GetRepeatFraction(frame_number).num - 1)); if (start > 0) @@ -567,7 +562,6 @@ void Clip::get_time_mapped_frame(std::shared_ptr frame, int64_t frame_num // Resample data, and return new buffer pointer juce::AudioSampleBuffer *buffer = resampler->GetResampledBuffer(); - int resampled_buffer_size = buffer->getNumSamples(); // Add the newly resized audio samples to the current frame for (int channel = 0; channel < channels; channel++) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 550648a1..c8ce141f 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -1426,8 +1426,6 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr int packet_samples = 0; int data_size = 0; - // re-initialize buffer size (it gets changed in the avcodec_decode_audio2 method call) - int buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE; #pragma omp critical (ProcessAudioPacket) { #if IS_FFMPEG_3_2 @@ -1465,7 +1463,6 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr if (frame_finished) { // determine how many samples were decoded - int planar = av_sample_fmt_is_planar((AVSampleFormat) AV_GET_CODEC_PIXEL_FORMAT(aStream, aCodecCtx)); int plane_size = -1; data_size = av_samples_get_buffer_size(&plane_size, AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels, @@ -1554,7 +1551,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr, "in_channels", info.channels, 0); av_opt_set_int(avr, "out_channels", info.channels, 0); - int r = SWR_INIT(avr); + SWR_INIT(avr); // Convert audio samples nb_samples = SWR_CONVERT(avr, // audio resample context diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 2b97ba91..ce8f6557 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -84,7 +84,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 #endif // HAVE_HW_ACCEL FFmpegWriter::FFmpegWriter(std::string path) : - path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL), + path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32), rescaler_position(0), video_codec(NULL), audio_codec(NULL), is_writing(false), write_video_count(0), write_audio_count(0), @@ -2030,7 +2030,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra int error_code = 0; #if IS_FFMPEG_3_2 // Write video packet (latest version of FFmpeg) - int frameFinished = 0; int ret; #if HAVE_HW_ACCEL diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 376feb62..1b7a01e9 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -39,7 +39,7 @@ using namespace openshot; ImageWriter::ImageWriter(std::string path) : - path(path), cache_size(8), is_writing(false), write_video_count(0), image_quality(75), number_of_loops(1), + path(path), cache_size(8), write_video_count(0), image_quality(75), number_of_loops(1), combine_frames(true), is_open(false) { // Disable audio & video (so they can be independently enabled) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 61ce31e3..0a0806b1 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -524,9 +524,6 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in // Loop through pixels for (int pixel = 0, byte_index=0; pixel < source_image->width() * source_image->height(); pixel++, byte_index+=4) { - // Get the alpha values from the pixel - int A = pixels[byte_index + 3]; - // Apply alpha to pixel pixels[byte_index + 3] *= alpha; } diff --git a/src/bindings/ruby/test.rb b/src/examples/Example.rb similarity index 100% rename from src/bindings/ruby/test.rb rename to src/examples/Example.rb From 5c688f1edfb9a39f9b89faf333e052d4a8ba01e2 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 7 May 2020 11:56:44 -0400 Subject: [PATCH 050/100] Add QT_VERSION_STR define to OpenShotVersion.h The CMake process will pick up Qt's Qt5Core_VERSION_STRING and stick it in a cache variable (with forced updating each run), and a new `#define` in the header exports it to the library and to the Python bindings so that it can be queried at runtime. --- CMakeLists.txt | 12 ++++++------ include/OpenShotVersion.h.in | 5 ++++- src/CMakeLists.txt | 4 ++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb3fe8cc..f50c575f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,12 +91,6 @@ if(DEFINED ENABLE_TESTS) set(ENABLE_TESTS ${ENABLE_TESTS} CACHE BOOL "Build unit tests (requires UnitTest++)" FORCE) endif() -########## Configure Version.h header ############## -configure_file(include/OpenShotVersion.h.in include/OpenShotVersion.h @ONLY) -# We'll want that installed later -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/OpenShotVersion.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot) - #### Work around a GCC < 9 bug with handling of _Pragma() in macros #### See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND @@ -142,6 +136,12 @@ endif() ############## PROCESS src/ DIRECTORIES ############## add_subdirectory(src) +########## Configure Version.h header ############## +configure_file(include/OpenShotVersion.h.in include/OpenShotVersion.h @ONLY) +# We'll want that installed later +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/OpenShotVersion.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libopenshot) + ################### DOCUMENTATION ################### # Find Doxygen (used for documentation) set(DOCS_ENABLED FALSE) # Only set true if Doxygen is found and configured diff --git a/include/OpenShotVersion.h.in b/include/OpenShotVersion.h.in index e15662b2..d8cf0735 100644 --- a/include/OpenShotVersion.h.in +++ b/include/OpenShotVersion.h.in @@ -42,6 +42,9 @@ #define OPENSHOT_VERSION_SO @PROJECT_SO_VERSION@ /// Shared object version number. This increments any time the API and ABI changes (so old apps will no longer link) +// Useful dependency versioning +#define QT_VERSION_STR "@QT_VERSION_STR@" + #include namespace openshot @@ -67,4 +70,4 @@ namespace openshot openshot::OpenShotVersion GetVersion(); } -#endif // OPENSHOT_VERSION_H \ No newline at end of file +#endif // OPENSHOT_VERSION_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17b73863..24ed7764 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -289,6 +289,10 @@ foreach(_qt_comp IN LISTS _qt_components) endif() endforeach() +# Keep track of Qt version, to embed in our version header +set(QT_VERSION_STR ${Qt5Core_VERSION_STRING} CACHE STRING "Qt version linked with" FORCE) +mark_as_advanced(QT_VERSION_STR) + ################### FFMPEG ##################### # Find FFmpeg libraries (used for video encoding / decoding) find_package(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale) From 6e7ad2316b56f6219e67b83e37ed43b5315544ce Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 7 May 2020 18:24:59 -0400 Subject: [PATCH 051/100] Add version.sh script (#500) --- version.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 version.sh diff --git a/version.sh b/version.sh new file mode 100755 index 00000000..86a664dc --- /dev/null +++ b/version.sh @@ -0,0 +1,4 @@ +#!/bin/sh +grep 'set.*(.*PROJECT_VERSION_FULL' CMakeLists.txt\ + |sed -e 's#set(PROJECT_VERSION_FULL.*"\(.*\)\")#\1#;q' + From 0e79844ed96d262c91dd6dccde2d19271fdf4d91 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 9 May 2020 18:33:03 -0400 Subject: [PATCH 052/100] Add more build-config variables - HAVE_IMAGEMAGICK and HAVE_RESVG will be #defined 0 or 1 - AV{CODEC,FORMAT,UTIL}_VERSION_STR will contain the FFmpeg component versions detected by CMake when configuring the build --- include/OpenShotVersion.h.in | 9 +++++++-- src/CMakeLists.txt | 25 ++++++++++++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/OpenShotVersion.h.in b/include/OpenShotVersion.h.in index d8cf0735..d0b015a4 100644 --- a/include/OpenShotVersion.h.in +++ b/include/OpenShotVersion.h.in @@ -42,8 +42,13 @@ #define OPENSHOT_VERSION_SO @PROJECT_SO_VERSION@ /// Shared object version number. This increments any time the API and ABI changes (so old apps will no longer link) -// Useful dependency versioning -#define QT_VERSION_STR "@QT_VERSION_STR@" +// Useful dependency versioning / feature availability +#cmakedefine QT_VERSION_STR "@QT_VERSION_STR@" +#cmakedefine AVCODEC_VERSION_STR "@AVCODEC_VERSION_STR@" +#cmakedefine AVFORMAT_VERSION_STR "@AVFORMAT_VERSION_STR@" +#cmakedefine AVUTIL_VERSION_STR "@AVUTIL_VERSION_STR@" +#cmakedefine01 HAVE_IMAGEMAGICK +#cmakedefine01 HAVE_RESVG #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24ed7764..90c74ead 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,11 +59,6 @@ IF (MAGICKCORE_HDRI_ENABLE) ELSE (MAGICKCORE_HDRI_ENABLE) add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 ) ENDIF (MAGICKCORE_HDRI_ENABLE) -IF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) - add_definitions( -DOPENSHOT_IMAGEMAGICK_COMPATIBILITY=${OPENSHOT_IMAGEMAGICK_COMPATIBILITY} ) -ELSE (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) - add_definitions( -DOPENSHOT_IMAGEMAGICK_COMPATIBILITY=0 ) -ENDIF (OPENSHOT_IMAGEMAGICK_COMPATIBILITY) # Find the ImageMagick++ library find_package(ImageMagick COMPONENTS Magick++ MagickWand MagickCore) @@ -75,6 +70,8 @@ if (ImageMagick_FOUND) add_definitions( -DUSE_IMAGEMAGICK=1 ) set(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") + set(HAVE_IMAGEMAGICK TRUE CACHE BOOL "Building with ImageMagick support" FORCE) + mark_as_advanced(HAVE_IMAGEMAGICK) endif() ################# LIBOPENSHOT-AUDIO ################### @@ -297,10 +294,20 @@ mark_as_advanced(QT_VERSION_STR) # Find FFmpeg libraries (used for video encoding / decoding) find_package(FFmpeg REQUIRED COMPONENTS avcodec avdevice avformat avutil swscale) -foreach(ff_comp avcodec avdevice avformat avfilter avutil postproc swscale swresample avresample) +set(all_comps avcodec avdevice avformat avfilter avutil postproc swscale swresample avresample) +set(version_comps avcodec avformat avutil) + +foreach(ff_comp IN LISTS all_comps) if(TARGET FFmpeg::${ff_comp}) - target_link_libraries(openshot PUBLIC FFmpeg::${ff_comp}) + target_link_libraries(openshot PUBLIC FFmpeg::${ff_comp}) + # Keep track of some FFmpeg lib versions, to embed in our version header + if(${ff_comp} IN_LIST version_comps) + string(TOUPPER ${ff_comp} v_name) + set(${v_name}_VERSION_STR ${${ff_comp}_VERSION} CACHE STRING "${ff_comp} version used" FORCE) + mark_as_advanced(${v_name}_VERSION_STR) + endif() endif() + endforeach() ################### Threads #################### @@ -363,6 +370,10 @@ if (TARGET RESVG::resvg) target_compile_definitions(openshot PUBLIC "-DUSE_RESVG=1") set(CMAKE_SWIG_FLAGS "-DUSE_RESVG=1") + + set(HAVE_RESVG TRUE CACHE BOOL "Building with Resvg support" FORCE) + mark_as_advanced(HAVE_RESVG) + endif() ############### LINK LIBRARY ################# From 13290364e7bea54164ab83d973951f2898ad9e23 Mon Sep 17 00:00:00 2001 From: Stefan Strogin Date: Sat, 16 May 2020 02:33:37 +0300 Subject: [PATCH 053/100] FFmpegUtilities: replace variable definition with statement expression It is needed to avoid multiple definitions of AV_GET_CODEC_CONTEXT, which is considered as an error with '-fno-common' which is default since gcc-10. Fixes: #511 --- include/FFmpegUtilities.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 62d64df1..b4ec951f 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -163,11 +163,10 @@ #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context) #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id - auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \ - AVCodecContext *context = avcodec_alloc_context3(av_codec); \ - avcodec_parameters_to_context(context, av_stream->codecpar); \ - return context; \ - }; + #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) \ + ({ AVCodecContext *context = avcodec_alloc_context3(av_codec); \ + avcodec_parameters_to_context(context, av_stream->codecpar); \ + context; }) #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec; #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in) #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar @@ -199,11 +198,10 @@ #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context) #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id - auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \ - AVCodecContext *context = avcodec_alloc_context3(av_codec); \ - avcodec_parameters_to_context(context, av_stream->codecpar); \ - return context; \ - }; + #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) \ + ({ AVCodecContext *context = avcodec_alloc_context3(av_codec); \ + avcodec_parameters_to_context(context, av_stream->codecpar); \ + context; }) #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec; #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in) #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar From 4e6c1819b0af7e33ac27d22fa02a09ad268f25b1 Mon Sep 17 00:00:00 2001 From: Jeff Shillitto Date: Sat, 16 May 2020 18:55:34 +1000 Subject: [PATCH 054/100] Set clip in constructor to resolve scale crop issue --- src/Clip.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Clip.cpp b/src/Clip.cpp index 39aad35d..cdb83cdc 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -150,6 +150,10 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), alloca // Update duration End(reader->info.duration); + + if (new_reader) { + new_reader->SetClip(this); + } } // Constructor with filepath From 5b5950c9913501bfe11feacac32e4a0bdc4ce568 Mon Sep 17 00:00:00 2001 From: Jeff Shillitto Date: Tue, 19 May 2020 19:57:06 +1000 Subject: [PATCH 055/100] use reader instead of new_reader --- src/Clip.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Clip.cpp b/src/Clip.cpp index cdb83cdc..fa1bb7c7 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -148,11 +148,10 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), alloca Open(); Close(); - // Update duration - End(reader->info.duration); - - if (new_reader) { - new_reader->SetClip(this); + // Update duration and set parent + if (reader) { + End(reader->info.duration); + reader->SetClip(this); } } @@ -206,9 +205,10 @@ Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(N } } - // Update duration + // Update duration and set parent if (reader) { End(reader->info.duration); + reader->SetClip(this); allocated_reader = reader; init_reader_rotation(); } From 216184dbb98308725b3715c5bc6a0f2ceff87ff3 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 19 May 2020 06:30:54 -0400 Subject: [PATCH 056/100] Work around Ruby/JUCE isfinite() conflict properly --- src/bindings/ruby/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 2faa10fc..18964486 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -72,6 +72,9 @@ endif() set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) +### Unbreak std::isfinite() +add_compile_definitions(HAVE_ISFINITE=1) + ### Suppress a ton of warnings in the generated SWIG C++ code set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \ -Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \ From 130829a41231b9ccb24493ab74d898e0d5bee339 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 19 May 2020 06:32:35 -0400 Subject: [PATCH 057/100] Deprecated juce::ScopedPointer => std::unique_ptr --- src/Frame.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Frame.cpp b/src/Frame.cpp index 9577a7f9..36e0af08 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -992,8 +992,8 @@ void Frame::Play() juce::AudioSourcePlayer audioSourcePlayer; deviceManager.addAudioCallback (&audioSourcePlayer); - ScopedPointer my_source; - my_source = new AudioBufferSource(audio.get()); + std::unique_ptr my_source; + my_source.reset (new AudioBufferSource (audio.get())); // Create TimeSliceThread for audio buffering juce::TimeSliceThread my_thread("Audio buffer thread"); @@ -1002,7 +1002,7 @@ void Frame::Play() my_thread.startThread(); AudioTransportSource transport1; - transport1.setSource (my_source, + transport1.setSource (my_source.get(), 5000, // tells it to buffer this many samples ahead &my_thread, (double) sample_rate, From affd4b248898a2958300a08697919e347d75aee0 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 19 May 2020 06:33:30 -0400 Subject: [PATCH 058/100] Add some missing juce:: prefixing --- include/Qt/AudioPlaybackThread.h | 8 ++++---- src/Frame.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index 348a0f48..9a159448 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -75,7 +75,7 @@ namespace openshot static AudioDeviceManagerSingleton * Instance(); /// Public device manager property - AudioDeviceManager audioDeviceManager; + juce::AudioDeviceManager audioDeviceManager; /// Close audio device void CloseAudioDevice(); @@ -86,9 +86,9 @@ namespace openshot */ class AudioPlaybackThread : juce::Thread { - AudioSourcePlayer player; - AudioTransportSource transport; - MixerAudioSource mixer; + juce::AudioSourcePlayer player; + juce::AudioTransportSource transport; + juce::MixerAudioSource mixer; AudioReaderSource *source; double sampleRate; int numChannels; diff --git a/src/Frame.cpp b/src/Frame.cpp index 36e0af08..ae9f1a4b 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -829,7 +829,7 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines) if (ret) { return; } - + // Get the frame's image const GenericScopedLock lock(addingImageSection); #pragma omp critical (AddImage) @@ -979,7 +979,8 @@ void Frame::Play() return; juce::AudioDeviceManager deviceManager; - String error = deviceManager.initialise (0, /* number of input channels */ + juce::String error = deviceManager.initialise ( + 0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ true /* select default device on failure */); @@ -1001,7 +1002,7 @@ void Frame::Play() // Start thread my_thread.startThread(); - AudioTransportSource transport1; + juce::AudioTransportSource transport1; transport1.setSource (my_source.get(), 5000, // tells it to buffer this many samples ahead &my_thread, From 128bacce708fb01ef9b6a63060b2c1ff29e91bc0 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 19 May 2020 07:19:01 -0400 Subject: [PATCH 059/100] Support older CMake add_compile_definitions() is CMake 3.12+ only. --- src/bindings/ruby/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 18964486..4d7b922a 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -73,7 +73,7 @@ set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) ### Unbreak std::isfinite() -add_compile_definitions(HAVE_ISFINITE=1) +add_definitions(-DHAVE_ISFINITE=1) ### Suppress a ton of warnings in the generated SWIG C++ code set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \ From e4dd72669f4778b92d139b12ef5c8d166934c94e Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 1 Jun 2020 13:24:07 -0500 Subject: [PATCH 060/100] Fix FPS setting on FFmpeg 4, which currently is not setting a valid FPS. --- src/FFmpegWriter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index ce8f6557..cd3185c4 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1222,6 +1222,13 @@ AVStream *FFmpegWriter::add_video_stream() { st->avg_frame_rate = av_inv_q(c->time_base); st->time_base.num = info.video_timebase.num; st->time_base.den = info.video_timebase.den; +#if (LIBAVFORMAT_VERSION_MAJOR >= 58) + _Pragma ("GCC diagnostic push"); + _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \ + st->codec->time_base.num = info.video_timebase.num; + st->codec->time_base.den = info.video_timebase.den; + _Pragma ("GCC diagnostic pop"); +#endif c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */ c->max_b_frames = 10; From 2a043014824822e74dd4d3710df55609d6919836 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 1 Jun 2020 15:24:15 -0400 Subject: [PATCH 061/100] Travis: allow_failures for FFmpeg 3.2 --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 24e772af..c8af86a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,12 @@ addons: - curl jobs: - include: + # The FFmpeg 3.2 backport PPA has gone missing + allow_failures: + - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" + + include: - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" env: - BUILD_VERSION=coverage_ffmpeg34 From 58c971a57690b533fba40cd6da077bec538c8c02 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 1 Jun 2020 15:24:15 -0400 Subject: [PATCH 062/100] Travis: allow_failures for FFmpeg 3.2 --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 24e772af..c8af86a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,8 +32,12 @@ addons: - curl jobs: - include: + # The FFmpeg 3.2 backport PPA has gone missing + allow_failures: + - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" + + include: - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" env: - BUILD_VERSION=coverage_ffmpeg34 From 456715437a31471209c14a58c03d7a6abea48b1f Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 1 Jun 2020 17:05:18 -0400 Subject: [PATCH 063/100] Remove unused Qt PPAs --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c8af86a7..af54662f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,7 +49,6 @@ jobs: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' packages: - *p_common - qt5-default @@ -96,7 +95,6 @@ jobs: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' packages: - *p_common - qt5-default @@ -114,7 +112,6 @@ jobs: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial' - sourceline: 'ppa:jon-hedgerows/ffmpeg-backports' packages: - *p_common From 1dd0281deb74d1287da15cf2c4309a76acd3a441 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 1 Jun 2020 17:06:04 -0400 Subject: [PATCH 064/100] Use Ubuntu 20.04 for FFmpeg 4 --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index af54662f..241d5be3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,19 +57,17 @@ jobs: - lcov - binutils-common # For c++filt - - name: "FFmpeg 4 GCC (Ubuntu 18.04 Bionic)" + - name: "FFmpeg 4 GCC (Ubuntu 20.04 Focal)" env: - BUILD_VERSION=ffmpeg4 - CMAKE_EXTRA_ARGS="" - TEST_TARGET=test os: linux - dist: bionic + dist: focal addons: apt: sources: - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic' - - sourceline: 'ppa:jonathonf/ffmpeg-4' packages: - *p_common - qt5-default From 511a6b1da2e349afb593836498b239c5c21dac99 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Mon, 1 Jun 2020 17:58:22 -0400 Subject: [PATCH 065/100] Update Ruby compatibility message --- src/bindings/ruby/CMakeLists.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 4d7b922a..2ec16dcf 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -48,13 +48,15 @@ option(SILENCE_RUBY_VERSION_WARNING if (${RUBY_VERSION} VERSION_GREATER 2.6.9 AND ${SWIG_VERSION} VERSION_LESS 4.0.3) if (NOT ${SILENCE_RUBY_VERSION_WARNING}) - message(WARNING " + message(WARNING "\ Ruby 2.7.0+ detected, building the libopenshot Ruby API bindings \ -requires a pre-release version of SWIG 4.0.3 with this commit: \ -https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4") - message(STATUS " -To disable this warning, add -DSILENCE_RUBY_VERSION_WARNING:BOOL=1 to the cmake \ -command line, or enable the option in the CMake GUI.") +requires either SWIG 4.0.3 or an older version patched with this commit: \ +https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4 \ +(Recent Fedora and Ubuntu distro packages of SWIG 4.0.1 have already been \ +patched.)") + message(STATUS "To disable the previous warning, add \ +-DSILENCE_RUBY_VERSION_WARNING:BOOL=1 to the cmake command line, \ +or enable the option in the CMake GUI.") endif() endif() From 93d12e7f14e8c4f002e5f98af14412b80a4cd53b Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 2 Jun 2020 08:53:39 -0700 Subject: [PATCH 066/100] Include data for fps in clip created by ffmpeg 4+ --- src/FFmpegWriter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index cc4b3d3a..e10b7026 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1266,6 +1266,13 @@ AVStream *FFmpegWriter::add_video_stream() { st->avg_frame_rate = av_inv_q(c->time_base); st->time_base.num = info.video_timebase.num; st->time_base.den = info.video_timebase.den; +#if (LIBAVFORMAT_VERSION_MAJOR >= 58) + _Pragma ("GCC diagnostic push"); + _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \ + st->codec->time_base.num = info.video_timebase.num; + st->codec->time_base.den = info.video_timebase.den; + _Pragma ("GCC diagnostic pop"); +#endif c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */ c->max_b_frames = 10; From 7ed26cf0223fbfd0a6f4988b9dd1099324496e8a Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 2 Jun 2020 13:30:05 -0500 Subject: [PATCH 067/100] Replace _Pragma with #pragma Co-authored-by: Frank Dana --- src/FFmpegWriter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index cd3185c4..5b57218f 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1223,11 +1223,11 @@ AVStream *FFmpegWriter::add_video_stream() { st->time_base.num = info.video_timebase.num; st->time_base.den = info.video_timebase.den; #if (LIBAVFORMAT_VERSION_MAJOR >= 58) - _Pragma ("GCC diagnostic push"); - _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" st->codec->time_base.num = info.video_timebase.num; st->codec->time_base.den = info.video_timebase.den; - _Pragma ("GCC diagnostic pop"); + #pragma GCC diagnostic pop #endif c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */ From d9e6af5cda54ad7d33569563d86653bcfc58a890 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 2 Jun 2020 11:35:07 -0700 Subject: [PATCH 068/100] Refert last commit --- src/FFmpegWriter.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e10b7026..cc4b3d3a 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1266,13 +1266,6 @@ AVStream *FFmpegWriter::add_video_stream() { st->avg_frame_rate = av_inv_q(c->time_base); st->time_base.num = info.video_timebase.num; st->time_base.den = info.video_timebase.den; -#if (LIBAVFORMAT_VERSION_MAJOR >= 58) - _Pragma ("GCC diagnostic push"); - _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \ - st->codec->time_base.num = info.video_timebase.num; - st->codec->time_base.den = info.video_timebase.den; - _Pragma ("GCC diagnostic pop"); -#endif c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */ c->max_b_frames = 10; From f4b40a4e7749f0d45ff850928ca935d9e6c99682 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 4 Jun 2020 08:28:33 -0700 Subject: [PATCH 069/100] Improvements to handling of new codecs --- src/FFmpegWriter.cpp | 61 +++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e6a7e5ef..9b348aed 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -479,15 +479,6 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va case AV_CODEC_ID_AV1 : c->bit_rate = 0; av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); - if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { - av_opt_set_int(c->priv_data, "preset", 6, 0); - av_opt_set_int(c->priv_data, "forced-idr",1,0); - } - if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { - av_opt_set_int(c->priv_data, "speed", 7, 0); - av_opt_set_int(c->priv_data, "tile-rows", 2, 0); - av_opt_set_int(c->priv_data, "tile-columns", 4, 0); - } break; #endif case AV_CODEC_ID_VP8 : @@ -547,24 +538,17 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va c->bit_rate = 0; if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0); - av_opt_set_int(c->priv_data, "preset", 6, 0); - av_opt_set_int(c->priv_data, "forced-idr",1,0); } else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { // Set number of tiles to a fixed value // TODO Let user choose number of tiles av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); - av_opt_set_int(c->priv_data, "speed", 7, 0); - av_opt_set_int(c->priv_data, "tile-rows", 2, 0); // number of rows - av_opt_set_int(c->priv_data, "tile-columns", 4, 0); // number of columns } else if (strstr(info.vcodec.c_str(), "aom") != NULL) { // Set number of tiles to a fixed value // TODO Let user choose number of tiles // libaom doesn't have qp only crf av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); - av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows - av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns } else { av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); @@ -1222,7 +1206,11 @@ AVStream *FFmpegWriter::add_video_stream() { #endif /* Init video encoder options */ - if (info.video_bit_rate >= 1000) { + if (info.video_bit_rate >= 1000 +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + && c->codec_id != AV_CODEC_ID_AV1 +#endif + ) { c->bit_rate = info.video_bit_rate; if (info.video_bit_rate >= 1500000) { c->qmin = 2; @@ -1231,11 +1219,48 @@ AVStream *FFmpegWriter::add_video_stream() { // Here should be the setting for low fixed bitrate // Defaults are used because mpeg2 otherwise had problems } else { - // Check if codec supports crf + // Check if codec supports crf or qp switch (c->codec_id) { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : + // TODO: + // set crf or qp according to bitrate as bitrate is not supported by + // these encoders (yet) + if (info.video_bit_rate >= 1000) { + c->bit_rate = 0; + if (strstr(info.vcodec.c_str(), "aom") != NULL) { + int calculated_quality = 35; + if (info.video_bit_rate < 500000) calculated_quality = 50; + if (info.video_bit_rate > 5000000) calculated_quality = 10; + av_opt_set_int(c->priv_data, "crf", calculated_quality, 0); + info.video_bit_rate = calculated_quality; + } else { + int calculated_quality = 50; + if (info.video_bit_rate < 500000) calculated_quality = 60; + if (info.video_bit_rate > 5000000) calculated_quality = 15; + av_opt_set_int(c->priv_data, "qp", calculated_quality, 0); + info.video_bit_rate = calculated_quality; + } // medium + } + if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { + av_opt_set_int(c->priv_data, "preset", 6, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } + else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + av_opt_set_int(c->priv_data, "speed", 7, 0); + av_opt_set_int(c->priv_data, "tile-rows", 2, 0); + av_opt_set_int(c->priv_data, "tile-columns", 4, 0); + } + else if (strstr(info.vcodec.c_str(), "aom") != NULL) { + // Set number of tiles to a fixed value + // TODO Let user choose number of tiles + av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows + av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns + av_opt_set_int(c->priv_data, "row-mt", 1, 0); // use multiple cores + av_opt_set_int(c->priv_data, "cpu-used", 3, 0); // default is 1, usable is 4 + } + //break; #endif case AV_CODEC_ID_VP9 : case AV_CODEC_ID_HEVC : From 62d7fb54596219b993cf432d0a437de6e1fdb7a6 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 4 Jun 2020 18:52:19 -0500 Subject: [PATCH 070/100] Changing some libopenshot code based on Codacy feedback. Small refactoring, scope limiing. --- include/FFmpegWriter.h | 2 +- src/FFmpegWriter.cpp | 42 ++++++++++++------------------------------ 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 37fa22dc..b3bec7ad 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -253,7 +253,7 @@ namespace openshot { /// @brief Constructor for FFmpegWriter. Throws one of the following exceptions. /// @param path The file path of the video file you want to open and read - FFmpegWriter(std::string path); + FFmpegWriter(const std::string path); /// Close the writer void Close(); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e6a7e5ef..5b5c5410 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -83,7 +83,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 } #endif // HAVE_HW_ACCEL -FFmpegWriter::FFmpegWriter(std::string path) : +FFmpegWriter::FFmpegWriter(const std::string path) : path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32), @@ -864,9 +864,6 @@ void FFmpegWriter::flush_encoders() { return; #endif - int error_code = 0; - int stop_encoding = 1; - // FLUSH VIDEO ENCODER if (info.has_video) for (;;) { @@ -940,13 +937,9 @@ void FFmpegWriter::flush_encoders() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string) av_err2str(error_code) + "]", "error_code", error_code); } if (!got_packet) { - stop_encoding = 1; break; } - // Override PTS (in frames and scaled to the codec's timebase) - //pkt.pts = write_video_count; - // set the timestamp if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, video_codec->time_base, video_st->time_base); @@ -961,10 +954,6 @@ void FFmpegWriter::flush_encoders() { if (error_code < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code); } - - // Deallocate memory (if needed) - if (video_outbuf) - av_freep(&video_outbuf); } // FLUSH AUDIO ENCODER @@ -986,20 +975,15 @@ void FFmpegWriter::flush_encoders() { pkt.pts = pkt.dts = write_audio_count; /* encode the image */ - int got_packet = 0; + int error_code = 0; #if IS_FFMPEG_3_2 - avcodec_send_frame(audio_codec, NULL); - got_packet = 0; + error_code = avcodec_send_frame(audio_codec, NULL); #else error_code = avcodec_encode_audio2(audio_codec, &pkt, NULL, &got_packet); #endif if (error_code < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code); } - if (!got_packet) { - stop_encoding = 1; - break; - } // Since the PTS can change during encoding, set the value again. This seems like a huge hack, // but it fixes lots of PTS related issues when I do this. @@ -1583,29 +1567,27 @@ void FFmpegWriter::write_audio_packets(bool is_final) { channels_in_frame = frame->GetAudioChannelsCount(); channel_layout_in_frame = frame->ChannelsLayout(); - // Get audio sample array float *frame_samples_float = NULL; // Get samples interleaved together (c1 c2 c1 c2 c1 c2) frame_samples_float = frame->GetInterleavedAudioSamples(sample_rate_in_frame, NULL, &samples_in_frame); - // Calculate total samples total_frame_samples = samples_in_frame * channels_in_frame; // Translate audio sample values back to 16 bit integers with saturation - float valF; - int16_t conv; const int16_t max16 = 32767; const int16_t min16 = -32768; for (int s = 0; s < total_frame_samples; s++, frame_position++) { - valF = frame_samples_float[s] * (1 << 15); - if (valF > max16) + float valF = frame_samples_float[s] * (1 << 15); + int16_t conv; + if (valF > max16) { conv = max16; - else if (valF < min16) + } else if (valF < min16) { conv = min16; - else + } else { conv = int(valF + 32768.5) - 32768; // +0.5 is for rounding + } // Copy into buffer all_queued_samples[frame_position] = conv; @@ -1731,10 +1713,11 @@ void FFmpegWriter::write_audio_packets(bool is_final) { // Determine how many samples we need int diff = 0; - if (remaining_frame_samples >= remaining_packet_samples) + if (remaining_frame_samples >= remaining_packet_samples) { diff = remaining_packet_samples; - else if (remaining_frame_samples < remaining_packet_samples) + } else { diff = remaining_frame_samples; + } // Copy frame samples into the packet samples array if (!is_final) @@ -1746,7 +1729,6 @@ void FFmpegWriter::write_audio_packets(bool is_final) { audio_input_position += diff; samples_position += diff * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)); remaining_frame_samples -= diff; - remaining_packet_samples -= diff; // Do we have enough samples to proceed? if (audio_input_position < (audio_input_frame_size * info.channels) && !is_final) From 86b83abf5d74f65c67ed6e8c3b5869110e66b43e Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 5 Jun 2020 15:41:23 -0500 Subject: [PATCH 071/100] Fixing undefined got_packet int --- src/FFmpegWriter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 5b5c5410..7eb24156 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -976,6 +976,7 @@ void FFmpegWriter::flush_encoders() { /* encode the image */ int error_code = 0; + int got_packet = 0; #if IS_FFMPEG_3_2 error_code = avcodec_send_frame(audio_codec, NULL); #else From 51fe8549e6364e8d685dd4e5c3a1f5de2fda50d3 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 5 Jun 2020 17:53:21 -0500 Subject: [PATCH 072/100] Fix regression caused by Codacy tweaks --- src/FFmpegWriter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 7eb24156..5a21c6ba 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -985,6 +985,9 @@ void FFmpegWriter::flush_encoders() { if (error_code < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code); } + if (!got_packet) { + break; + } // Since the PTS can change during encoding, set the value again. This seems like a huge hack, // but it fixes lots of PTS related issues when I do this. From 7b94ac838b76f1211ed3c14183fdd15deb354b04 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 5 Jun 2020 18:07:25 -0500 Subject: [PATCH 073/100] Removing bad suggestion. In theory, we could change this signature to take a const reference to a string, but for now, I'm reverting it. --- include/FFmpegWriter.h | 2 +- src/FFmpegWriter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index b3bec7ad..37fa22dc 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -253,7 +253,7 @@ namespace openshot { /// @brief Constructor for FFmpegWriter. Throws one of the following exceptions. /// @param path The file path of the video file you want to open and read - FFmpegWriter(const std::string path); + FFmpegWriter(std::string path); /// Close the writer void Close(); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 5a21c6ba..e3dedb28 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -83,7 +83,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 } #endif // HAVE_HW_ACCEL -FFmpegWriter::FFmpegWriter(const std::string path) : +FFmpegWriter::FFmpegWriter(std::string path) : path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32), From 7831cfe9128502ae894d85c14e033991cd9a3d1b Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 6 Jun 2020 01:55:52 -0500 Subject: [PATCH 074/100] Adding some new functionality and documentation to DummyReader. Adding the ability to add test frames, with fake image and audio data. This will can be used in unittests, and will soon be used to verify some new audio improvements (coming soon). --- include/DummyReader.h | 50 +++++++++++++++++- src/DummyReader.cpp | 31 +++++++++-- src/Frame.cpp | 5 ++ tests/CMakeLists.txt | 1 + tests/DummyReader_Tests.cpp | 102 ++++++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 tests/DummyReader_Tests.cpp diff --git a/include/DummyReader.h b/include/DummyReader.h index 4c935103..576a0df8 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -46,14 +46,58 @@ namespace openshot { /** - * @brief This class is used as a simple, dummy reader, which always returns a blank frame. + * @brief This class is used as a simple, dummy reader, which can be very useful when writing + * unit tests. It can return a single blank frame or it can return custom frame objects + * which were added using the WriteFrame() method. * * A dummy reader can be created with any framerate or samplerate. This is useful in unit * tests that need to test different framerates or samplerates. + * + * @code + * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration) + * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + * r.Open(); // Open the reader + * + * // Get a frame (which will be blank, since we haven't added any frames yet) + * std::shared_ptr f = r.GetFrame(1); + * + * // Now let's create some test frames + * for (int64_t frame_number = 1; frame_number <= 30; frame_number++) + * { + * // Create blank frame (with specific frame #, samples, and channels) + * // Sample count should be 44100 / 30 fps = 1470 samples per frame + * int sample_count = 1470; + * std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2)); + * + * // Create test samples with incrementing value + * float *audio_buffer = new float[sample_count]; + * for (int64_t sample_number = 0; sample_number < sample_count; sample_number++) + * { + * // Generate an incrementing audio sample value (just as an example) + * audio_buffer[sample_number] = float(frame_number) + (float(sample_number) / float(sample_count)); + * } + * + * // Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source, + * // int numSamples, float gainToApplyToSource = 1.0f) + * f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1 + * f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2 + * + * // Write test frame to dummy reader + * r.WriteFrame(f); + * } + * + * // Now let's verify our DummyReader works + * std::shared_ptr f = r.GetFrame(1); + * // r.GetFrame(1)->GetAudioSamples(0)[1] should equal 1.00068033 based on our above calculations + * + * // Close the reader + * r.Close(); + * @endcode */ class DummyReader : public ReaderBase { private: + CacheMemory dummy_cache; std::shared_ptr image_frame; bool is_open; @@ -94,6 +138,10 @@ namespace openshot /// Open File - which is called by the constructor automatically void Open() override; + + /// @brief Add a frame to the dummy reader. This is useful when constructing unit tests that require custom frames. + /// @param frame The openshot::Frame object to write to this image + void WriteFrame(std::shared_ptr frame); }; } diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 8fd98bcb..1b663a07 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -99,24 +99,49 @@ void DummyReader::Close() { // Mark as "closed" is_open = false; + + // Clear cache + dummy_cache.Clear(); } } -// Get an openshot::Frame object for a specific frame number of this reader. +// Add Frame objects to DummyReader +void DummyReader::WriteFrame(std::shared_ptr frame) +{ + if (frame) { + dummy_cache.Add(frame); + } +} + +// Get an openshot::Frame object for a specific frame number of this reader. It is either a blank frame +// or a custom frame added with the WriteFrame() method. std::shared_ptr DummyReader::GetFrame(int64_t requested_frame) { // Check for open reader (or throw exception) if (!is_open) throw ReaderClosed("The ImageReader is closed. Call Open() before calling this method.", "dummy"); - if (image_frame) - { + if (dummy_cache.Count() == 0 && image_frame) { // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(getFrameCriticalSection); // Always return same frame (regardless of which frame number was requested) image_frame->number = requested_frame; return image_frame; + + } else if (dummy_cache.Count() > 0) { + // Create a scoped lock, allowing only a single thread to run the following code at one time + const GenericScopedLock lock(getFrameCriticalSection); + + // Get a frame from the dummy cache + std::shared_ptr f = dummy_cache.GetFrame(requested_frame); + if (f) { + // return frame from cache (if found) + return f; + } else { + // No cached frame found + throw InvalidFile("Requested frame not found. You can only access Frame numbers added with WriteFrame().", "dummy"); + } } else // no frame loaded diff --git a/src/Frame.cpp b/src/Frame.cpp index ae9f1a4b..764b9651 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -480,6 +480,11 @@ const unsigned char* Frame::GetPixels() // Get pixel data (for only a single scan-line) const unsigned char* Frame::GetPixels(int row) { + // Check for blank image + if (!image) + // Fill with black + AddColor(width, height, color); + // Return array of pixel packets return image->constScanLine(row); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 480dfb3d..7ccddba8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -109,6 +109,7 @@ set(OPENSHOT_TEST_FILES Clip_Tests.cpp Color_Tests.cpp Coordinate_Tests.cpp + DummyReader_Tests.cpp ReaderBase_Tests.cpp ImageWriter_Tests.cpp FFmpegReader_Tests.cpp diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp new file mode 100644 index 00000000..ea410ad0 --- /dev/null +++ b/tests/DummyReader_Tests.cpp @@ -0,0 +1,102 @@ +/** + * @file + * @brief Unit tests for openshot::DummyReader + * @author Jonathan Thomas + * + * @ref License + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenShot Library. If not, see . + */ + +#include "UnitTest++.h" +// Prevent name clashes with juce::UnitTest +#define DONT_SET_USING_JUCE_NAMESPACE 1 + +#include "../include/OpenShot.h" + +using namespace std; +using namespace openshot; + +TEST (DummyReader_Constructor) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + r.Open(); // Open the reader + + // Check values + CHECK_EQUAL(1920, r.info.width); + CHECK_EQUAL(1080, r.info.height); + CHECK_EQUAL(30, r.info.fps.num); + CHECK_EQUAL(1, r.info.fps.den); + CHECK_EQUAL(44100, r.info.sample_rate); + CHECK_EQUAL(2, r.info.channels); + CHECK_EQUAL(30.0, r.info.duration); +} + +TEST (DummyReader_Blank_Frame) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + r.Open(); // Open the reader + + // Get a blank frame (because we have not added any frames using WriteFrame() yet) + // Check values + CHECK_EQUAL(1, r.GetFrame(1)->number); + CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(700)[700] == 0); // black pixel + CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(701)[701] == 0); // black pixel +} + +TEST (DummyReader_Fake_Frame) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + r.Open(); // Open the reader + + // Let's create some test frames + for (int64_t frame_number = 1; frame_number <= 30; frame_number++) { + // Create blank frame (with specific frame #, samples, and channels) + // Sample count should be 44100 / 30 fps = 1470 samples per frame + int sample_count = 1470; + std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2)); + + // Create test samples with incrementing value + float *audio_buffer = new float[sample_count]; + for (int64_t sample_number = 0; sample_number < sample_count; sample_number++) { + // Generate an incrementing audio sample value (just as an example) + audio_buffer[sample_number] = float(frame_number) + (float(sample_number) / float(sample_count)); + } + + // Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source, + f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1 + f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2 + + // Write test frame to dummy reader + r.WriteFrame(f); + } + + // Verify our artificial audio sample data is correct + CHECK_EQUAL(1, r.GetFrame(1)->number); + CHECK_EQUAL(1, r.GetFrame(1)->GetAudioSamples(0)[0]); + CHECK_CLOSE(1.00068033, r.GetFrame(1)->GetAudioSamples(0)[1], 0.00001); + CHECK_CLOSE(1.00136054, r.GetFrame(1)->GetAudioSamples(0)[2], 0.00001); + CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]); + CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001); + CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001); +} \ No newline at end of file From d29027ae30466f3aeb6ec0b78cc28754d7630174 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 6 Jun 2020 02:03:27 -0500 Subject: [PATCH 075/100] Added an additional unittest for DummyReader (for invalid frame) --- tests/DummyReader_Tests.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp index ea410ad0..6ec11e08 100644 --- a/tests/DummyReader_Tests.cpp +++ b/tests/DummyReader_Tests.cpp @@ -99,4 +99,23 @@ TEST (DummyReader_Fake_Frame) { CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]); CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001); CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001); +} + +TEST (DummyReader_Invalid_Fake_Frame) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + r.Open(); + + // Create fake frames (with specific frame #, samples, and channels) + std::shared_ptr f1(new openshot::Frame(1, 1470, 2)); + std::shared_ptr f2(new openshot::Frame(2, 1470, 2)); + + // Write test frames to dummy reader + r.WriteFrame(f1); + r.WriteFrame(f2); + + // Verify exception + CHECK_EQUAL(1, r.GetFrame(1)->number); + CHECK_EQUAL(2, r.GetFrame(2)->number); + CHECK_THROW(r.GetFrame(3)->number, InvalidFile); } \ No newline at end of file From 8b12c1fa2173db24246858e744118da544d7e320 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 6 Jun 2020 17:25:45 -0500 Subject: [PATCH 076/100] Replacing WriteFrame() method with custom constructor which can accept a CacheBase* pointer, for instances where a DummyReader needs some specific test Frame objects --- include/DummyReader.h | 33 ++++++++++--------- src/DummyReader.cpp | 64 ++++++++++++++++++++----------------- tests/DummyReader_Tests.cpp | 58 ++++++++++++++++++++++++--------- 3 files changed, 96 insertions(+), 59 deletions(-) diff --git a/include/DummyReader.h b/include/DummyReader.h index 576a0df8..e9c90968 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -48,18 +48,14 @@ namespace openshot /** * @brief This class is used as a simple, dummy reader, which can be very useful when writing * unit tests. It can return a single blank frame or it can return custom frame objects - * which were added using the WriteFrame() method. + * which were passed into the constructor with a Cache object. * * A dummy reader can be created with any framerate or samplerate. This is useful in unit * tests that need to test different framerates or samplerates. * * @code - * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration) - * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); - * r.Open(); // Open the reader - * - * // Get a frame (which will be blank, since we haven't added any frames yet) - * std::shared_ptr f = r.GetFrame(1); + * // Create cache object to store fake Frame objects + * CacheMemory cache; * * // Now let's create some test frames * for (int64_t frame_number = 1; frame_number <= 30; frame_number++) @@ -82,25 +78,33 @@ namespace openshot * f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1 * f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2 * - * // Write test frame to dummy reader - * r.WriteFrame(f); + * // Add test frame to cache + * cache.Add(f); * } * + * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache) + * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache); + * r.Open(); // Open the reader + * * // Now let's verify our DummyReader works * std::shared_ptr f = r.GetFrame(1); * // r.GetFrame(1)->GetAudioSamples(0)[1] should equal 1.00068033 based on our above calculations * - * // Close the reader + * // Clean up * r.Close(); + * cache.Clear() * @endcode */ class DummyReader : public ReaderBase { private: - CacheMemory dummy_cache; + CacheBase* dummy_cache; std::shared_ptr image_frame; bool is_open; + /// Initialize variables used by constructor + void init(Fraction fps, int width, int height, int sample_rate, int channels, float duration); + public: /// Blank constructor for DummyReader, with default settings. @@ -109,6 +113,9 @@ namespace openshot /// Constructor for DummyReader. DummyReader(openshot::Fraction fps, int width, int height, int sample_rate, int channels, float duration); + /// Constructor for DummyReader which takes a frame cache object. + DummyReader(openshot::Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache); + virtual ~DummyReader(); /// Close File @@ -138,10 +145,6 @@ namespace openshot /// Open File - which is called by the constructor automatically void Open() override; - - /// @brief Add a frame to the dummy reader. This is useful when constructing unit tests that require custom frames. - /// @param frame The openshot::Frame object to write to this image - void WriteFrame(std::shared_ptr frame); }; } diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 1b663a07..8b6f752f 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -32,16 +32,8 @@ using namespace openshot; -// Blank constructor for DummyReader, with default settings. -DummyReader::DummyReader() { - - // Call actual constructor with default values - DummyReader(Fraction(24,1), 1280, 768, 44100, 2, 30.0); -} - -// Constructor for DummyReader. Pass a framerate and samplerate. -DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration) { - +// Initialize variables used by constructor +void DummyReader::init(Fraction fps, int width, int height, int sample_rate, int channels, float duration) { // Set key info settings info.has_audio = false; info.has_video = true; @@ -68,10 +60,30 @@ DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, i // Set the ratio based on the reduced fraction info.display_ratio.num = size.num; info.display_ratio.den = size.den; +} - // Open and Close the reader, to populate its attributes (such as height, width, etc...) - Open(); - Close(); +// Blank constructor for DummyReader, with default settings. +DummyReader::DummyReader() : dummy_cache(NULL), is_open(false) { + + // Initialize important variables + init(Fraction(24,1), 1280, 768, 44100, 2, 30.0); +} + +// Constructor for DummyReader. Pass a framerate and samplerate. +DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration) : dummy_cache(NULL), is_open(false) { + + // Initialize important variables + init(fps, width, height, sample_rate, channels, duration); +} + +// Constructor which also takes a cache object +DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache) : is_open(false) { + + // Initialize important variables + init(fps, width, height, sample_rate, channels, duration); + + // Set cache object + dummy_cache = (CacheBase*) cache; } DummyReader::~DummyReader() { @@ -99,29 +111,23 @@ void DummyReader::Close() { // Mark as "closed" is_open = false; - - // Clear cache - dummy_cache.Clear(); - } -} - -// Add Frame objects to DummyReader -void DummyReader::WriteFrame(std::shared_ptr frame) -{ - if (frame) { - dummy_cache.Add(frame); } } // Get an openshot::Frame object for a specific frame number of this reader. It is either a blank frame -// or a custom frame added with the WriteFrame() method. +// or a custom frame added with passing a Cache object to the constructor. std::shared_ptr DummyReader::GetFrame(int64_t requested_frame) { // Check for open reader (or throw exception) if (!is_open) throw ReaderClosed("The ImageReader is closed. Call Open() before calling this method.", "dummy"); - if (dummy_cache.Count() == 0 && image_frame) { + int dummy_cache_count = 0; + if (dummy_cache) { + dummy_cache_count = dummy_cache->Count(); + } + + if (dummy_cache_count == 0 && image_frame) { // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(getFrameCriticalSection); @@ -129,18 +135,18 @@ std::shared_ptr DummyReader::GetFrame(int64_t requested_frame) image_frame->number = requested_frame; return image_frame; - } else if (dummy_cache.Count() > 0) { + } else if (dummy_cache_count > 0) { // Create a scoped lock, allowing only a single thread to run the following code at one time const GenericScopedLock lock(getFrameCriticalSection); // Get a frame from the dummy cache - std::shared_ptr f = dummy_cache.GetFrame(requested_frame); + std::shared_ptr f = dummy_cache->GetFrame(requested_frame); if (f) { // return frame from cache (if found) return f; } else { // No cached frame found - throw InvalidFile("Requested frame not found. You can only access Frame numbers added with WriteFrame().", "dummy"); + throw InvalidFile("Requested frame not found. You can only access Frame numbers that exist in the Cache object.", "dummy"); } } else diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp index 6ec11e08..c72be2d9 100644 --- a/tests/DummyReader_Tests.cpp +++ b/tests/DummyReader_Tests.cpp @@ -37,9 +37,24 @@ using namespace std; using namespace openshot; +TEST (DummyReader_Basic_Constructor) { + // Create a default fraction (should be 1/1) + openshot::DummyReader r; + r.Open(); // Open the reader + + // Check values + CHECK_EQUAL(1280, r.info.width); + CHECK_EQUAL(768, r.info.height); + CHECK_EQUAL(24, r.info.fps.num); + CHECK_EQUAL(1, r.info.fps.den); + CHECK_EQUAL(44100, r.info.sample_rate); + CHECK_EQUAL(2, r.info.channels); + CHECK_EQUAL(30.0, r.info.duration); +} + TEST (DummyReader_Constructor) { // Create a default fraction (should be 1/1) - openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 60.0); r.Open(); // Open the reader // Check values @@ -49,7 +64,7 @@ TEST (DummyReader_Constructor) { CHECK_EQUAL(1, r.info.fps.den); CHECK_EQUAL(44100, r.info.sample_rate); CHECK_EQUAL(2, r.info.channels); - CHECK_EQUAL(30.0, r.info.duration); + CHECK_EQUAL(60.0, r.info.duration); } TEST (DummyReader_Blank_Frame) { @@ -57,7 +72,7 @@ TEST (DummyReader_Blank_Frame) { openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); r.Open(); // Open the reader - // Get a blank frame (because we have not added any frames using WriteFrame() yet) + // Get a blank frame (because we have not passed a Cache object (full of Frame objects) to the constructor // Check values CHECK_EQUAL(1, r.GetFrame(1)->number); CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(700)[700] == 0); // black pixel @@ -65,9 +80,9 @@ TEST (DummyReader_Blank_Frame) { } TEST (DummyReader_Fake_Frame) { - // Create a default fraction (should be 1/1) - openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); - r.Open(); // Open the reader + + // Create cache object to hold test frames + CacheMemory cache; // Let's create some test frames for (int64_t frame_number = 1; frame_number <= 30; frame_number++) { @@ -87,10 +102,14 @@ TEST (DummyReader_Fake_Frame) { f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1 f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2 - // Write test frame to dummy reader - r.WriteFrame(f); + // Add test frame to dummy reader + cache.Add(f); } + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache); + r.Open(); // Open the reader + // Verify our artificial audio sample data is correct CHECK_EQUAL(1, r.GetFrame(1)->number); CHECK_EQUAL(1, r.GetFrame(1)->GetAudioSamples(0)[0]); @@ -99,23 +118,32 @@ TEST (DummyReader_Fake_Frame) { CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]); CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001); CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001); + + // Clean up + cache.Clear(); + r.Close(); } TEST (DummyReader_Invalid_Fake_Frame) { - // Create a default fraction (should be 1/1) - openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0); - r.Open(); - // Create fake frames (with specific frame #, samples, and channels) std::shared_ptr f1(new openshot::Frame(1, 1470, 2)); std::shared_ptr f2(new openshot::Frame(2, 1470, 2)); - // Write test frames to dummy reader - r.WriteFrame(f1); - r.WriteFrame(f2); + // Add test frames to cache object + CacheMemory cache; + cache.Add(f1); + cache.Add(f2); + + // Create a default fraction (should be 1/1) + openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache); + r.Open(); // Verify exception CHECK_EQUAL(1, r.GetFrame(1)->number); CHECK_EQUAL(2, r.GetFrame(2)->number); CHECK_THROW(r.GetFrame(3)->number, InvalidFile); + + // Clean up + cache.Clear(); + r.Close(); } \ No newline at end of file From 8af624fc4ef40e188571809b4be00c2669581049 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 11 Jun 2020 17:40:53 -0400 Subject: [PATCH 077/100] Add an APPIMAGE_BUILD option to libopenshot - Defaults OFF, must be enabled during build generation - Set (cmake -DAPPIMAGE_BUILD=1) by GitLab linux builder - Stored as a symbol in the library (via OpenShotVersion.h #defines) - Also visible in Python module (`if openshot.APPIMAGE_BUILD: pass`) Also, use CMAKE_SWIG_FLAGS properly (as a list), fix some indentation --- .gitlab-ci.yml | 2 +- CMakeLists.txt | 1 + include/OpenShotVersion.h.in | 1 + src/CMakeLists.txt | 78 ++++++++++++++++++------------------ tests/CMakeLists.txt | 1 - 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 925bf020..d690b8e1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ linux-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -DCMAKE_BUILD_TYPE:STRING=Release -DUSE_SYSTEM_JSONCPP=0 ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"PYTHON_MODULE_PATH=python" -D"RUBY_MODULE_PATH=ruby" -DCMAKE_BUILD_TYPE:STRING=Release -DAPPIMAGE_BUILD=1 -DUSE_SYSTEM_JSONCPP=0 ../ - make - make install - make doc diff --git a/CMakeLists.txt b/CMakeLists.txt index f50c575f..94b09879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ option(DISABLE_BUNDLED_JSONCPP "Don't fall back to bundled JsonCpp" OFF) option(ENABLE_IWYU "Enable 'Include What You Use' scanner (CMake 3.3+)" OFF) option(ENABLE_TESTS "Build unit tests (requires UnitTest++)" ON) option(ENABLE_DOCS "Build API documentation (requires Doxygen)" ON) +option(APPIMAGE_BUILD "Build to install in an AppImage (Linux only)" OFF) # Legacy commandline override if (DISABLE_TESTS) diff --git a/include/OpenShotVersion.h.in b/include/OpenShotVersion.h.in index d0b015a4..5e86e8ce 100644 --- a/include/OpenShotVersion.h.in +++ b/include/OpenShotVersion.h.in @@ -49,6 +49,7 @@ #cmakedefine AVUTIL_VERSION_STR "@AVUTIL_VERSION_STR@" #cmakedefine01 HAVE_IMAGEMAGICK #cmakedefine01 HAVE_RESVG +#cmakedefine01 APPIMAGE_BUILD #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90c74ead..61892668 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,8 +33,8 @@ include(GNUInstallDirs) # Set some compiler options for Windows # required for libopenshot-audio headers if (WIN32) - add_definitions( -DIGNORE_JUCE_HYPOT=1 ) - set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath") + add_definitions( -DIGNORE_JUCE_HYPOT=1 ) + set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath") endif() if (APPLE) @@ -50,28 +50,28 @@ endif() ################ IMAGE MAGICK ################## # Set the Quantum Depth that ImageMagick was built with (default to 16 bits) IF (MAGICKCORE_QUANTUM_DEPTH) - add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=${MAGICKCORE_QUANTUM_DEPTH} ) + add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=${MAGICKCORE_QUANTUM_DEPTH} ) ELSE (MAGICKCORE_QUANTUM_DEPTH) - add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 ) + add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 ) ENDIF (MAGICKCORE_QUANTUM_DEPTH) IF (MAGICKCORE_HDRI_ENABLE) - add_definitions( -DMAGICKCORE_HDRI_ENABLE=${MAGICKCORE_HDRI_ENABLE} ) + add_definitions( -DMAGICKCORE_HDRI_ENABLE=${MAGICKCORE_HDRI_ENABLE} ) ELSE (MAGICKCORE_HDRI_ENABLE) - add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 ) + add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 ) ENDIF (MAGICKCORE_HDRI_ENABLE) # Find the ImageMagick++ library find_package(ImageMagick COMPONENTS Magick++ MagickWand MagickCore) if (ImageMagick_FOUND) - # Include ImageMagick++ headers (needed for compile) - include_directories(${ImageMagick_INCLUDE_DIRS}) + # Include ImageMagick++ headers (needed for compile) + include_directories(${ImageMagick_INCLUDE_DIRS}) - # define a global var (used in the C++) - add_definitions( -DUSE_IMAGEMAGICK=1 ) - set(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") + # define a global var (used in the C++) + add_definitions( -DUSE_IMAGEMAGICK=1 ) + list(APPEND CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") - set(HAVE_IMAGEMAGICK TRUE CACHE BOOL "Building with ImageMagick support" FORCE) - mark_as_advanced(HAVE_IMAGEMAGICK) + set(HAVE_IMAGEMAGICK TRUE CACHE BOOL "Building with ImageMagick support" FORCE) + mark_as_advanced(HAVE_IMAGEMAGICK) endif() ################# LIBOPENSHOT-AUDIO ################### @@ -85,15 +85,15 @@ include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) # Find BlackMagic DeckLinkAPI libraries if (ENABLE_BLACKMAGIC) - find_package(BlackMagic) + find_package(BlackMagic) - if (BLACKMAGIC_FOUND) - # Include Blackmagic headers (needed for compile) - include_directories(${BLACKMAGIC_INCLUDE_DIR}) + if (BLACKMAGIC_FOUND) + # Include Blackmagic headers (needed for compile) + include_directories(${BLACKMAGIC_INCLUDE_DIR}) - # define a global var (used in the C++) - add_definitions( -DUSE_BLACKMAGIC=1 ) - set(CMAKE_SWIG_FLAGS "-DUSE_BLACKMAGIC=1") + # define a global var (used in the C++) + add_definitions( -DUSE_BLACKMAGIC=1 ) + list(APPEND CMAKE_SWIG_FLAGS "-DUSE_BLACKMAGIC=1") endif() endif() @@ -148,7 +148,7 @@ set(OPENSHOT_SOURCES Fraction.cpp Frame.cpp FrameMapper.cpp - Json.cpp + Json.cpp KeyFrame.cpp OpenShotVersion.cpp ZmqLogger.cpp @@ -216,7 +216,7 @@ set_target_properties(openshot PROPERTIES # Add optional ImageMagic-dependent sources if(ImageMagick_FOUND) - target_sources(openshot PRIVATE + target_sources(openshot PRIVATE ImageReader.cpp ImageWriter.cpp TextReader.cpp) @@ -245,7 +245,7 @@ target_include_directories(openshot ################### JSONCPP ##################### # Include jsoncpp headers (needed for JSON parsing) if (USE_SYSTEM_JSONCPP) - message(STATUS "Looking for system jsoncpp") + message(STATUS "Looking for system jsoncpp") # Either an installed config or our find module will # create the IMPORTED target jsoncpp_lib if successful find_package(jsoncpp) @@ -344,7 +344,7 @@ find_package(cppzmq QUIET) # Creates cppzmq target # Link ZeroMQ library if (TARGET libzmq) - target_link_libraries(openshot PUBLIC libzmq) + target_link_libraries(openshot PUBLIC libzmq) endif() # Include cppzmq headers, if not bundled into libzmq if (TARGET cppzmq) @@ -361,7 +361,7 @@ if(DEFINED ENV{RESVGDIR} AND NOT DEFINED RESVG_ROOT) endif() # Find resvg library (used for rendering svg files) -FIND_PACKAGE(RESVG) +find_package(RESVG) # Include resvg headers (optional SVG library) if (TARGET RESVG::resvg) @@ -369,7 +369,7 @@ if (TARGET RESVG::resvg) target_link_libraries(openshot PUBLIC RESVG::resvg) target_compile_definitions(openshot PUBLIC "-DUSE_RESVG=1") - set(CMAKE_SWIG_FLAGS "-DUSE_RESVG=1") + list(APPEND CMAKE_SWIG_FLAGS "-DUSE_RESVG=1") set(HAVE_RESVG TRUE CACHE BOOL "Building with Resvg support" FORCE) mark_as_advanced(HAVE_RESVG) @@ -379,7 +379,7 @@ endif() ############### LINK LIBRARY ################# # Link remaining dependency libraries target_link_libraries(openshot PUBLIC - ${LIBOPENSHOT_AUDIO_LIBRARIES} + ${LIBOPENSHOT_AUDIO_LIBRARIES} ${PROFILER}) if(ImageMagick_FOUND) @@ -391,8 +391,8 @@ if(BLACKMAGIC_FOUND) endif() if(WIN32) - # Required for exception handling on Windows - target_link_libraries(openshot PUBLIC "imagehlp" "dbghelp" ) + # Required for exception handling on Windows + target_link_libraries(openshot PUBLIC "imagehlp" "dbghelp" ) endif() @@ -401,9 +401,9 @@ endif() add_executable(openshot-example examples/Example.cpp) # Define path to test input files -SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") +set(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") if (WIN32) - STRING(REPLACE "/" "\\\\" TEST_MEDIA_PATH TEST_MEDIA_PATH) + string(REPLACE "/" "\\\\" TEST_MEDIA_PATH TEST_MEDIA_PATH) endif() target_compile_definitions(openshot-example PRIVATE -DTEST_MEDIA_PATH="${TEST_MEDIA_PATH}" ) @@ -423,12 +423,12 @@ target_link_libraries(openshot-player openshot) ############### TEST BLACKMAGIC CAPTURE APP ################ if (BLACKMAGIC_FOUND) - # Create test executable - add_executable(openshot-blackmagic - examples/ExampleBlackmagic.cpp) + # Create test executable + add_executable(openshot-blackmagic + examples/ExampleBlackmagic.cpp) - # Link test executable to the new library - target_link_libraries(openshot-blackmagic openshot) + # Link test executable to the new library + target_link_libraries(openshot-blackmagic openshot) endif() ############### INCLUDE SWIG BINDINGS ################ @@ -448,13 +448,13 @@ install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ ############### CPACK PACKAGING ############## if(MINGW) - set(CPACK_GENERATOR "NSIS") + set(CPACK_GENERATOR "NSIS") endif() if(UNIX AND NOT APPLE) - set(CPACK_GENERATOR "DEB") + set(CPACK_GENERATOR "DEB") endif() #if(UNIX AND APPLE) -# set(CPACK_GENERATOR "DragNDrop") +# set(CPACK_GENERATOR "DragNDrop") #endif() set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Jonathan Thomas") #required diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7ccddba8..53b4cace 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -80,7 +80,6 @@ if(ImageMagick_FOUND) # define a global var (used in the C++) add_definitions( -DUSE_IMAGEMAGICK=1 ) - set(CMAKE_SWIG_FLAGS "-DUSE_IMAGEMAGICK=1") endif() ################# LIBOPENSHOT-AUDIO ################### From bec21b1c7719e50d2a0e97f4fee83997cfa8f2f5 Mon Sep 17 00:00:00 2001 From: Daniel Jour Date: Fri, 12 Jun 2020 22:30:54 +0200 Subject: [PATCH 078/100] Add a note about the buffering behavior of Timeline to DummyReader Using DummyReader with a custom cache with a Timeline can lead to strange exceptions due to Timeline's buffering. Therefore adding a note to the DummyReader documentation about that. --- include/DummyReader.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/DummyReader.h b/include/DummyReader.h index e9c90968..9a75751d 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -53,6 +53,12 @@ namespace openshot * A dummy reader can be created with any framerate or samplerate. This is useful in unit * tests that need to test different framerates or samplerates. * + * @note Timeline does buffering by requesting more frames than it + * strictly needs. Thus if you use this DummyReader with a custom + * cache in a Timeline, make sure it has enough + * frames. Specifically you need some frames after the last frame + * you plan to access through the Timeline. + * * @code * // Create cache object to store fake Frame objects * CacheMemory cache; From 4e2c08db88f30a195836998aa62f05b7713c819f Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:02:26 -0700 Subject: [PATCH 079/100] Update src/FFmpegWriter.cpp Thanks for fixing that Co-authored-by: Jonathan Thomas --- src/FFmpegWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 9b348aed..058b7490 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1254,7 +1254,7 @@ AVStream *FFmpegWriter::add_video_stream() { } else if (strstr(info.vcodec.c_str(), "aom") != NULL) { // Set number of tiles to a fixed value - // TODO Let user choose number of tiles + // TODO: Allow user to chose their own number of tiles av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns av_opt_set_int(c->priv_data, "row-mt", 1, 0); // use multiple cores From 91647e6d0b702fecec9e653ef342a220aa6d9935 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:03:29 -0700 Subject: [PATCH 080/100] Update src/FFmpegWriter.cpp Perfect. I forgot that comment. Co-authored-by: Jonathan Thomas --- src/FFmpegWriter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 058b7490..831db284 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -478,6 +478,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : c->bit_rate = 0; + // AV1 only supports "crf" quality values av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); break; #endif From 2491d402df29ab7a91820acc6239f5477346b12a Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:04:49 -0700 Subject: [PATCH 081/100] Update src/FFmpegWriter.cpp I should take more care of the comments. Co-authored-by: Jonathan Thomas --- src/FFmpegWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 831db284..7ad2eb17 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1225,7 +1225,7 @@ AVStream *FFmpegWriter::add_video_stream() { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : - // TODO: + // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. // set crf or qp according to bitrate as bitrate is not supported by // these encoders (yet) if (info.video_bit_rate >= 1000) { From bf0e700ae7ffb0370cc3f7721cb2e9a18c36c5b6 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:05:43 -0700 Subject: [PATCH 082/100] Update src/FFmpegWriter.cpp Co-authored-by: Jonathan Thomas --- src/FFmpegWriter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 7ad2eb17..c35edcb4 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1226,7 +1226,6 @@ AVStream *FFmpegWriter::add_video_stream() { #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. - // set crf or qp according to bitrate as bitrate is not supported by // these encoders (yet) if (info.video_bit_rate >= 1000) { c->bit_rate = 0; From c037d5c01df664bb41e22a00571a900c1512fa76 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:07:09 -0700 Subject: [PATCH 083/100] Update src/FFmpegWriter.cpp We might want to leave some kind of comment though. The encoders will (probably) get these options (soon). Co-authored-by: Jonathan Thomas --- src/FFmpegWriter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index c35edcb4..291ba848 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1226,7 +1226,6 @@ AVStream *FFmpegWriter::add_video_stream() { #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. - // these encoders (yet) if (info.video_bit_rate >= 1000) { c->bit_rate = 0; if (strstr(info.vcodec.c_str(), "aom") != NULL) { From 3dfcea1dd527d63b1c93dd0251a0723f4f88e4b5 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:33:14 -0700 Subject: [PATCH 084/100] Fix indentation --- src/FFmpegWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 291ba848..cb1c326d 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1225,7 +1225,7 @@ AVStream *FFmpegWriter::add_video_stream() { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : - // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. + // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. if (info.video_bit_rate >= 1000) { c->bit_rate = 0; if (strstr(info.vcodec.c_str(), "aom") != NULL) { From 056a72fa17fadaa7a263ffbfa0100b02dc210de8 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:41:38 -0700 Subject: [PATCH 085/100] Fix indentation (2) --- src/FFmpegWriter.cpp | 76 ++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index cb1c326d..741f2f26 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -542,12 +542,12 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va } else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { // Set number of tiles to a fixed value - // TODO Let user choose number of tiles + // TODO Let user choose number of tiles av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0); } else if (strstr(info.vcodec.c_str(), "aom") != NULL) { // Set number of tiles to a fixed value - // TODO Let user choose number of tiles + // TODO Let user choose number of tiles // libaom doesn't have qp only crf av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0); } @@ -1207,10 +1207,10 @@ AVStream *FFmpegWriter::add_video_stream() { #endif /* Init video encoder options */ - if (info.video_bit_rate >= 1000 + if (info.video_bit_rate >= 1000 #if (LIBAVCODEC_VERSION_MAJOR >= 58) && c->codec_id != AV_CODEC_ID_AV1 -#endif +#endif ) { c->bit_rate = info.video_bit_rate; if (info.video_bit_rate >= 1500000) { @@ -1226,40 +1226,40 @@ AVStream *FFmpegWriter::add_video_stream() { #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : // TODO: Set `crf` or `qp` according to bitrate, as bitrate is not supported by these encoders yet. - if (info.video_bit_rate >= 1000) { - c->bit_rate = 0; - if (strstr(info.vcodec.c_str(), "aom") != NULL) { - int calculated_quality = 35; - if (info.video_bit_rate < 500000) calculated_quality = 50; - if (info.video_bit_rate > 5000000) calculated_quality = 10; - av_opt_set_int(c->priv_data, "crf", calculated_quality, 0); - info.video_bit_rate = calculated_quality; - } else { - int calculated_quality = 50; - if (info.video_bit_rate < 500000) calculated_quality = 60; - if (info.video_bit_rate > 5000000) calculated_quality = 15; - av_opt_set_int(c->priv_data, "qp", calculated_quality, 0); - info.video_bit_rate = calculated_quality; - } // medium - } - if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { - av_opt_set_int(c->priv_data, "preset", 6, 0); - av_opt_set_int(c->priv_data, "forced-idr",1,0); - } - else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { - av_opt_set_int(c->priv_data, "speed", 7, 0); - av_opt_set_int(c->priv_data, "tile-rows", 2, 0); - av_opt_set_int(c->priv_data, "tile-columns", 4, 0); - } - else if (strstr(info.vcodec.c_str(), "aom") != NULL) { - // Set number of tiles to a fixed value - // TODO: Allow user to chose their own number of tiles - av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows - av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns - av_opt_set_int(c->priv_data, "row-mt", 1, 0); // use multiple cores - av_opt_set_int(c->priv_data, "cpu-used", 3, 0); // default is 1, usable is 4 - } - //break; + if (info.video_bit_rate >= 1000) { + c->bit_rate = 0; + if (strstr(info.vcodec.c_str(), "aom") != NULL) { + int calculated_quality = 35; + if (info.video_bit_rate < 500000) calculated_quality = 50; + if (info.video_bit_rate > 5000000) calculated_quality = 10; + av_opt_set_int(c->priv_data, "crf", calculated_quality, 0); + info.video_bit_rate = calculated_quality; + } else { + int calculated_quality = 50; + if (info.video_bit_rate < 500000) calculated_quality = 60; + if (info.video_bit_rate > 5000000) calculated_quality = 15; + av_opt_set_int(c->priv_data, "qp", calculated_quality, 0); + info.video_bit_rate = calculated_quality; + } // medium + } + if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) { + av_opt_set_int(c->priv_data, "preset", 6, 0); + av_opt_set_int(c->priv_data, "forced-idr",1,0); + } + else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) { + av_opt_set_int(c->priv_data, "speed", 7, 0); + av_opt_set_int(c->priv_data, "tile-rows", 2, 0); + av_opt_set_int(c->priv_data, "tile-columns", 4, 0); + } + else if (strstr(info.vcodec.c_str(), "aom") != NULL) { + // Set number of tiles to a fixed value + // TODO: Allow user to chose their own number of tiles + av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows + av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns + av_opt_set_int(c->priv_data, "row-mt", 1, 0); // use multiple cores + av_opt_set_int(c->priv_data, "cpu-used", 3, 0); // default is 1, usable is 4 + } + //break; #endif case AV_CODEC_ID_VP9 : case AV_CODEC_ID_HEVC : From 001b2d8a71d5d6fa85c5f03c775b016e196fccd3 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 18 Jun 2020 05:47:40 -0400 Subject: [PATCH 086/100] MagickUtils: Add #pragma to silence IM6 warning --- include/MagickUtilities.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/MagickUtilities.h b/include/MagickUtilities.h index 74365904..953b85ee 100644 --- a/include/MagickUtilities.h +++ b/include/MagickUtilities.h @@ -32,7 +32,11 @@ #ifdef USE_IMAGEMAGICK +// Exclude a warning message with IM6 headers +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-qualifiers" #include "Magick++.h" +#pragma GCC diagnostic pop // Determine ImageMagick version, as IM7 isn't fully // backwards compatible From 3157d757477edfc14f226a1e3ce430a97176e2d6 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 2 Jul 2020 16:54:32 -0700 Subject: [PATCH 087/100] Leave the values for qmin and qmax at their default values except for mpeg2. Changing them for the other codecs resultet in exporting with the wrong bitrate. --- src/FFmpegWriter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d960d677..d8695501 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1202,8 +1202,10 @@ AVStream *FFmpegWriter::add_video_stream() { ) { c->bit_rate = info.video_bit_rate; if (info.video_bit_rate >= 1500000) { - c->qmin = 2; - c->qmax = 30; + if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + c->qmin = 3; + c->qmax = 30; + } } // Here should be the setting for low fixed bitrate // Defaults are used because mpeg2 otherwise had problems From accc5a8deb42bcac4ae3caced2bc98a9971f00b6 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 5 Jul 2020 20:45:41 -0500 Subject: [PATCH 088/100] Updating to gcc 8.4 for MacOS Catalina --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 925bf020..2b8d8299 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ mac-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc48/bin/g++-4.8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc48/bin/gcc-4.8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPYTHON_MODULE_PATH=python -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ + - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc@8/bin/g++-8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc@8/bin/gcc-8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPYTHON_MODULE_PATH=python -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ - make - make install - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" From 7b322a0948d277749f259ef730835617918bc39c Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 5 Jul 2020 20:51:18 -0500 Subject: [PATCH 089/100] Making CMake Threads not required. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17b73863..f0b0524f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -303,7 +303,7 @@ endforeach() # Threading library -- uses IMPORTED target Threads::Threads (since CMake 3.1) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) -find_package(Threads REQUIRED) +find_package(Threads) target_link_libraries(openshot PUBLIC Threads::Threads) ################### OPENMP ##################### From bfefe501d0d5a2982172c852bdb2e97a6821b009 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 5 Jul 2020 21:09:31 -0500 Subject: [PATCH 090/100] Experimenting with Cmake and Threads failure --- src/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0b0524f..cd2fe142 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -303,8 +303,8 @@ endforeach() # Threading library -- uses IMPORTED target Threads::Threads (since CMake 3.1) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) -find_package(Threads) -target_link_libraries(openshot PUBLIC Threads::Threads) +#find_package(Threads REQUIRED) +#target_link_libraries(openshot PUBLIC Threads::Threads) ################### OPENMP ##################### # Check for OpenMP (used for multi-core processing) @@ -317,7 +317,7 @@ if(NOT TARGET OpenMP::OpenMP_CXX) add_library(OpenMP_TARGET INTERFACE) add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET) target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) - target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads) + #target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads) target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) endif() From d2dd3d3e3f21f248043701ed275120afbdcad338 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 5 Jul 2020 21:46:40 -0500 Subject: [PATCH 091/100] Experimenting with new include folder, since Catalina doesn't have a /usr/include/ --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2b8d8299..1835040c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ mac-builder: - unzip artifacts.zip - export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64 - mkdir -p build; cd build; - - cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc@8/bin/g++-8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc@8/bin/gcc-8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPYTHON_MODULE_PATH=python -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ + - cmake -DCMAKE_CXX_FLAGS=-I\ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc@8/bin/g++-8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc@8/bin/gcc-8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPYTHON_MODULE_PATH=python -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ - make - make install - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" From b7dd86e63a579c21c2325ceb79fd797312699236 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 6 Jul 2020 02:10:35 -0500 Subject: [PATCH 092/100] Experimental ABI fix to deal with '__cxx11' --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd2fe142..ba485e74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,8 +41,8 @@ if (APPLE) # If you still get errors compiling with GCC 4.8, mac headers need to be patched: http://hamelot.co.uk/programming/osx-gcc-dispatch_block_t-has-not-been-declared-invalid-typedef/ set_property(GLOBAL PROPERTY JUCE_MAC "JUCE_MAC") add_definitions(-DNDEBUG) + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) set(EXTENSION "mm") - set(JUCE_PLATFORM_SPECIFIC_DIR build/macosx/platform_specific_code) set(JUCE_PLATFORM_SPECIFIC_LIBRARIES "-framework Carbon -framework Cocoa -framework CoreFoundation -framework CoreAudio -framework CoreMidi -framework IOKit -framework AGL -framework AudioToolbox -framework QuartzCore -lobjc -framework Accelerate") endif() From 6e6b60fa22f774a0717423893b798ba1cf6be8c3 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 6 Jul 2020 02:33:26 -0500 Subject: [PATCH 093/100] Experimental ABI fix to deal with '__cxx11' (take 2) --- src/CMakeLists.txt | 3 +++ tests/CMakeLists.txt | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba485e74..50143a6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,6 +45,9 @@ if (APPLE) set(EXTENSION "mm") set(JUCE_PLATFORM_SPECIFIC_DIR build/macosx/platform_specific_code) set(JUCE_PLATFORM_SPECIFIC_LIBRARIES "-framework Carbon -framework Cocoa -framework CoreFoundation -framework CoreAudio -framework CoreMidi -framework IOKit -framework AGL -framework AudioToolbox -framework QuartzCore -lobjc -framework Accelerate") + + # Prevent compiling with __cxx11 + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) endif() ################ IMAGE MAGICK ################## diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7ccddba8..f75d8ab1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,6 +36,11 @@ if(WIN32) set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -include cmath") endif() +if (APPLE) + # Prevent compiling with __cxx11 + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +endif() + ################### UNITTEST++ ##################### # Find UnitTest++ libraries (used for unit testing) find_package(UnitTest++) From aac43ec038b93496a4fc4ab4457259b6422cb62a Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 7 Jul 2020 02:34:11 -0500 Subject: [PATCH 094/100] Removing commented out code --- src/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 50143a6f..6b9dd8ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,6 @@ if (APPLE) # If you still get errors compiling with GCC 4.8, mac headers need to be patched: http://hamelot.co.uk/programming/osx-gcc-dispatch_block_t-has-not-been-declared-invalid-typedef/ set_property(GLOBAL PROPERTY JUCE_MAC "JUCE_MAC") add_definitions(-DNDEBUG) - add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) set(EXTENSION "mm") set(JUCE_PLATFORM_SPECIFIC_DIR build/macosx/platform_specific_code) set(JUCE_PLATFORM_SPECIFIC_LIBRARIES "-framework Carbon -framework Cocoa -framework CoreFoundation -framework CoreAudio -framework CoreMidi -framework IOKit -framework AGL -framework AudioToolbox -framework QuartzCore -lobjc -framework Accelerate") @@ -306,8 +305,6 @@ endforeach() # Threading library -- uses IMPORTED target Threads::Threads (since CMake 3.1) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) -#find_package(Threads REQUIRED) -#target_link_libraries(openshot PUBLIC Threads::Threads) ################### OPENMP ##################### # Check for OpenMP (used for multi-core processing) @@ -320,7 +317,6 @@ if(NOT TARGET OpenMP::OpenMP_CXX) add_library(OpenMP_TARGET INTERFACE) add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET) target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) - #target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads) target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS}) endif() From 9ef8f8478eca5b128c7bf7e6946c134e1ed82762 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 7 Jul 2020 10:14:02 -0700 Subject: [PATCH 095/100] Formating --- src/FFmpegWriter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d8695501..e737462f 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1202,10 +1202,10 @@ AVStream *FFmpegWriter::add_video_stream() { ) { c->bit_rate = info.video_bit_rate; if (info.video_bit_rate >= 1500000) { - if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - c->qmin = 3; - c->qmax = 30; - } + if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + c->qmin = 3; + c->qmax = 30; + } } // Here should be the setting for low fixed bitrate // Defaults are used because mpeg2 otherwise had problems From 6114be5e0ff9fbdd5ab439dbe98840a97afb8d7d Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 7 Jul 2020 10:20:48 -0700 Subject: [PATCH 096/100] Fixed typo --- src/FFmpegWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e737462f..158ef662 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1203,7 +1203,7 @@ AVStream *FFmpegWriter::add_video_stream() { c->bit_rate = info.video_bit_rate; if (info.video_bit_rate >= 1500000) { if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - c->qmin = 3; + c->qmin = 2; c->qmax = 30; } } From ca31359327c4d4c4a4c615de550ed8978262b88e Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Wed, 8 Jul 2020 17:39:04 -0400 Subject: [PATCH 097/100] FFmpegWriter: Missed 1 rename to video_codec_ctx --- src/FFmpegWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index cbf8a88b..5797d09e 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -845,7 +845,7 @@ void FFmpegWriter::flush_encoders() { if (info.has_video && video_codec_ctx && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) return; #else - if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) + if (info.has_video && video_codec_ctx && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) return; #endif From 85b6a967254af5493f1130631da5aa99559675e3 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 8 Jul 2020 17:56:08 -0400 Subject: [PATCH 098/100] Enable IN_LIST in older CMake --- src/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61892668..ffaa7e8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,11 @@ include(FeatureSummary) include(GNUInstallDirs) +# Enable IN_LIST in older CMake +if (POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) +endif() + ################ WINDOWS ################## # Set some compiler options for Windows # required for libopenshot-audio headers From b8e1aded6752011d4486cce55eaa5a65e0a670f8 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 26 Jul 2020 22:37:12 -0400 Subject: [PATCH 099/100] CMake: Remove threading config variables Using FindThreads and the Threads::Threads target directly was causing problems, and OpenMP seems to handle all this itself now. --- src/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ccc31949..31cdda98 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -317,11 +317,6 @@ foreach(ff_comp IN LISTS all_comps) endforeach() -################### Threads #################### -# Threading library -- uses IMPORTED target Threads::Threads (since CMake 3.1) -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) -set(THREADS_PREFER_PTHREAD_FLAG TRUE) - ################### OPENMP ##################### # Check for OpenMP (used for multi-core processing) From 729e349d62087c4c593d3af1073688b8a35deab1 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Fri, 7 Aug 2020 17:14:39 -0400 Subject: [PATCH 100/100] Remove FFmpeg 3.2 from Travis matrix (#548) --- .travis.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index 241d5be3..ab338bdd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,11 +32,6 @@ addons: - curl jobs: - - # The FFmpeg 3.2 backport PPA has gone missing - allow_failures: - - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" - include: - name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)" env: @@ -99,31 +94,6 @@ jobs: - libavresample-dev - libomp-dev - - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)" - env: - - BUILD_VERSION=ffmpeg32 - - CMAKE_EXTRA_ARGS="" - - TEST_TARGET="os_test" - os: linux - dist: xenial - addons: - apt: - sources: - - sourceline: 'ppa:openshot.developers/libopenshot-daily' - - sourceline: 'ppa:jon-hedgerows/ffmpeg-backports' - packages: - - *p_common - - libavresample-dev - - libavcodec57 - - libavdevice57 - - libavfilter6 - - libavformat57 - - libavresample3 - - libavutil55 - - libpostproc54 - - libswresample2 - - libswscale4 - - name: "FFmpeg 2 GCC (Ubuntu 16.04 Xenial)" env: - BUILD_VERSION=ffmpeg2