diff --git a/.gitignore b/.gitignore
index 427a1344..e08b9c55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,8 +12,10 @@
*.la
*.a
-build
+build*
dist
+install*
+test/**/test*[.wav|.avi|.mov|.h264|.mxf]
# CMake
CMakeCache.txt
diff --git a/.travis.yml b/.travis.yml
index fb5b4bd7..fa780ef6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,23 +25,28 @@ env:
- DEPENDENCY_LOG_FILE=${TRAVIS_BUILD_DIR}/build-dependencies-log.txt
- YASM_VERSION=1.3.0
- - LAME_VERSION=3.99.5
- - FAAC_VERSION=1.28
+ - LAME_VERSION=3.100
+ # - FAAC_VERSION=1.28
- XVID_VERSION=1.3.3
- - FDKAAC_VERSION=0.1.3
+ # - FDKAAC_VERSION=0.1.3
- OGG_VERSION=1.3.2
- - VORBIS_VERSION=1.3.4
- - THEORA_VERSION=1.1.1
+ - VORBIS_VERSION=1.3.6
+ # - THEORA_VERSION=1.1.1
- VPX_VERSION=1.4.0
matrix:
- - DEPENDENCY_NAME=libav DEPENDENCY_VERSION=11.3 ENABLE_COVERAGE=true
- - DEPENDENCY_NAME=libav DEPENDENCY_VERSION=11.3 ENABLE_COVERAGE=false
- - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.4.2 ENABLE_COVERAGE=true
- - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.4.2 ENABLE_COVERAGE=false
- - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.5.7 ENABLE_COVERAGE=false
- - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.6.8 ENABLE_COVERAGE=false
- - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.7.6 ENABLE_COVERAGE=false
- - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.8.6 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=libav DEPENDENCY_VERSION=11.12 ENABLE_COVERAGE=true
+ # - DEPENDENCY_NAME=libav DEPENDENCY_VERSION=11.12 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=libav DEPENDENCY_VERSION=12.3 ENABLE_COVERAGE=true
+ # - DEPENDENCY_NAME=libav DEPENDENCY_VERSION=12.3 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.4.2 ENABLE_COVERAGE=true
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.4.2 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.5.7 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.6.8 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.7.6 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.8.6 ENABLE_COVERAGE=false
+ # - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=4.0 ENABLE_COVERAGE=false
+ - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=4.1 ENABLE_COVERAGE=false
+ - DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=4.2 ENABLE_COVERAGE=true
matrix:
exclude:
@@ -57,6 +62,7 @@ matrix:
env: DEPENDENCY_NAME=ffmpeg DEPENDENCY_VERSION=2.4.2 ENABLE_COVERAGE=true
allow_failures:
# build with libav
+ - os: osx
- env: DEPENDENCY_NAME=libav DEPENDENCY_VERSION=11.3 ENABLE_COVERAGE=true
- env: DEPENDENCY_NAME=libav DEPENDENCY_VERSION=11.3 ENABLE_COVERAGE=false
# build with ffmpeg-2.8.6
@@ -75,8 +81,10 @@ addons:
packages:
- cmake
- swig
- - python-dev
- - python-nose
+ - python3-dev
+ - python3
+ - python3-nose
+ - python3-coverage
- freeglut3-dev
cache:
@@ -96,11 +104,12 @@ before_script:
# install coverage tools
- if [ ${ENABLE_COVERAGE} ]; then ./tools/travis/gcc.install.coverage.sh; fi
+
+script:
# install avtranscoder dependencies
- if [ ${TRAVIS_OS_NAME} = "linux" ]; then ./tools/travis/linux.install.deps.sh; fi
- if [ ${TRAVIS_OS_NAME} = "osx" ]; then ./tools/travis/osx.install.deps.sh; fi
-script:
# build
- ./tools/travis/build.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65da65f2..3fa384b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,15 @@ cmake_minimum_required(VERSION 2.8.11)
project(AvTranscoder)
+# All libraries will be put in INSTALL_PREFIX/lib
+# RPATH of host points INSTALL_PREFIX/lib
+# see: http://www.cmake.org/Wiki/CMake_RPATH_handling
+set(CMAKE_MACOSX_RPATH 1)
+set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+
# Define AvTranscoder default path to profiles
add_definitions(-DAVTRANSCODER_DEFAULT_AVPROFILES="${CMAKE_INSTALL_PREFIX}/share/avprofiles")
diff --git a/README.md b/README.md
index f31fd5b8..c2d9effc 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,9 @@ Based on FFmpeg/Libav libraries to support various video and audio formats, avTr
[](https://ci.appveyor.com/project/cchampet/avtranscoder)
[](https://coveralls.io/r/avTranscoder/avTranscoder)
-[](https://bitdeli.com/free "Bitdeli Badge")
+
-[](http://waffle.io/avTranscoder/avTranscoder)
+
Click on the badge above to have a big picture view of what's in progress and how you can help.
:warning: The latest avTranscoder API does not fit with libav.
@@ -18,7 +18,7 @@ Click on the badge above to have a big picture view of what's in progress and ho
#### The basics
* avTranscoder is a C++ library.
* avTranscoder uses [SWIG](http://www.swig.org/) to generate __Java__ and __Python__ bindings.
-* avTranscoder is multiplateform (Linux, MAC, Windows).
+* avTranscoder is multiplatform (Linux, MAC, Windows).
* avTranscoder could be based on [Libav](https://libav.org/), [FFmpeg](https://ffmpeg.org/), or your custom fork of one of these librairies.
#### License
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 83ed81df..02945a9b 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -1,8 +1,10 @@
# C++ apps
+add_subdirectory(avAudioPhaseMeter)
add_subdirectory(avInfo)
add_subdirectory(avMeta)
add_subdirectory(avPlayer)
add_subdirectory(avProcessor)
+add_subdirectory(customEncoder)
# Python apps
add_subdirectory(pyProcessor)
diff --git a/app/avAudioPhaseMeter/CMakeLists.txt b/app/avAudioPhaseMeter/CMakeLists.txt
new file mode 100644
index 00000000..68946eb9
--- /dev/null
+++ b/app/avAudioPhaseMeter/CMakeLists.txt
@@ -0,0 +1,25 @@
+### cpp/avProcessor
+
+# Load custom cmake utilities
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+include(AvTranscoderMacros)
+
+# Build app
+add_executable(avaudiophasemeter avAudioPhaseMeter.cpp)
+set_target_properties(avaudiophasemeter PROPERTIES VERSION ${AVTRANSCODER_VERSION})
+target_link_libraries(avaudiophasemeter avtranscoder-shared)
+
+# Install app
+if(WIN32)
+ set_target_properties(avaudiophasemeter PROPERTIES OUTPUT_NAME "avaudiophasemeter-${AVTRANSCODER_VERSION}")
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avaudiophasemeter.exe" "${CMAKE_CURRENT_BINARY_DIR}/avaudiophasemeter-${AVTRANSCODER_VERSION}.exe")
+else()
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avaudiophasemeter" "${CMAKE_CURRENT_BINARY_DIR}/avaudiophasemeter-${AVTRANSCODER_VERSION}")
+endif()
+
+install(
+ FILES ${BINARY_FILES}
+ PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE
+ DESTINATION "bin/"
+ OPTIONAL
+)
diff --git a/app/avAudioPhaseMeter/avAudioPhaseMeter.cpp b/app/avAudioPhaseMeter/avAudioPhaseMeter.cpp
new file mode 100644
index 00000000..e018f785
--- /dev/null
+++ b/app/avAudioPhaseMeter/avAudioPhaseMeter.cpp
@@ -0,0 +1,148 @@
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+std::vector parseConfigFile(const std::string& configFilename)
+{
+ std::vector result;
+
+ std::ifstream configFile(configFilename.c_str(), std::ifstream::in);
+
+ std::string line;
+ size_t countLines = 0;
+ while(std::getline(configFile, line))
+ {
+ if(++countLines > 2)
+ {
+ throw std::runtime_error("Audio phase analysis can only be done on a stereo pair, i.e. two channels (see usage).");
+ }
+
+ std::istringstream is_line(line);
+ std::string filename;
+ if(std::getline(is_line, filename, '='))
+ {
+ std::string stream;
+ std::getline(is_line, stream);
+
+ std::stringstream ss(stream);
+ size_t streamIndex = 0;
+ char separator;
+ int channelIndex = -1;
+ ss >> streamIndex;
+ ss >> separator;
+ if(separator == '.')
+ {
+ ss >> channelIndex;
+ }
+
+ bool newInputDescAdded = false;
+ // if we already have an input description with the same filename/streamIndex, add only the new channelIndex
+ for(std::vector::iterator it = result.begin(); it != result.end(); ++it)
+ {
+ if(it->_filename == filename && it->_streamIndex == streamIndex)
+ {
+ it->_channelIndexArray.push_back(channelIndex);
+ newInputDescAdded = true;
+ break;
+ }
+ }
+ if(!newInputDescAdded)
+ {
+ result.push_back(avtranscoder::InputStreamDesc(filename, streamIndex, channelIndex));
+ }
+ }
+ }
+
+ configFile.close();
+
+ return result;
+}
+
+void displayUsage(const std::string& program)
+{
+ std::cout << "Usage: " << program << " CONFIG OUTPUT [OPTIONS]" << std::endl << std::endl;
+ std::cout << "\tCONFIG: input configuration file" << std::endl;
+ std::cout << "\t\tEach line represents one audio stream analysed." << std::endl;
+ std::cout << "\t\tPattern of each line is:" << std::endl;
+ std::cout << "\t\t[inputFile]=STREAM_INDEX.CHANNEL_INDEX" << std::endl;
+ std::cout << "\t\tWARNING: audio phase analyser only support stereo layout, i.e. two lines in this configuration." << std::endl << std::endl;
+ std::cout << "\tOUTPUT: metadata output file" << std::endl;
+ std::cout << "\t\tPattern for each frame is:" << std::endl;
+ std::cout << "\t\t `frame:[FRAME_ID] pts:[PTS] pts_time:[PTS_TIME]" << std::endl;
+ std::cout << "\t\t lavfi.aphasemeter.phase=[PHASE_VALUE]`" << std::endl << std::endl;
+ std::cout << "\tOPTIONS:" << std::endl;
+ std::cout << "\t\t--info set log level to AV_LOG_INFO" << std::endl;
+ std::cout << "\t\t--debug set log level to AV_LOG_DEBUG" << std::endl;
+ std::cout << "\t\t--help display this help" << std::endl << std::endl;
+}
+
+int main(int argc, char** argv)
+{
+ // Preload FFmpeg context
+ avtranscoder::preloadCodecsAndFormats();
+ avtranscoder::Logger::setLogLevel(AV_LOG_QUIET);
+
+ if(argc < 3)
+ {
+ displayUsage(argv[0]);
+ }
+
+ // List command line arguments
+ std::vector arguments;
+ for(int argument = 1; argument < argc; ++argument)
+ {
+ arguments.push_back(argv[argument]);
+ }
+ for(size_t argument = 0; argument < arguments.size(); ++argument)
+ {
+ if(arguments.at(argument) == "--help")
+ {
+ displayUsage(argv[0]);
+ return 0;
+ }
+ else if(arguments.at(argument) == "--debug")
+ {
+ avtranscoder::Logger::setLogLevel(AV_LOG_DEBUG);
+ }
+ else if(arguments.at(argument) == "--info")
+ {
+ avtranscoder::Logger::setLogLevel(AV_LOG_INFO);
+ }
+ }
+
+ try
+ {
+ std::string configFilePath(arguments.at(0));
+ std::string outputFilePath(arguments.at(1));
+ std::vector inputStreamsToAnalyse = parseConfigFile(configFilePath);
+
+ avtranscoder::OutputFile outputFile(outputFilePath, "null"); // the output file will be overwritten by the extracted metadata
+
+ avtranscoder::Transcoder transcoder(outputFile);
+ transcoder.setProcessMethod(avtranscoder::eProcessMethodBasedOnStream, 0);
+ transcoder.addStream(inputStreamsToAnalyse);
+
+ avtranscoder::StreamTranscoder& streamTranscoder = transcoder.getStreamTranscoder(0);
+ avtranscoder::FilterGraph* filterGraph = streamTranscoder.getFilterGraph();
+ filterGraph->addFilter("aphasemeter", "video=0");
+ filterGraph->addFilter("ametadata", "mode=print:file=" + outputFilePath);
+
+ avtranscoder::ConsoleProgress progress;
+ transcoder.process(progress);
+ }
+ catch(std::exception& e)
+ {
+ std::cerr << "ERROR: during process, an error occured: " << e.what() << std::endl;
+ }
+ catch(...)
+ {
+ std::cerr << "ERROR: during process, an unknown error occured" << std::endl;
+ }
+}
diff --git a/app/avInfo/CMakeLists.txt b/app/avInfo/CMakeLists.txt
index 4cba2e5e..8eddbb4c 100644
--- a/app/avInfo/CMakeLists.txt
+++ b/app/avInfo/CMakeLists.txt
@@ -11,7 +11,8 @@ target_link_libraries(avinfo avtranscoder-shared)
# Install app
if(WIN32)
- set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avinfo.exe")
+ set_target_properties(avinfo PROPERTIES OUTPUT_NAME "avinfo-${AVTRANSCODER_VERSION}")
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avinfo.exe" "${CMAKE_CURRENT_BINARY_DIR}/avinfo-${AVTRANSCODER_VERSION}.exe")
else()
set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avinfo" "${CMAKE_CURRENT_BINARY_DIR}/avinfo-${AVTRANSCODER_VERSION}")
endif()
diff --git a/app/avMeta/CMakeLists.txt b/app/avMeta/CMakeLists.txt
index b12c99c9..2228c579 100644
--- a/app/avMeta/CMakeLists.txt
+++ b/app/avMeta/CMakeLists.txt
@@ -11,7 +11,8 @@ target_link_libraries(avmeta avtranscoder-shared)
# Install app
if(WIN32)
- set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avmeta.exe")
+ set_target_properties(avmeta PROPERTIES OUTPUT_NAME "avmeta-${AVTRANSCODER_VERSION}")
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avmeta.exe" "${CMAKE_CURRENT_BINARY_DIR}/avmeta-${AVTRANSCODER_VERSION}.exe")
else()
set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avmeta" "${CMAKE_CURRENT_BINARY_DIR}/avmeta-${AVTRANSCODER_VERSION}")
endif()
diff --git a/app/avPlayer/CMakeLists.txt b/app/avPlayer/CMakeLists.txt
index bf735c2e..61c7e05c 100644
--- a/app/avPlayer/CMakeLists.txt
+++ b/app/avPlayer/CMakeLists.txt
@@ -33,7 +33,8 @@ target_link_libraries(avplayer avtranscoder-shared ${OPENGL_LIBRARIES} ${GLUT_LI
# Install app
if(WIN32)
- set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avplayer.exe")
+ set_target_properties(avplayer PROPERTIES OUTPUT_NAME "avplayer-${AVTRANSCODER_VERSION}")
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avplayer.exe" "${CMAKE_CURRENT_BINARY_DIR}/avplayer-${AVTRANSCODER_VERSION}.exe")
else()
set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avplayer" "${CMAKE_CURRENT_BINARY_DIR}/avplayer-${AVTRANSCODER_VERSION}")
endif()
diff --git a/app/avProcessor/CMakeLists.txt b/app/avProcessor/CMakeLists.txt
index 4cb1a118..8c20bf4f 100644
--- a/app/avProcessor/CMakeLists.txt
+++ b/app/avProcessor/CMakeLists.txt
@@ -11,7 +11,8 @@ target_link_libraries(avprocessor avtranscoder-shared)
# Install app
if(WIN32)
- set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avprocessor.exe")
+ set_target_properties(avprocessor PROPERTIES OUTPUT_NAME "avprocessor-${AVTRANSCODER_VERSION}")
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avprocessor.exe" "${CMAKE_CURRENT_BINARY_DIR}/avprocessor-${AVTRANSCODER_VERSION}.exe")
else()
set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/avprocessor" "${CMAKE_CURRENT_BINARY_DIR}/avprocessor-${AVTRANSCODER_VERSION}")
endif()
diff --git a/app/customEncoder/CMakeLists.txt b/app/customEncoder/CMakeLists.txt
new file mode 100644
index 00000000..df273a35
--- /dev/null
+++ b/app/customEncoder/CMakeLists.txt
@@ -0,0 +1,25 @@
+### cpp/customEncoder
+
+# Load custom cmake utilities
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+include(AvTranscoderMacros)
+
+# Build app
+add_executable(custom-encoder customEncoder.cpp)
+set_target_properties(custom-encoder PROPERTIES VERSION ${AVTRANSCODER_VERSION})
+target_link_libraries(custom-encoder avtranscoder-shared)
+
+# Install app
+if(WIN32)
+ set_target_properties(custom-encoder PROPERTIES OUTPUT_NAME "custom-encoder-${AVTRANSCODER_VERSION}")
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/custom-encoder.exe" "${CMAKE_CURRENT_BINARY_DIR}/custom-encoder-${AVTRANSCODER_VERSION}.exe")
+else()
+ set(BINARY_FILES "${CMAKE_CURRENT_BINARY_DIR}/custom-encoder" "${CMAKE_CURRENT_BINARY_DIR}/custom-encoder-${AVTRANSCODER_VERSION}")
+endif()
+
+install(
+ FILES ${BINARY_FILES}
+ PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE
+ DESTINATION "bin/"
+ OPTIONAL
+)
diff --git a/app/customEncoder/customEncoder.cpp b/app/customEncoder/customEncoder.cpp
new file mode 100644
index 00000000..0de6ce2d
--- /dev/null
+++ b/app/customEncoder/customEncoder.cpp
@@ -0,0 +1,208 @@
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+void parseConfigFile(const std::string& configFilename, avtranscoder::Transcoder& transcoder)
+{
+ std::ifstream configFile(configFilename.c_str(), std::ifstream::in);
+
+ std::string line;
+ while(std::getline(configFile, line))
+ {
+ std::istringstream is_line(line);
+ std::string filename;
+ if(std::getline(is_line, filename, '='))
+ {
+ std::string streamId;
+ if(std::getline(is_line, streamId, ':'))
+ {
+ std::string transcodeProfile;
+ std::getline(is_line, transcodeProfile);
+
+ std::stringstream ss(streamId);
+ size_t streamIndex = 0;
+ char separator = 'x';
+ std::vector channelIndexArray;
+ ss >> streamIndex;
+ ss >> separator;
+ if(separator == '.')
+ {
+ int subStreamIndex = -1;
+ ss >> subStreamIndex;
+ channelIndexArray.push_back(subStreamIndex);
+ }
+
+ // generated stream
+ if(!filename.length())
+ transcoder.addGenerateStream(transcodeProfile);
+ else
+ {
+ avtranscoder::InputStreamDesc inputDesc(filename, streamIndex, channelIndexArray);
+ transcoder.addStream(inputDesc, transcodeProfile);
+ }
+ }
+ }
+ }
+
+ configFile.close();
+}
+
+
+
+class AvExport CustomCodec
+ : public avtranscoder::ICodec
+{
+public:
+ CustomCodec()
+ : avtranscoder::ICodec(avtranscoder::eCodecTypeEncoder, AV_CODEC_ID_PCM_S24LE)
+ {
+ }
+
+ void openCodec(){}
+ void closeCodec(){}
+
+ std::string getCodecName() const { return "Custom Encoder"; };
+ AVCodecID getCodecId() const { return AV_CODEC_ID_PCM_S24LE; }
+ avtranscoder::ECodecType getCodecType() const { return avtranscoder::eCodecTypeEncoder; }
+ int getLatency() const { return 0; }
+
+ avtranscoder::OptionArray getOptions() {
+ std::vector options;
+ return options;
+ }
+};
+
+
+class AvExport CustomEncoder
+ : public avtranscoder::IEncoder
+{
+public:
+ CustomEncoder()
+ : _codec()
+ {}
+ /**
+ * @brief Setup the encoder
+ * @param profile: set encoder parameters from the given profile
+ * @note Open the encoder.
+ */
+ void setupEncoder(const avtranscoder::ProfileLoader::Profile& profile = avtranscoder::ProfileLoader::Profile()) {
+ return;
+ };
+
+ /**
+ * @brief Encode a new frame, and get coded frame
+ * @param sourceFrame: frame that needs to be encoded
+ * @param codedFrame: output encoded coded data (first frames can be delayed)
+ * @return status of encoding
+ * @throw runtime_error if the encoded process failed.
+ */
+ bool encodeFrame(const avtranscoder::IFrame& sourceFrame, avtranscoder::CodedData& codedFrame) {
+ codedFrame.assign(5760, 0);
+ return true;
+ };
+
+ /**
+ * @brief Get the frames remaining into the encoder
+ * @param codedFrame: output encoded data
+ * @return status of encoding
+ * @throw runtime_error if the encoded process failed.
+ */
+ bool encodeFrame(avtranscoder::CodedData& codedFrame) {
+ return false;
+ };
+
+ /**
+ * @brief Get codec used for encoding.
+ * @return a reference to the codec
+ */
+ avtranscoder::ICodec& getCodec() {
+ return _codec;
+ };
+
+private:
+ CustomCodec _codec;
+};
+
+
+int main(int argc, char** argv)
+{
+ std::string help;
+ help += "Usage\n";
+ help += "\tavprocessor INPUT_FILE_NAME OUTPUT_FILE_NAME [--verbose] [--logFile] [--help]\n";
+ help += "Command line options\n";
+ help += "\t--verbose: set log level to AV_LOG_DEBUG\n";
+ help += "\t--logFile: put log in 'avtranscoder.log' file\n";
+ help += "\t--help: display this help\n";
+
+ // Preload FFmpeg context
+ avtranscoder::preloadCodecsAndFormats();
+ avtranscoder::Logger::setLogLevel(AV_LOG_QUIET);
+
+ // List command line arguments
+ std::vector arguments;
+ for(int argument = 1; argument < argc; ++argument)
+ {
+ arguments.push_back(argv[argument]);
+ }
+ for(size_t argument = 0; argument < arguments.size(); ++argument)
+ {
+ if(arguments.at(argument) == "--help")
+ {
+ std::cout << help << std::endl;
+ return 0;
+ }
+ else if(arguments.at(argument) == "--verbose")
+ {
+ avtranscoder::Logger::setLogLevel(AV_LOG_DEBUG);
+ }
+ else if(arguments.at(argument) == "--logFile")
+ {
+ avtranscoder::Logger::logInFile();
+ }
+ }
+
+ // Check required arguments
+ if(argc < 3)
+ {
+ std::cout << "avprocessor can rewrap or transcode inputs to create an output media file." << std::endl;
+ std::cout << "Use option --help to display help" << std::endl;
+ return (-1);
+ }
+
+ try
+ {
+ std::string output_format = "s24le";
+ avtranscoder::OutputFile outputFile(argv[2], output_format);
+
+ avtranscoder::Transcoder transcoder(outputFile);
+ transcoder.setProcessMethod(avtranscoder::eProcessMethodBasedOnStream);
+
+ CustomEncoder* customEncoder = new CustomEncoder;
+ avtranscoder::InputStreamDesc inputDescLeft(argv[1], 1, 0);
+ avtranscoder::InputStreamDesc inputDescRight(argv[1], 2, 0);
+
+ std::vector inputDescriptors;
+ inputDescriptors.push_back(avtranscoder::InputStreamDesc(argv[1], 1, 0));
+ inputDescriptors.push_back(avtranscoder::InputStreamDesc(argv[1], 2, 0));
+
+ transcoder.addStream(inputDescriptors, customEncoder);
+
+ avtranscoder::ConsoleProgress progress;
+ transcoder.process(progress);
+ }
+ catch(std::exception& e)
+ {
+ std::cerr << "ERROR: during process, an error occured: " << e.what() << std::endl;
+ }
+ catch(...)
+ {
+ std::cerr << "ERROR: during process, an unknown error occured" << std::endl;
+ }
+}
diff --git a/appveyor.yml b/appveyor.yml
index adc2bc2c..a809dd3e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -8,7 +8,7 @@ platform:
environment:
global:
DEPENDENCY_NAME: ffmpeg
- DEPENDENCY_VERSION: 2.4.5
+ DEPENDENCY_VERSION: 4.2.1
DEPENDENCY_INSTALL_PATH: C:\ProgramData\install-dependency
AVTRANSCODER_INSTALL_PATH: C:\projects\avtranscoder\build\install-avtranscoder
@@ -25,10 +25,10 @@ install:
# Get the correct python version
- ps: if($env:platform -eq 'x86') {
- $env:PYTHON = "C:\Python27";
+ $env:PYTHON = "C:\Python35";
}
else {
- $env:PYTHON = "C:\Python27-x64";
+ $env:PYTHON = "C:\Python35-x64";
}
# Prepend newly installed Python to the PATH of this build
- cmd: set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
@@ -37,7 +37,7 @@ install:
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
# Upgrade to the latest version of pip to avoid it displaying warnings about it being out of date.
- - pip install --disable-pip-version-check --user --upgrade pip
+ - "python -m pip install --disable-pip-version-check --user --upgrade pip"
# Install tests dependencies
- pip install nose
diff --git a/src/AvTranscoder/Library.cpp b/src/AvTranscoder/Library.cpp
index 961a8906..aed1f827 100644
--- a/src/AvTranscoder/Library.cpp
+++ b/src/AvTranscoder/Library.cpp
@@ -11,6 +11,7 @@ extern "C" {
#else
#include
#endif
+#include
#include
#include
}
@@ -105,9 +106,10 @@ Libraries getLibraries()
std::vector getInputExtensions()
{
std::vector extensions;
- AVInputFormat* iFormat = NULL;
+ const AVInputFormat* iFormat = NULL;
+ void *iFormatOpaque = NULL;
- while((iFormat = av_iformat_next(iFormat)))
+ while((iFormat = av_demuxer_iterate(&iFormatOpaque)))
{
if(iFormat->extensions != NULL)
{
@@ -143,9 +145,10 @@ std::vector getInputExtensions()
std::vector getOutputExtensions()
{
std::vector extensions;
- AVOutputFormat* oFormat = NULL;
+ const AVOutputFormat* oFormat = NULL;
+ void *oFormatOpaque = NULL;
- while((oFormat = av_oformat_next(oFormat)))
+ while((oFormat = av_muxer_iterate(&oFormatOpaque)))
{
if(oFormat->extensions != NULL)
{
diff --git a/src/AvTranscoder/avTranscoder.i b/src/AvTranscoder/avTranscoder.i
index 5005baa8..175a6c22 100644
--- a/src/AvTranscoder/avTranscoder.i
+++ b/src/AvTranscoder/avTranscoder.i
@@ -6,6 +6,7 @@
%include "std_vector.i"
%include "std_pair.i"
%include "std_map.i"
+%include "stdint.i"
%include "AvTranscoder/swig/avException.i"
%include "AvTranscoder/swig/avExport.i"
diff --git a/src/AvTranscoder/codec/ICodec.hpp b/src/AvTranscoder/codec/ICodec.hpp
index de3203dd..8ad135ee 100644
--- a/src/AvTranscoder/codec/ICodec.hpp
+++ b/src/AvTranscoder/codec/ICodec.hpp
@@ -54,7 +54,6 @@ class AvExport ICodec
#ifndef SWIG
AVCodecContext& getAVCodecContext() { return *_avCodecContext; }
const AVCodecContext& getAVCodecContext() const { return *_avCodecContext; }
- AVCodec& getAVCodec() { return *_avCodec; }
const AVCodec& getAVCodec() const { return *_avCodec; }
#endif
@@ -66,7 +65,7 @@ class AvExport ICodec
protected:
AVCodecContext* _avCodecContext; ///< Full codec instance description (has ownership)
- AVCodec* _avCodec; ///< Codec abstract description
+ const AVCodec* _avCodec; ///< Codec abstract description
const bool _isCodecContextAllocated; ///< Is the AVCodecContext allocated by the class
ECodecType _type;
diff --git a/src/AvTranscoder/common.cpp b/src/AvTranscoder/common.cpp
index 5b683c83..86022a79 100644
--- a/src/AvTranscoder/common.cpp
+++ b/src/AvTranscoder/common.cpp
@@ -15,8 +15,10 @@ namespace avtranscoder
void preloadCodecsAndFormats()
{
+#if LIBAVFILTER_VERSION_MAJOR < 7
av_register_all();
avfilter_register_all();
+#endif
}
std::string getDescriptionFromErrorCode(const int code)
diff --git a/src/AvTranscoder/common.hpp b/src/AvTranscoder/common.hpp
index 481daad0..c249e3a3 100644
--- a/src/AvTranscoder/common.hpp
+++ b/src/AvTranscoder/common.hpp
@@ -2,8 +2,8 @@
#define _AV_TRANSCODER_COMMON_HPP_
#define AVTRANSCODER_VERSION_MAJOR 0
-#define AVTRANSCODER_VERSION_MINOR 14
-#define AVTRANSCODER_VERSION_MICRO 0
+#define AVTRANSCODER_VERSION_MINOR 16
+#define AVTRANSCODER_VERSION_MICRO 2
#include
diff --git a/src/AvTranscoder/data/coded/CodedData.cpp b/src/AvTranscoder/data/coded/CodedData.cpp
index 8c556b69..074a0f83 100644
--- a/src/AvTranscoder/data/coded/CodedData.cpp
+++ b/src/AvTranscoder/data/coded/CodedData.cpp
@@ -43,7 +43,7 @@ CodedData& CodedData::operator=(const CodedData& other)
CodedData::~CodedData()
{
- av_free_packet(&_packet);
+ av_packet_unref(&_packet);
}
void CodedData::resize(const size_t newSize)
@@ -75,7 +75,7 @@ void CodedData::refData(CodedData& frame)
void CodedData::clear()
{
- av_free_packet(&_packet);
+ av_packet_unref(&_packet);
initAVPacket();
}
@@ -87,14 +87,16 @@ void CodedData::assign(const size_t size, const int value)
void CodedData::initAVPacket()
{
- av_init_packet(&_packet);
+ _packet = *av_packet_alloc();
_packet.data = NULL;
_packet.size = 0;
}
void CodedData::copyAVPacket(const AVPacket& avPacket)
{
-#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVCODEC_VERSION_INT > AV_VERSION_INT(54, 56, 0)
+#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVCODEC_VERSION_MAJOR > 57
+ av_packet_ref(&_packet, &avPacket);
+#elif AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVCODEC_VERSION_INT > AV_VERSION_INT(54, 56, 0)
// Need const_cast for libav versions from 54.56. to 55.56.
av_copy_packet(&_packet, const_cast(&avPacket));
#else
diff --git a/src/AvTranscoder/data/decoded/AudioFrame.cpp b/src/AvTranscoder/data/decoded/AudioFrame.cpp
index 8dfd3bd8..54fa8119 100644
--- a/src/AvTranscoder/data/decoded/AudioFrame.cpp
+++ b/src/AvTranscoder/data/decoded/AudioFrame.cpp
@@ -45,9 +45,9 @@ AudioFrame::AudioFrame(const AudioFrameDesc& desc, const bool forceDataAllocatio
, _desc(desc)
{
// Set Frame properties
- av_frame_set_sample_rate(_frame, desc._sampleRate);
- av_frame_set_channels(_frame, desc._nbChannels);
- av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
+ _frame->sample_rate = desc._sampleRate;
+ _frame->channels = desc._nbChannels;
+ _frame->channel_layout = av_get_default_channel_layout(desc._nbChannels);
_frame->format = desc._sampleFormat;
_frame->nb_samples = getDefaultNbSamples();
@@ -102,9 +102,9 @@ void AudioFrame::allocateData()
LOG_WARN("The AudioFrame seems to already have allocated data. This could lead to memory leaks.")
// Set Frame properties
- av_frame_set_sample_rate(_frame, _desc._sampleRate);
- av_frame_set_channels(_frame, _desc._nbChannels);
- av_frame_set_channel_layout(_frame, av_get_default_channel_layout(_desc._nbChannels));
+ _frame->sample_rate = _desc._sampleRate;
+ _frame->channels = _desc._nbChannels;
+ _frame->channel_layout = av_get_default_channel_layout(_desc._nbChannels);
_frame->format = _desc._sampleFormat;
if(_frame->nb_samples == 0)
_frame->nb_samples = getDefaultNbSamples();
diff --git a/src/AvTranscoder/data/decoded/AudioFrame.hpp b/src/AvTranscoder/data/decoded/AudioFrame.hpp
index 6bf00175..f8d1cb8b 100644
--- a/src/AvTranscoder/data/decoded/AudioFrame.hpp
+++ b/src/AvTranscoder/data/decoded/AudioFrame.hpp
@@ -51,9 +51,9 @@ class AvExport AudioFrame : public IFrame
void freeData();
size_t getDataSize() const;
- size_t getSampleRate() const { return av_frame_get_sample_rate(_frame); }
- size_t getNbChannels() const { return av_frame_get_channels(_frame); }
- size_t getChannelLayout() const { return av_frame_get_channel_layout(_frame); }
+ size_t getSampleRate() const { return _frame->sample_rate; }
+ size_t getNbChannels() const { return _frame->channels; }
+ size_t getChannelLayout() const { return _frame->channel_layout; }
std::string getChannelLayoutDesc() const; ///< Get a description of a channel layout (example: '5.1').
AVSampleFormat getSampleFormat() const { return static_cast(_frame->format); }
size_t getBytesPerSample() const; ///< 0 if unknown sample format
diff --git a/src/AvTranscoder/data/decoded/IFrame.cpp b/src/AvTranscoder/data/decoded/IFrame.cpp
index 608f90e4..84efa32b 100644
--- a/src/AvTranscoder/data/decoded/IFrame.cpp
+++ b/src/AvTranscoder/data/decoded/IFrame.cpp
@@ -69,7 +69,7 @@ void IFrame::assignValue(const unsigned char value)
// Create the buffer
const int bufferSize = getDataSize();
- unsigned char* dataBuffer = static_cast(malloc(bufferSize * sizeof(unsigned char)));
+ unsigned char* dataBuffer = static_cast(av_malloc(bufferSize * sizeof(unsigned char)));
memset(dataBuffer, value, bufferSize);
// Fill the frame
diff --git a/src/AvTranscoder/data/decoded/VideoFrame.cpp b/src/AvTranscoder/data/decoded/VideoFrame.cpp
index 4da08b00..631ffc76 100644
--- a/src/AvTranscoder/data/decoded/VideoFrame.cpp
+++ b/src/AvTranscoder/data/decoded/VideoFrame.cpp
@@ -5,6 +5,7 @@
extern "C" {
#include
#include
+#include
}
#include
@@ -75,7 +76,7 @@ size_t VideoFrame::getDataSize() const
return 0;
}
- const size_t size = avpicture_get_size(getPixelFormat(), getWidth(), getHeight());
+ const size_t size = av_image_get_buffer_size(getPixelFormat(), getWidth(), getHeight(), 1);
if(size == 0)
throw std::runtime_error("Unable to determine image buffer size: " + getDescriptionFromErrorCode(size));
return size;
@@ -92,7 +93,7 @@ void VideoFrame::allocateData()
_frame->format = _desc._pixelFormat;
// Allocate data
- const int ret = avpicture_alloc(reinterpret_cast(_frame), _desc._pixelFormat, _desc._width, _desc._height);
+ const int ret = av_image_alloc(_frame->data, _frame->linesize, _desc._width, _desc._height, _desc._pixelFormat, 1);
if(ret < 0)
{
const std::string formatName = getPixelFormatName(_desc._pixelFormat);
@@ -109,14 +110,13 @@ void VideoFrame::allocateData()
void VideoFrame::freeData()
{
- avpicture_free(reinterpret_cast(_frame));
+ av_freep(&_frame->data[0]);
_dataAllocated = false;
}
void VideoFrame::assignBuffer(const unsigned char* ptrValue)
{
- const int ret =
- avpicture_fill(reinterpret_cast(_frame), ptrValue, getPixelFormat(), getWidth(), getHeight());
+ const int ret = av_image_fill_arrays(_frame->data, _frame->linesize, ptrValue, getPixelFormat(), getWidth(), getHeight(), 1);
if(ret < 0)
{
std::stringstream msg;
diff --git a/src/AvTranscoder/decoder/AudioDecoder.cpp b/src/AvTranscoder/decoder/AudioDecoder.cpp
index a995a3df..1a7a7d99 100644
--- a/src/AvTranscoder/decoder/AudioDecoder.cpp
+++ b/src/AvTranscoder/decoder/AudioDecoder.cpp
@@ -87,7 +87,7 @@ bool AudioDecoder::decodeNextFrame(IFrame& frameBuffer)
if(!_isSetup)
setupDecoder();
- int got_frame = 0;
+ bool got_frame = false;
while(!got_frame)
{
CodedData data;
@@ -98,18 +98,27 @@ bool AudioDecoder::decodeNextFrame(IFrame& frameBuffer)
// decoding
// @note could be called several times to return the remaining frames (last call with an empty packet)
// @see CODEC_CAP_DELAY
- int ret = avcodec_decode_audio4(&_inputStream->getAudioCodec().getAVCodecContext(), &frameBuffer.getAVFrame(),
- &got_frame, &data.getAVPacket());
+ int ret = avcodec_send_packet(&_inputStream->getAudioCodec().getAVCodecContext(), &data.getAVPacket());
+
if(ret < 0)
{
- throw std::runtime_error("An error occurred during audio decoding: " + getDescriptionFromErrorCode(ret));
+ throw std::runtime_error("An error occurred sending audio packet to decoder: " + getDescriptionFromErrorCode(ret));
}
+ ret = avcodec_receive_frame(&_inputStream->getAudioCodec().getAVCodecContext(), &frameBuffer.getAVFrame());
+
+ if (ret == 0)
+ got_frame = true;
+ else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ got_frame = false;
+ else
+ throw std::runtime_error("An error occurred receiving audio packet from decoder: " + getDescriptionFromErrorCode(ret));
+
// fixed channel layout value after decoding
frameBuffer.getAVFrame().channel_layout = channelLayout;
// if no frame could be decompressed
- if(!nextPacketRead && ret == 0 && got_frame == 0)
+ if(!nextPacketRead && got_frame == 0)
decodeNextFrame = false;
else
decodeNextFrame = true;
@@ -121,6 +130,10 @@ bool AudioDecoder::decodeNextFrame(IFrame& frameBuffer)
return false;
}
}
+
+ if(decodeNextFrame)
+ incrementNbDecodedFrames(frameBuffer.getAVFrame().nb_samples);
+
return decodeNextFrame;
}
diff --git a/src/AvTranscoder/decoder/AudioGenerator.cpp b/src/AvTranscoder/decoder/AudioGenerator.cpp
index 63b1a4b1..6842ba21 100644
--- a/src/AvTranscoder/decoder/AudioGenerator.cpp
+++ b/src/AvTranscoder/decoder/AudioGenerator.cpp
@@ -41,6 +41,14 @@ bool AudioGenerator::decodeNextFrame(IFrame& frameBuffer)
// (which was allocated to expect this number of samples).
_silent->setNbSamplesPerChannel(frameBuffer.getAVFrame().nb_samples);
}
+
+ if(_silent->getNbSamplesPerChannel() != (size_t)frameBuffer.getAVFrame().nb_samples) {
+ LOG_DEBUG("Reset next audio frame nb samples and reallocate.")
+ frameBuffer.getAVFrame().nb_samples = _silent->getNbSamplesPerChannel();
+ frameBuffer.freeData();
+ frameBuffer.allocateData();
+ }
+
LOG_DEBUG("Copy data of the silence when decode next frame")
frameBuffer.copyData(*_silent);
}
@@ -50,6 +58,8 @@ bool AudioGenerator::decodeNextFrame(IFrame& frameBuffer)
LOG_DEBUG("Convert data of the audio specified when decode next frame")
_audioTransform.convert(*_inputFrame, frameBuffer);
}
+
+ incrementNbDecodedFrames(_silent->getNbSamplesPerChannel());
return true;
}
diff --git a/src/AvTranscoder/decoder/IDecoder.hpp b/src/AvTranscoder/decoder/IDecoder.hpp
index d9acf8d1..66062140 100644
--- a/src/AvTranscoder/decoder/IDecoder.hpp
+++ b/src/AvTranscoder/decoder/IDecoder.hpp
@@ -10,6 +10,12 @@ namespace avtranscoder
class AvExport IDecoder
{
+protected:
+ IDecoder()
+ : _decoded_frames_counter(0)
+ {
+ }
+
public:
virtual ~IDecoder(){};
@@ -51,6 +57,16 @@ class AvExport IDecoder
* @note Not sense for generators.
*/
virtual void flushDecoder() {}
+
+ size_t getNbDecodedFrames() { return _decoded_frames_counter; }
+
+protected:
+ void incrementNbDecodedFrames(const size_t& nb_frames = 1) {
+ _decoded_frames_counter += nb_frames;
+ }
+
+private:
+ size_t _decoded_frames_counter;
};
}
diff --git a/src/AvTranscoder/decoder/VideoDecoder.cpp b/src/AvTranscoder/decoder/VideoDecoder.cpp
index ae76fb05..447913be 100644
--- a/src/AvTranscoder/decoder/VideoDecoder.cpp
+++ b/src/AvTranscoder/decoder/VideoDecoder.cpp
@@ -94,15 +94,22 @@ bool VideoDecoder::decodeNextFrame(IFrame& frameBuffer)
// decoding
// @note could be called several times to return the remaining frames (last call with an empty packet)
// @see CODEC_CAP_DELAY
- const int ret = avcodec_decode_video2(&_inputStream->getVideoCodec().getAVCodecContext(), &frameBuffer.getAVFrame(),
- &got_frame, &data.getAVPacket());
- if(ret < 0)
- {
- throw std::runtime_error("An error occurred during video decoding: " + getDescriptionFromErrorCode(ret));
- }
+ int ret = avcodec_send_packet(&_inputStream->getVideoCodec().getAVCodecContext(), &data.getAVPacket());
+
+ if (ret < 0 && (nextPacketRead || ret != AVERROR_EOF))
+ throw std::runtime_error("An error occurred sending video packet to decoder: " + getDescriptionFromErrorCode(ret));
+
+ ret = avcodec_receive_frame(&_inputStream->getVideoCodec().getAVCodecContext(), &frameBuffer.getAVFrame());
+
+ if (ret == 0)
+ got_frame = true;
+ else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ got_frame = false;
+ else
+ throw std::runtime_error("An error occurred receiving video packet from decoder: " + getDescriptionFromErrorCode(ret));
// if no frame could be decompressed
- if(!nextPacketRead && ret == 0 && got_frame == 0)
+ if ((!nextPacketRead && ret == 0) || !got_frame)
decodeNextFrame = false;
else
decodeNextFrame = true;
@@ -114,6 +121,10 @@ bool VideoDecoder::decodeNextFrame(IFrame& frameBuffer)
return false;
}
}
+
+ if(decodeNextFrame)
+ incrementNbDecodedFrames();
+
return decodeNextFrame;
}
diff --git a/src/AvTranscoder/decoder/VideoGenerator.cpp b/src/AvTranscoder/decoder/VideoGenerator.cpp
index ad89c9ac..155d635d 100644
--- a/src/AvTranscoder/decoder/VideoGenerator.cpp
+++ b/src/AvTranscoder/decoder/VideoGenerator.cpp
@@ -51,6 +51,8 @@ bool VideoGenerator::decodeNextFrame(IFrame& frameBuffer)
LOG_DEBUG("Convert data of the image specified when decode next frame")
_videoTransform.convert(*_inputFrame, frameBuffer);
}
+
+ incrementNbDecodedFrames();
return true;
}
diff --git a/src/AvTranscoder/encoder/AudioEncoder.cpp b/src/AvTranscoder/encoder/AudioEncoder.cpp
index 06410299..0b0621d6 100644
--- a/src/AvTranscoder/encoder/AudioEncoder.cpp
+++ b/src/AvTranscoder/encoder/AudioEncoder.cpp
@@ -7,6 +7,7 @@ extern "C" {
}
#include
+#include
namespace avtranscoder
{
@@ -93,20 +94,19 @@ void AudioEncoder::setupEncoder(const ProfileLoader::Profile& profile)
bool AudioEncoder::encodeFrame(const IFrame& sourceFrame, CodedData& codedFrame)
{
- AVCodecContext& avCodecContext = _codec.getAVCodecContext();
-
AVPacket& packet = codedFrame.getAVPacket();
- if((avCodecContext.coded_frame) && (avCodecContext.coded_frame->pts != (int)AV_NOPTS_VALUE))
+ const AVFrame& srcAvFrame = sourceFrame.getAVFrame();
+ if(srcAvFrame.pts != (int)AV_NOPTS_VALUE)
{
- packet.pts = avCodecContext.coded_frame->pts;
+ packet.pts = srcAvFrame.pts;
}
- if(avCodecContext.coded_frame && avCodecContext.coded_frame->key_frame)
+ if(srcAvFrame.key_frame)
{
packet.flags |= AV_PKT_FLAG_KEY;
}
- return encode(&sourceFrame.getAVFrame(), packet);
+ return encode(&srcAvFrame, packet);
}
bool AudioEncoder::encodeFrame(CodedData& codedFrame)
@@ -120,7 +120,23 @@ bool AudioEncoder::encode(const AVFrame* decodedData, AVPacket& encodedData)
encodedData.data = NULL;
AVCodecContext& avCodecContext = _codec.getAVCodecContext();
-#if LIBAVCODEC_VERSION_MAJOR > 53
+#if LIBAVCODEC_VERSION_MAJOR > 58
+ int ret = avcodec_send_frame(&avCodecContext, decodedData);
+
+ if(ret != 0)
+ throw std::runtime_error("Error sending audio frame to encoder: " + getDescriptionFromErrorCode(ret));
+
+ ret = avcodec_receive_packet(&avCodecContext, &encodedData);
+
+ if (ret == 0)
+ return true;
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ return false;
+
+ throw std::runtime_error("Error receiving audio frame from encoder: " + getDescriptionFromErrorCode(ret));
+
+#elif LIBAVCODEC_VERSION_MAJOR > 53
int gotPacket = 0;
const int ret = avcodec_encode_audio2(&avCodecContext, &encodedData, decodedData, &gotPacket);
if(ret != 0)
diff --git a/src/AvTranscoder/encoder/AudioEncoder.hpp b/src/AvTranscoder/encoder/AudioEncoder.hpp
index 0c8e0a55..7a39abc2 100644
--- a/src/AvTranscoder/encoder/AudioEncoder.hpp
+++ b/src/AvTranscoder/encoder/AudioEncoder.hpp
@@ -1,7 +1,7 @@
#ifndef _AV_TRANSCODER_ENCODER_AUDIO_ENCODER_HPP_
#define _AV_TRANSCODER_ENCODER_AUDIO_ENCODER_HPP_
-#include "IEncoder.hpp"
+#include
#include
#include
diff --git a/src/AvTranscoder/encoder/VideoEncoder.cpp b/src/AvTranscoder/encoder/VideoEncoder.cpp
index c6d43b66..d8662ff8 100644
--- a/src/AvTranscoder/encoder/VideoEncoder.cpp
+++ b/src/AvTranscoder/encoder/VideoEncoder.cpp
@@ -77,7 +77,11 @@ void VideoEncoder::setupEncoder(const ProfileLoader::Profile& profile)
if(profile.count(constants::avProfileProcessStat))
{
LOG_INFO("SetUp video encoder to compute statistics during process")
+#ifdef AV_CODEC_FLAG_PSNR
+ encoderFlags |= AV_CODEC_FLAG_PSNR;
+#else
encoderFlags |= CODEC_FLAG_PSNR;
+#endif
}
_codec.getAVCodecContext().flags |= encoderFlags;
_codec.openCodec();
@@ -106,20 +110,19 @@ void VideoEncoder::setupEncoder(const ProfileLoader::Profile& profile)
bool VideoEncoder::encodeFrame(const IFrame& sourceFrame, CodedData& codedFrame)
{
- AVCodecContext& avCodecContext = _codec.getAVCodecContext();
-
AVPacket& packet = codedFrame.getAVPacket();
- if((avCodecContext.coded_frame) && (avCodecContext.coded_frame->pts != (int)AV_NOPTS_VALUE))
+ const AVFrame& srcAvFrame = sourceFrame.getAVFrame();
+ if(srcAvFrame.pts != (int)AV_NOPTS_VALUE)
{
- packet.pts = avCodecContext.coded_frame->pts;
+ packet.pts = srcAvFrame.pts;
}
- if(avCodecContext.coded_frame && avCodecContext.coded_frame->key_frame)
+ if(srcAvFrame.key_frame)
{
packet.flags |= AV_PKT_FLAG_KEY;
}
- return encode(&sourceFrame.getAVFrame(), packet);
+ return encode(&srcAvFrame, packet);
}
bool VideoEncoder::encodeFrame(CodedData& codedFrame)
@@ -133,7 +136,23 @@ bool VideoEncoder::encode(const AVFrame* decodedData, AVPacket& encodedData)
encodedData.data = NULL;
AVCodecContext& avCodecContext = _codec.getAVCodecContext();
-#if LIBAVCODEC_VERSION_MAJOR > 53
+#if LIBAVCODEC_VERSION_MAJOR > 58
+ int ret = avcodec_send_frame(&avCodecContext, decodedData);
+
+ if (ret != 0 && ret != AVERROR_EOF)
+ throw std::runtime_error("Error sending video frame to encoder: " + getDescriptionFromErrorCode(ret));
+
+ ret = avcodec_receive_packet(&avCodecContext, &encodedData);
+
+ if (ret == 0)
+ return true;
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ return false;
+
+ throw std::runtime_error("Error receiving video frame from encoder: " + getDescriptionFromErrorCode(ret));
+
+#elif LIBAVCODEC_VERSION_MAJOR > 53
int gotPacket = 0;
const int ret = avcodec_encode_video2(&avCodecContext, &encodedData, decodedData, &gotPacket);
if(ret != 0)
@@ -141,6 +160,7 @@ bool VideoEncoder::encode(const AVFrame* decodedData, AVPacket& encodedData)
throw std::runtime_error("Encode video frame error: avcodec encode video frame - " +
getDescriptionFromErrorCode(ret));
}
+
return gotPacket == 1;
#else
const int ret = avcodec_encode_video(&avCodecContext, encodedData.data, encodedData.size, decodedData);
diff --git a/src/AvTranscoder/encoder/VideoEncoder.hpp b/src/AvTranscoder/encoder/VideoEncoder.hpp
index d12035e6..6f7493b6 100644
--- a/src/AvTranscoder/encoder/VideoEncoder.hpp
+++ b/src/AvTranscoder/encoder/VideoEncoder.hpp
@@ -1,7 +1,7 @@
#ifndef _AV_TRANSCODER_ENCODER_VIDEO_ENCODER_HPP_
#define _AV_TRANSCODER_ENCODER_VIDEO_ENCODER_HPP_
-#include "IEncoder.hpp"
+#include
#include
#include
diff --git a/src/AvTranscoder/file/FormatContext.cpp b/src/AvTranscoder/file/FormatContext.cpp
index 51d78f4e..cd423e85 100644
--- a/src/AvTranscoder/file/FormatContext.cpp
+++ b/src/AvTranscoder/file/FormatContext.cpp
@@ -46,10 +46,6 @@ FormatContext::~FormatContext()
if(!_avFormatContext)
return;
- // free the streams added
- for(std::vector::iterator it = _avStreamAllocated.begin(); it != _avStreamAllocated.end(); ++it)
- avcodec_close((*it)->codec);
-
// free the format context
if(_isOpen)
avformat_close_input(&_avFormatContext);
@@ -151,7 +147,7 @@ AVStream& FormatContext::addAVStream(const AVCodec& avCodec)
bool FormatContext::seek(const uint64_t position, const int flag)
{
- LOG_INFO("Seek in '" << _avFormatContext->filename << "' at " << position << " with flag '" << flag << "'")
+ LOG_INFO("Seek in '" << _avFormatContext->url << "' at " << position << " with flag '" << flag << "'")
const int err = av_seek_frame(_avFormatContext, -1, position, flag);
if(err < 0)
{
@@ -186,12 +182,13 @@ AVStream& FormatContext::getAVStream(size_t index) const
void FormatContext::setFilename(const std::string& filename)
{
- strcpy(&_avFormatContext->filename[0], filename.c_str());
+ _avFormatContext->url = (char*)av_malloc(filename.size());
+ strcpy(_avFormatContext->url, filename.c_str());
}
void FormatContext::setOutputFormat(const std::string& filename, const std::string& shortName, const std::string& mimeType)
{
- AVOutputFormat* oformat = av_guess_format(shortName.c_str(), filename.c_str(), mimeType.c_str());
+ const AVOutputFormat* oformat = av_guess_format(shortName.c_str(), filename.c_str(), mimeType.c_str());
if(!oformat)
{
std::string msg("Unable to find format for ");
diff --git a/src/AvTranscoder/file/FormatContext.hpp b/src/AvTranscoder/file/FormatContext.hpp
index 0a33bbe1..b4283e19 100644
--- a/src/AvTranscoder/file/FormatContext.hpp
+++ b/src/AvTranscoder/file/FormatContext.hpp
@@ -113,8 +113,8 @@ class AvExport FormatContext
#ifndef SWIG
AVFormatContext& getAVFormatContext() const { return *_avFormatContext; }
- AVOutputFormat& getAVOutputFormat() const { return *_avFormatContext->oformat; }
- AVInputFormat& getAVInputFormat() const { return *_avFormatContext->iformat; }
+ const AVOutputFormat& getAVOutputFormat() const { return *_avFormatContext->oformat; }
+ const AVInputFormat& getAVInputFormat() const { return *_avFormatContext->iformat; }
AVIOContext& getAVIOContext() const { return *_avFormatContext->pb; }
AVDictionary& getAVMetaData() const { return *_avFormatContext->metadata; }
AVStream& getAVStream(size_t index) const;
diff --git a/src/AvTranscoder/file/IOutputFile.hpp b/src/AvTranscoder/file/IOutputFile.hpp
index 4d9dc233..c070cdb7 100644
--- a/src/AvTranscoder/file/IOutputFile.hpp
+++ b/src/AvTranscoder/file/IOutputFile.hpp
@@ -51,6 +51,15 @@ class AvExport IOutputFile
throw std::logic_error("function is not implemented");
}
+ /**
+ * @brief Add a custom output stream
+ * @param iCodecDesc description of output codec
+ **/
+ virtual IOutputStream& addCustomStream(const ICodec& iCodecDesc)
+ {
+ throw std::logic_error("function is not implemented");
+ }
+
/**
* @brief Write the header of file (if necessary)
**/
diff --git a/src/AvTranscoder/file/OutputFile.cpp b/src/AvTranscoder/file/OutputFile.cpp
index 8d292b95..49711abc 100644
--- a/src/AvTranscoder/file/OutputFile.cpp
+++ b/src/AvTranscoder/file/OutputFile.cpp
@@ -3,6 +3,7 @@
#include
#include
+#include
#ifndef FF_INPUT_BUFFER_PADDING_SIZE
#define FF_INPUT_BUFFER_PADDING_SIZE 16
@@ -35,31 +36,33 @@ IOutputStream& OutputFile::addVideoStream(const VideoCodec& videoDesc)
{
AVStream& stream = _formatContext.addAVStream(videoDesc.getAVCodec());
- stream.codec->width = videoDesc.getAVCodecContext().width;
- stream.codec->height = videoDesc.getAVCodecContext().height;
- stream.codec->bit_rate = videoDesc.getAVCodecContext().bit_rate;
- stream.codec->pix_fmt = videoDesc.getAVCodecContext().pix_fmt;
- stream.codec->profile = videoDesc.getAVCodecContext().profile;
- stream.codec->level = videoDesc.getAVCodecContext().level;
- stream.codec->field_order = videoDesc.getAVCodecContext().field_order;
+ stream.codecpar->codec_type = videoDesc.getAVCodecContext().codec_type;
+ stream.codecpar->codec_id = videoDesc.getAVCodecContext().codec_id;
+ stream.codecpar->codec_tag = videoDesc.getAVCodecContext().codec_tag;
- stream.codec->colorspace = videoDesc.getAVCodecContext().colorspace;
- stream.codec->color_primaries = videoDesc.getAVCodecContext().color_primaries;
- stream.codec->color_range = videoDesc.getAVCodecContext().color_range;
- stream.codec->color_trc = videoDesc.getAVCodecContext().color_trc;
- stream.codec->chroma_sample_location = videoDesc.getAVCodecContext().chroma_sample_location;
+ stream.codecpar->width = videoDesc.getAVCodecContext().width;
+ stream.codecpar->height = videoDesc.getAVCodecContext().height;
+ stream.codecpar->bit_rate = videoDesc.getAVCodecContext().bit_rate;
+ stream.codecpar->format = videoDesc.getAVCodecContext().pix_fmt;
+ stream.codecpar->profile = videoDesc.getAVCodecContext().profile;
+ stream.codecpar->level = videoDesc.getAVCodecContext().level;
+ stream.codecpar->field_order = videoDesc.getAVCodecContext().field_order;
+
+ stream.codecpar->color_space = videoDesc.getAVCodecContext().colorspace;
+ stream.codecpar->color_primaries = videoDesc.getAVCodecContext().color_primaries;
+ stream.codecpar->color_range = videoDesc.getAVCodecContext().color_range;
+ stream.codecpar->color_trc = videoDesc.getAVCodecContext().color_trc;
+ stream.codecpar->chroma_location = videoDesc.getAVCodecContext().chroma_sample_location;
setOutputStream(stream, videoDesc);
// need to set the time_base on the AVCodecContext and the AVStream
// compensating the frame rate with the ticks_per_frame and keeping
// a coherent reading speed.
- av_reduce(&stream.codec->time_base.num, &stream.codec->time_base.den,
+ av_reduce(&stream.time_base.num, &stream.time_base.den,
videoDesc.getAVCodecContext().time_base.num * videoDesc.getAVCodecContext().ticks_per_frame,
videoDesc.getAVCodecContext().time_base.den, INT_MAX);
- stream.time_base = stream.codec->time_base;
-
OutputStream* outputStream = new OutputStream(*this, _formatContext.getNbStreams() - 1);
_outputStreams.push_back(outputStream);
@@ -70,16 +73,20 @@ IOutputStream& OutputFile::addAudioStream(const AudioCodec& audioDesc)
{
AVStream& stream = _formatContext.addAVStream(audioDesc.getAVCodec());
- stream.codec->sample_rate = audioDesc.getAVCodecContext().sample_rate;
- stream.codec->channels = audioDesc.getAVCodecContext().channels;
- stream.codec->channel_layout = audioDesc.getAVCodecContext().channel_layout;
- stream.codec->sample_fmt = audioDesc.getAVCodecContext().sample_fmt;
- stream.codec->frame_size = audioDesc.getAVCodecContext().frame_size;
+ stream.codecpar->codec_type = audioDesc.getAVCodecContext().codec_type;
+ stream.codecpar->codec_id = audioDesc.getAVCodecContext().codec_id;
+ stream.codecpar->codec_tag = audioDesc.getAVCodecContext().codec_tag;
+
+ stream.codecpar->sample_rate = audioDesc.getAVCodecContext().sample_rate;
+ stream.codecpar->channels = audioDesc.getAVCodecContext().channels;
+ stream.codecpar->channel_layout = audioDesc.getAVCodecContext().channel_layout;
+ stream.codecpar->format = audioDesc.getAVCodecContext().sample_fmt;
+ stream.codecpar->frame_size = audioDesc.getAVCodecContext().frame_size;
setOutputStream(stream, audioDesc);
// need to set the time_base on the AVCodecContext of the AVStream
- av_reduce(&stream.codec->time_base.num, &stream.codec->time_base.den, audioDesc.getAVCodecContext().time_base.num,
+ av_reduce(&stream.time_base.num, &stream.time_base.den, audioDesc.getAVCodecContext().time_base.num,
audioDesc.getAVCodecContext().time_base.den, INT_MAX);
OutputStream* outputStream = new OutputStream(*this, _formatContext.getNbStreams() - 1);
@@ -88,6 +95,29 @@ IOutputStream& OutputFile::addAudioStream(const AudioCodec& audioDesc)
return *outputStream;
}
+IOutputStream& OutputFile::addCustomStream(const ICodec& iCodecDesc)
+{
+ AVStream& stream = _formatContext.addAVStream(iCodecDesc.getAVCodec());
+
+ stream.codecpar->codec_type = iCodecDesc.getAVCodecContext().codec_type;
+ stream.codecpar->codec_id = iCodecDesc.getAVCodecContext().codec_id;
+ stream.codecpar->codec_tag = iCodecDesc.getAVCodecContext().codec_tag;
+
+ stream.codecpar->sample_rate = 48000;
+ stream.codecpar->channels = 1;
+ stream.codecpar->channel_layout = AV_CH_LAYOUT_MONO;
+ stream.codecpar->format = AV_SAMPLE_FMT_S32;
+ stream.codecpar->frame_size = 1920;
+
+ // need to set the time_base on the AVCodecContext of the AVStream
+ av_reduce(&stream.time_base.num, &stream.time_base.den, 1, 1, INT_MAX);
+
+ OutputStream* outputStream = new OutputStream(*this, _formatContext.getNbStreams() - 1);
+ _outputStreams.push_back(outputStream);
+
+ return *outputStream;
+}
+
IOutputStream& OutputFile::addDataStream(const DataCodec& dataDesc)
{
_formatContext.addAVStream(dataDesc.getAVCodec());
@@ -117,7 +147,7 @@ IOutputStream& OutputFile::getStream(const size_t streamIndex)
std::string OutputFile::getFilename() const
{
- return std::string(_formatContext.getAVFormatContext().filename);
+ return std::string(_formatContext.getAVFormatContext().url);
}
std::string OutputFile::getFormatName() const
@@ -169,14 +199,13 @@ bool OutputFile::beginWrap()
IOutputStream::EWrappingStatus OutputFile::wrap(const CodedData& data, const size_t streamIndex)
{
if(!data.getSize())
- return IOutputStream::eWrappingSuccess;
+ return IOutputStream::eWrappingSkip;
LOG_DEBUG("Wrap on stream " << streamIndex << " (" << data.getSize() << " bytes for frame "
<< _frameCount.at(streamIndex) << ")")
// Packet to wrap
- AVPacket packet;
- av_init_packet(&packet);
+ AVPacket packet = *av_packet_alloc();
packet.stream_index = streamIndex;
packet.data = (uint8_t*)data.getData();
packet.size = data.getSize();
@@ -200,12 +229,12 @@ IOutputStream::EWrappingStatus OutputFile::wrap(const CodedData& data, const siz
packet.dts = av_rescale_q(data.getAVPacket().dts, srcTimeBase, dstTimeBase);
}
// add stream PTS if already incremented
- const int currentStreamPTS = _outputStreams.at(streamIndex)->getStreamPTS();
- if(packet.pts != AV_NOPTS_VALUE && packet.pts < currentStreamPTS)
- {
- packet.pts += currentStreamPTS;
- packet.dts += currentStreamPTS;
- }
+ // const int currentStreamPTS = _outputStreams.at(streamIndex)->getStreamPTS();
+ // if(packet.pts != AV_NOPTS_VALUE && packet.pts < currentStreamPTS)
+ // {
+ // packet.pts += currentStreamPTS;
+ // packet.dts += currentStreamPTS;
+ // }
}
// copy duration of packet wrapped
@@ -329,25 +358,35 @@ void OutputFile::setupRemainingWrappingOptions()
void OutputFile::setOutputStream(AVStream& avStream, const ICodec& codec)
{
+#if LIBAVCODEC_VERSION_MAJOR < 59
// depending on the format, place global headers in extradata instead of every keyframe
if(_formatContext.getAVOutputFormat().flags & AVFMT_GLOBALHEADER)
{
+#ifdef AV_CODEC_FLAG_GLOBAL_HEADER
+ avStream.codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+#else
avStream.codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+#endif
}
// if the codec is experimental, allow it
+#ifdef AV_CODEC_CAP_EXPERIMENTAL
+ if(codec.getAVCodec().capabilities & AV_CODEC_CAP_EXPERIMENTAL)
+#else
if(codec.getAVCodec().capabilities & CODEC_CAP_EXPERIMENTAL)
+#endif
{
LOG_WARN("This codec is considered experimental by libav/ffmpeg:" << codec.getCodecName());
avStream.codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
}
+#endif
// some codecs need/can use extradata to decode
uint8_t* srcExtradata = codec.getAVCodecContext().extradata;
const int srcExtradataSize = codec.getAVCodecContext().extradata_size;
- avStream.codec->extradata = (uint8_t*)av_malloc(srcExtradataSize + FF_INPUT_BUFFER_PADDING_SIZE);
- memcpy(avStream.codec->extradata, srcExtradata, srcExtradataSize);
- memset(((uint8_t*)avStream.codec->extradata) + srcExtradataSize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- avStream.codec->extradata_size = codec.getAVCodecContext().extradata_size;
+ avStream.codecpar->extradata = (uint8_t*)av_malloc(srcExtradataSize + FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(avStream.codecpar->extradata, srcExtradata, srcExtradataSize);
+ memset(((uint8_t*)avStream.codecpar->extradata) + srcExtradataSize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ avStream.codecpar->extradata_size = codec.getAVCodecContext().extradata_size;
}
}
diff --git a/src/AvTranscoder/file/OutputFile.hpp b/src/AvTranscoder/file/OutputFile.hpp
index 4a18e4c0..c8fefc3b 100644
--- a/src/AvTranscoder/file/OutputFile.hpp
+++ b/src/AvTranscoder/file/OutputFile.hpp
@@ -37,6 +37,7 @@ class AvExport OutputFile : public IOutputFile
IOutputStream& addVideoStream(const VideoCodec& videoDesc);
IOutputStream& addAudioStream(const AudioCodec& audioDesc);
IOutputStream& addDataStream(const DataCodec& dataDesc);
+ IOutputStream& addCustomStream(const ICodec& iCodecDesc);
/**
* @brief Open ressource, write header, and setup specific wrapping options given when call setupWrapping.
diff --git a/src/AvTranscoder/filter/Filter.cpp b/src/AvTranscoder/filter/Filter.cpp
index 07cc30d8..c5ac8fb4 100644
--- a/src/AvTranscoder/filter/Filter.cpp
+++ b/src/AvTranscoder/filter/Filter.cpp
@@ -15,7 +15,7 @@ Filter::Filter(const std::string& name, const std::string& options, const std::s
, _options(options)
, _instanceName(instanceName.empty() ? name : instanceName)
{
- _filter = avfilter_get_by_name(name.c_str());
+ _filter = (AVFilter*)avfilter_get_by_name(name.c_str());
if(!_filter)
{
std::string msg("Cannot find filter ");
diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp
index 8b960ef9..58f62fdb 100644
--- a/src/AvTranscoder/filter/FilterGraph.cpp
+++ b/src/AvTranscoder/filter/FilterGraph.cpp
@@ -211,7 +211,7 @@ bool FilterGraph::areInputFrameSizesEqual(const std::vector