From eb7d60da3e5d652e02d89c95b5f0336a0d591bb0 Mon Sep 17 00:00:00 2001 From: Zexin Yang Date: Fri, 18 Nov 2022 11:13:45 +0100 Subject: [PATCH] video encoding - user has to request ffmpeg support - handle old version of ffmpeg --- CMakeLists.txt | 36 +++++++++++++------ applications/Mapple/main.cpp | 7 ++-- applications/Mapple/paint_canvas_snapshot.cpp | 3 ++ easy3d/video/CMakeLists.txt | 2 +- easy3d/video/video_encoder.cpp | 26 ++++++++++++-- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b97d4fb29..66a6cc463 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,8 @@ option(Easy3D_BUILD_TESTS "Build Easy3D Tests" OFF) option(Easy3D_ENABLE_CGAL "Build advanced features that require CGAL (>= v5.1)" OFF) # Build advanced examples/applications that require Qt5 (>= v5.6) option(Easy3D_ENABLE_QT "Build advanced examples/applications that require Qt5 (>= v5.6)" OFF) +# Build the video encoding module that requires ffmpeg +option(Easy3D_ENABLE_FFMPEG "Build the video encoding module that requires ffmpeg" OFF) ################################################################################ @@ -158,16 +160,29 @@ if (Easy3D_ENABLE_CGAL) endif () endif () -include(./cmake/FindFFMPEG.cmake) -if (FFMPEG_FOUND) - set(Easy3D_HAS_FFMPEG TRUE) -else () - set(Easy3D_HAS_FFMPEG FALSE) - message(WARNING "You have requested FFMPEG support but FFMPEG was not found. " - "To use FFMPEG, make sure FFMPEG exists on your system (install/build FFMPEG if necessary). " - "You can modify the search paths of 'include' and 'lib' in 'Easy3D/cmake/FindFFMPEG.cmake', " - "and then run CMake. The FFMPEG support allows recording animation into a video file. " - "Ignore this message if you don't need this feature.") +if (Easy3D_ENABLE_FFMPEG) + include(./cmake/FindFFMPEG.cmake) + if (FFMPEG_FOUND) + set(Easy3D_HAS_FFMPEG TRUE) + else () + set(Easy3D_HAS_FFMPEG FALSE) + message(WARNING "You have requested ffmpeg support but ffmpeg was not found (v4.0 or later required). " + "The ffmpeg support allows encoding/recording animation into a video file. You can ignore " + "this warning if you don't need this feature. \n" + "To enable video encoding, make sure ffmpeg exists on your system. Modify the search paths of " + "'include' and 'lib' in 'Easy3D/cmake/FindFFMPEG.cmake', and then run CMake. \n" + "How to install ffmpeg (v4.0 or later required)? \n" + " On Windows, you can download ffmpeg from: \n" + " https://ffmpeg.org/download.html \n" + " On macOS, use the following command to install ffmpeg: \n" + " brew install ffmpeg \n" + " On Linux, one has to install the libraries using: \n" + " sudo apt-get install libavcodec-dev \n" + " sudo apt-get install libavformat-dev \n" + " sudo apt-get install libswscale-dev \n" + " sudo apt-get install libavutil-dev \n" + ) + endif () endif () ################################################################################ @@ -313,6 +328,7 @@ message(STATUS " Build documentation : ${Easy3D_BUILD_DOCUMENTATION}") message(STATUS " Build tests : ${Easy3D_BUILD_TESTS}") message(STATUS " With CGAL (>= v5.1) : ${Easy3D_ENABLE_CGAL}") message(STATUS " With Qt5 (>= v5.6) : ${Easy3D_ENABLE_QT}") +message(STATUS " With ffmpeg (>= v4.0) : ${Easy3D_ENABLE_FFMPEG}") message(STATUS " Installation directory : ${CMAKE_INSTALL_PREFIX}") message(STATUS "************************************************************") diff --git a/applications/Mapple/main.cpp b/applications/Mapple/main.cpp index 2954edf1d..0e39747ca 100644 --- a/applications/Mapple/main.cpp +++ b/applications/Mapple/main.cpp @@ -62,10 +62,13 @@ class Mapple : public QApplication try { return QApplication::notify(receiver, event); } catch(QException& e) { - LOG(ERROR) << "an exception was thrown: " << e.what(); + LOG(ERROR) << "caught an exception: " << e.what(); + } + catch(std::exception& e) { + LOG(ERROR) << "caught an exception: " << e.what(); } catch(...) { - LOG(ERROR) << "an unknown exception was thrown"; + LOG(ERROR) << "caught an unknown exception"; } return false; } diff --git a/applications/Mapple/paint_canvas_snapshot.cpp b/applications/Mapple/paint_canvas_snapshot.cpp index 96bcfe49f..9e1e05405 100644 --- a/applications/Mapple/paint_canvas_snapshot.cpp +++ b/applications/Mapple/paint_canvas_snapshot.cpp @@ -262,7 +262,10 @@ void PaintCanvas::recordAnimation(const QString &file_name, int fps, int bit_rat const int fh = h * dpi_scaling(); VideoEncoder encoder; if (!encoder.start(file_name.toStdString(), fps, bitrate)) { + // clean up and restore the settings before exit + encoder.end(); setEnabled(true); + easy3d::connect(&camera_->frame_modified, this, static_cast(&PaintCanvas::update)); return; } diff --git a/easy3d/video/CMakeLists.txt b/easy3d/video/CMakeLists.txt index 85601623f..4dfd38783 100755 --- a/easy3d/video/CMakeLists.txt +++ b/easy3d/video/CMakeLists.txt @@ -12,5 +12,5 @@ set(${module}_sources add_module(${module} "${${module}_headers}" "${${module}_sources}" "${private_dependencies}" "${public_dependencies}") target_include_directories(easy3d_${module} PRIVATE ${FFMPEG_INCLUDE_DIRS}) -target_compile_definitions(easy3d_${module} PUBLIC HAS_CGAL) +target_compile_definitions(easy3d_${module} PUBLIC HAS_FFMPEG) install_module(${module}) \ No newline at end of file diff --git a/easy3d/video/video_encoder.cpp b/easy3d/video/video_encoder.cpp index 8a989d9fe..79d80b779 100644 --- a/easy3d/video/video_encoder.cpp +++ b/easy3d/video/video_encoder.cpp @@ -24,7 +24,7 @@ * along with this program. If not, see . ********************************************************************/ -#include "video_encoder.h" +#include extern "C" { #include @@ -35,6 +35,13 @@ extern "C" { #include + +// check avcodec version +#if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 18, 100)) // this number corresponds to ffmpeg v4.0 + #pragma message "[WARNING]: Your ffmpeg is too old. Please update it to v4.0 or above" +#endif + + namespace internal { // a wrapper around a single output AVStream @@ -287,8 +294,10 @@ namespace internal { LOG(WARNING) << "could not deduce output format from file extension: using MPEG"; avformat_alloc_output_context2(&fmt_ctx, nullptr, "mpeg", filename_.c_str()); } - if (!fmt_ctx) - return false; + if (!fmt_ctx) { + LOG(ERROR) << "failed to allocate the output media context"; + return false; + } fmt = fmt_ctx->oformat; return true; @@ -373,6 +382,9 @@ namespace internal { void VideoEncoderImpl::end() { + if (!fmt_ctx) // video context was not created or has already been deleted + return; + av_write_trailer(fmt_ctx); /* Close each codec. */ @@ -384,6 +396,7 @@ namespace internal { /* free the stream */ avformat_free_context(fmt_ctx); + fmt_ctx = nullptr; } } @@ -394,6 +407,13 @@ using namespace internal; namespace easy3d { VideoEncoder::VideoEncoder() : encoder_(nullptr) { + LOG(INFO) << "ffmpeg version : " << av_version_info(); + LOG(INFO) << "avcodec_version: " + << AV_VERSION_MAJOR(LIBAVCODEC_VERSION_INT) << "." + << AV_VERSION_MINOR(LIBAVCODEC_VERSION_INT); + if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 18, 100)) // this number corresponds to ffmpeg v4.0 + LOG(WARNING) << "your program was built with too old ffmpeg (" << av_version_info() << "), and " + << "video encoding is not available. Contact the author of the program to fix it"; #ifdef NDEBUG av_log_set_level(AV_LOG_QUIET); #else