diff --git a/app/avPlay/AvReader.cpp b/app/avPlay/AvReader.cpp index f51039e3..3febbebe 100644 --- a/app/avPlay/AvReader.cpp +++ b/app/avPlay/AvReader.cpp @@ -17,7 +17,7 @@ AvReader::AvReader( const std::string& filename ) _inputFile.activateStream( _videoStream ); _inputVideo = new avtranscoder::VideoDecoder( _inputFile.getStream( _videoStream ) ); - _inputVideo->setup(); + _inputVideo->setupDecoder(); _sourceImage = new avtranscoder::VideoFrame( _inputFile.getStream( _videoStream ).getVideoCodec().getVideoFrameDesc() ); diff --git a/src/AvTranscoder/avTranscoder.i b/src/AvTranscoder/avTranscoder.i index c394ed13..a4dadcd0 100644 --- a/src/AvTranscoder/avTranscoder.i +++ b/src/AvTranscoder/avTranscoder.i @@ -36,4 +36,5 @@ %include "AvTranscoder/encoder/encoder.i" %include "AvTranscoder/transform/transform.i" %include "AvTranscoder/file/file.i" +%include "AvTranscoder/stat/stat.i" %include "AvTranscoder/transcoder/transcoder.i" diff --git a/src/AvTranscoder/decoder/AudioDecoder.cpp b/src/AvTranscoder/decoder/AudioDecoder.cpp index fe6391e2..c0413222 100644 --- a/src/AvTranscoder/decoder/AudioDecoder.cpp +++ b/src/AvTranscoder/decoder/AudioDecoder.cpp @@ -50,8 +50,39 @@ AudioDecoder::~AudioDecoder() } -void AudioDecoder::setup() +void AudioDecoder::setupDecoder( const ProfileLoader::Profile& profile ) { + LOG_DEBUG( "Set profile of audio decoder with:\n" << profile ) + + AudioCodec& codec = _inputStream->getAudioCodec(); + + // set threads before any other options + if( profile.count( constants::avProfileThreads ) ) + codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); + else + codec.getOption( constants::avProfileThreads ).setString( "auto" ); + + // set decoder options + for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) + { + if( (*it).first == constants::avProfileIdentificator || + (*it).first == constants::avProfileIdentificatorHuman || + (*it).first == constants::avProfileType || + (*it).first == constants::avProfileThreads ) + continue; + + try + { + Option& decodeOption = codec.getOption( (*it).first ); + decodeOption.setString( (*it).second ); + } + catch( std::exception& e ) + { + LOG_WARN( "AudioDecoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) + } + } + + // open decoder _inputStream->getAudioCodec().openCodec(); } @@ -145,37 +176,4 @@ bool AudioDecoder::decodeNextFrame() return true; } -void AudioDecoder::setProfile( const ProfileLoader::Profile& profile ) -{ - LOG_DEBUG( "Set profile of audio decoder with:\n" << profile ) - - AudioCodec& codec = _inputStream->getAudioCodec(); - - // set threads before any other options - if( profile.count( constants::avProfileThreads ) ) - codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); - else - codec.getOption( constants::avProfileThreads ).setString( "auto" ); - - // set decoder options - for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) - { - if( (*it).first == constants::avProfileIdentificator || - (*it).first == constants::avProfileIdentificatorHuman || - (*it).first == constants::avProfileType || - (*it).first == constants::avProfileThreads ) - continue; - - try - { - Option& decodeOption = codec.getOption( (*it).first ); - decodeOption.setString( (*it).second ); - } - catch( std::exception& e ) - { - LOG_WARN( "AudioDecoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) - } - } -} - } diff --git a/src/AvTranscoder/decoder/AudioDecoder.hpp b/src/AvTranscoder/decoder/AudioDecoder.hpp index 290ae825..b9fc3300 100644 --- a/src/AvTranscoder/decoder/AudioDecoder.hpp +++ b/src/AvTranscoder/decoder/AudioDecoder.hpp @@ -2,7 +2,6 @@ #define _AV_TRANSCODER_ESSENCE_STREAM_AV_INPUT_AUDIO_HPP_ #include "IDecoder.hpp" -#include struct AVFrame; @@ -17,13 +16,11 @@ class AvExport AudioDecoder : public IDecoder AudioDecoder( InputStream& inputStream ); ~AudioDecoder(); - void setup(); + void setupDecoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ); bool decodeNextFrame( Frame& frameBuffer ); bool decodeNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); - void setProfile( const ProfileLoader::Profile& profile ); - private: bool decodeNextFrame(); diff --git a/src/AvTranscoder/decoder/AudioGenerator.hpp b/src/AvTranscoder/decoder/AudioGenerator.hpp index c6ef8f4b..b9defc01 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.hpp +++ b/src/AvTranscoder/decoder/AudioGenerator.hpp @@ -16,7 +16,7 @@ class AvExport AudioGenerator : public IDecoder ~AudioGenerator(); - void setup() {} + void setupDecoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ) {} bool decodeNextFrame( Frame& frameBuffer ); bool decodeNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); diff --git a/src/AvTranscoder/decoder/IDecoder.hpp b/src/AvTranscoder/decoder/IDecoder.hpp index 62084afd..bbbf4fa8 100644 --- a/src/AvTranscoder/decoder/IDecoder.hpp +++ b/src/AvTranscoder/decoder/IDecoder.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace avtranscoder { @@ -13,9 +14,11 @@ class AvExport IDecoder virtual ~IDecoder() {}; /** - * @brief Open the decoder + * @brief Setup the decoder + * @param profile: set decoder parameters from the given profile + * @note Open the decoder. */ - virtual void setup() = 0; + virtual void setupDecoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ) = 0; /** * @brief Decode next frame diff --git a/src/AvTranscoder/decoder/VideoDecoder.cpp b/src/AvTranscoder/decoder/VideoDecoder.cpp index b551a334..9ea2549a 100644 --- a/src/AvTranscoder/decoder/VideoDecoder.cpp +++ b/src/AvTranscoder/decoder/VideoDecoder.cpp @@ -48,8 +48,39 @@ VideoDecoder::~VideoDecoder() } } -void VideoDecoder::setup() +void VideoDecoder::setupDecoder( const ProfileLoader::Profile& profile ) { + LOG_DEBUG( "Set profile of video decoder with:\n" << profile ) + + VideoCodec& codec = _inputStream->getVideoCodec(); + + // set threads before any other options + if( profile.count( constants::avProfileThreads ) ) + codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); + else + codec.getOption( constants::avProfileThreads ).setString( "auto" ); + + // set decoder options + for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) + { + if( (*it).first == constants::avProfileIdentificator || + (*it).first == constants::avProfileIdentificatorHuman || + (*it).first == constants::avProfileType || + (*it).first == constants::avProfileThreads ) + continue; + + try + { + Option& decodeOption = codec.getOption( (*it).first ); + decodeOption.setString( (*it).second ); + } + catch( std::exception& e ) + { + LOG_WARN( "VideoDecoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) + } + } + + // open decoder _inputStream->getVideoCodec().openCodec(); } @@ -104,37 +135,4 @@ void VideoDecoder::flushDecoder() avcodec_flush_buffers( &_inputStream->getVideoCodec().getAVCodecContext() ); } -void VideoDecoder::setProfile( const ProfileLoader::Profile& profile ) -{ - LOG_DEBUG( "Set profile of video decoder with:\n" << profile ) - - VideoCodec& codec = _inputStream->getVideoCodec(); - - // set threads before any other options - if( profile.count( constants::avProfileThreads ) ) - codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); - else - codec.getOption( constants::avProfileThreads ).setString( "auto" ); - - // set decoder options - for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) - { - if( (*it).first == constants::avProfileIdentificator || - (*it).first == constants::avProfileIdentificatorHuman || - (*it).first == constants::avProfileType || - (*it).first == constants::avProfileThreads ) - continue; - - try - { - Option& decodeOption = codec.getOption( (*it).first ); - decodeOption.setString( (*it).second ); - } - catch( std::exception& e ) - { - LOG_WARN( "VideoDecoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) - } - } -} - } diff --git a/src/AvTranscoder/decoder/VideoDecoder.hpp b/src/AvTranscoder/decoder/VideoDecoder.hpp index 936fdabd..72dfb9cd 100644 --- a/src/AvTranscoder/decoder/VideoDecoder.hpp +++ b/src/AvTranscoder/decoder/VideoDecoder.hpp @@ -2,7 +2,6 @@ #define _AV_TRANSCODER_DECODER_VIDEO_DECODER_HPP_ #include "IDecoder.hpp" -#include struct AVFrame; @@ -16,16 +15,14 @@ class AvExport VideoDecoder : public IDecoder public: VideoDecoder( InputStream& inputStream ); ~VideoDecoder(); - - void setup(); + + void setupDecoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ); bool decodeNextFrame( Frame& frameBuffer ); bool decodeNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); void flushDecoder(); - - void setProfile( const ProfileLoader::Profile& profile ); - + private: bool decodeNextFrame(); diff --git a/src/AvTranscoder/decoder/VideoGenerator.hpp b/src/AvTranscoder/decoder/VideoGenerator.hpp index cd92b7c6..ce7cb4fd 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.hpp +++ b/src/AvTranscoder/decoder/VideoGenerator.hpp @@ -16,7 +16,7 @@ class AvExport VideoGenerator : public IDecoder ~VideoGenerator(); - void setup() {} + void setupDecoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ) {} bool decodeNextFrame( Frame& frameBuffer ); bool decodeNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); diff --git a/src/AvTranscoder/encoder/AudioEncoder.cpp b/src/AvTranscoder/encoder/AudioEncoder.cpp index c10fbd4c..4cfae412 100644 --- a/src/AvTranscoder/encoder/AudioEncoder.cpp +++ b/src/AvTranscoder/encoder/AudioEncoder.cpp @@ -35,9 +35,69 @@ AudioEncoder::~AudioEncoder() #endif } -void AudioEncoder::setup() +void AudioEncoder::setupAudioEncoder( const AudioFrameDesc& frameDesc, const ProfileLoader::Profile& profile ) { + LOG_DEBUG( "Set profile of audio encoder with:\n" << profile ) + + // set sampleRate, number of channels, sample format + _codec.setAudioParameters( frameDesc ); + + // setup encoder + setupEncoder( profile ); +} + +void AudioEncoder::setupEncoder( const ProfileLoader::Profile& profile ) +{ + // set threads before any other options + if( profile.count( constants::avProfileThreads ) ) + _codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); + else + _codec.getOption( constants::avProfileThreads ).setString( "auto" ); + + + // set encoder options + for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) + { + if( (*it).first == constants::avProfileIdentificator || + (*it).first == constants::avProfileIdentificatorHuman || + (*it).first == constants::avProfileType || + (*it).first == constants::avProfileCodec || + (*it).first == constants::avProfileSampleFormat || + (*it).first == constants::avProfileThreads ) + continue; + + try + { + Option& encodeOption = _codec.getOption( (*it).first ); + encodeOption.setString( (*it).second ); + } + catch( std::exception& e ) + {} + } + + // open encoder _codec.openCodec(); + + for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) + { + if( (*it).first == constants::avProfileIdentificator || + (*it).first == constants::avProfileIdentificatorHuman || + (*it).first == constants::avProfileType || + (*it).first == constants::avProfileCodec || + (*it).first == constants::avProfileSampleFormat || + (*it).first == constants::avProfileThreads ) + continue; + + try + { + Option& encodeOption = _codec.getOption( (*it).first ); + encodeOption.setString( (*it).second ); + } + catch( std::exception& e ) + { + LOG_WARN( "AudioEncoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) + } + } } bool AudioEncoder::encodeFrame( const Frame& sourceFrame, Frame& codedFrame ) @@ -133,63 +193,5 @@ bool AudioEncoder::encodeFrame( Frame& codedFrame ) #endif } -void AudioEncoder::setProfile( const ProfileLoader::Profile& profile, const AudioFrameDesc& frameDesc ) -{ - LOG_DEBUG( "Set profile of audio encoder with:\n" << profile ) - - // set sampleRate, number of channels, sample format - _codec.setAudioParameters( frameDesc ); - - // set threads before any other options - if( profile.count( constants::avProfileThreads ) ) - _codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); - else - _codec.getOption( constants::avProfileThreads ).setString( "auto" ); - - - // set encoder options - for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) - { - if( (*it).first == constants::avProfileIdentificator || - (*it).first == constants::avProfileIdentificatorHuman || - (*it).first == constants::avProfileType || - (*it).first == constants::avProfileCodec || - (*it).first == constants::avProfileSampleFormat || - (*it).first == constants::avProfileThreads ) - continue; - - try - { - Option& encodeOption = _codec.getOption( (*it).first ); - encodeOption.setString( (*it).second ); - } - catch( std::exception& e ) - {} - } - - setup(); - - for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) - { - if( (*it).first == constants::avProfileIdentificator || - (*it).first == constants::avProfileIdentificatorHuman || - (*it).first == constants::avProfileType || - (*it).first == constants::avProfileCodec || - (*it).first == constants::avProfileSampleFormat || - (*it).first == constants::avProfileThreads ) - continue; - - try - { - Option& encodeOption = _codec.getOption( (*it).first ); - encodeOption.setString( (*it).second ); - } - catch( std::exception& e ) - { - LOG_WARN( "AudioEncoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) - } - } -} - } diff --git a/src/AvTranscoder/encoder/AudioEncoder.hpp b/src/AvTranscoder/encoder/AudioEncoder.hpp index f64d7f1f..376c1c0f 100644 --- a/src/AvTranscoder/encoder/AudioEncoder.hpp +++ b/src/AvTranscoder/encoder/AudioEncoder.hpp @@ -13,8 +13,9 @@ class AvExport AudioEncoder : public IEncoder public: AudioEncoder( const std::string& audioCodecName ); ~AudioEncoder(); - - void setup(); + + void setupAudioEncoder( const AudioFrameDesc& frameDesc, const ProfileLoader::Profile& profile = ProfileLoader::Profile() ); + void setupEncoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ); bool encodeFrame( const Frame& sourceFrame, Frame& codedFrame ); bool encodeFrame( Frame& codedFrame ); @@ -22,8 +23,6 @@ class AvExport AudioEncoder : public IEncoder ICodec& getCodec() { return _codec; } AudioCodec& getAudioCodec() { return _codec; } - void setProfile( const ProfileLoader::Profile& profile, const AudioFrameDesc& frameDesc ); - private: AudioCodec _codec; AVFrame* _frame; ///< Contains the encoded data to pass to the Frame when encodeFrame diff --git a/src/AvTranscoder/encoder/IEncoder.hpp b/src/AvTranscoder/encoder/IEncoder.hpp index 46c82c18..ac188704 100644 --- a/src/AvTranscoder/encoder/IEncoder.hpp +++ b/src/AvTranscoder/encoder/IEncoder.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace avtranscoder { @@ -14,8 +15,10 @@ class AvExport IEncoder /** * @brief Setup the encoder + * @param profile: set encoder parameters from the given profile + * @note Open the encoder. */ - virtual void setup() = 0; + virtual void setupEncoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ) = 0; /** * @brief Encode a new frame, and get coded frame diff --git a/src/AvTranscoder/encoder/VideoEncoder.cpp b/src/AvTranscoder/encoder/VideoEncoder.cpp index d0bd0064..b7d4d025 100644 --- a/src/AvTranscoder/encoder/VideoEncoder.cpp +++ b/src/AvTranscoder/encoder/VideoEncoder.cpp @@ -36,11 +36,83 @@ VideoEncoder::~VideoEncoder() #endif } -void VideoEncoder::setup() +void VideoEncoder::setupVideoEncoder( const VideoFrameDesc& frameDesc, const ProfileLoader::Profile& profile ) { - _codec.openCodec(); + LOG_DEBUG( "Set profile of video encoder with:\n" << profile ) + + // set width, height, pixel format, fps + _codec.setImageParameters( frameDesc ); + + // setup encoder + setupEncoder( profile ); } +void VideoEncoder::setupEncoder( const ProfileLoader::Profile& profile ) +{ + // set threads before any other options + if( profile.count( constants::avProfileThreads ) ) + _codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); + else + _codec.getOption( constants::avProfileThreads ).setString( "auto" ); + + // set encoder options + for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) + { + if( (*it).first == constants::avProfileIdentificator || + (*it).first == constants::avProfileIdentificatorHuman || + (*it).first == constants::avProfileType || + (*it).first == constants::avProfileCodec || + (*it).first == constants::avProfileWidth || + (*it).first == constants::avProfileHeight || + (*it).first == constants::avProfilePixelFormat || + (*it).first == constants::avProfileFrameRate || + (*it).first == constants::avProfileThreads ) + continue; + + try + { + Option& encodeOption = _codec.getOption( (*it).first ); + encodeOption.setString( (*it).second ); + } + catch( std::exception& e ) + {} + } + + // open encoder + int encoderFlags = 0; + if( profile.count( constants::avProfileProcessStat ) ) + { + LOG_INFO( "SetUp video encoder to compute statistics during process" ) + encoderFlags |= CODEC_FLAG_PSNR; + } + _codec.getAVCodecContext().flags |= encoderFlags; + _codec.openCodec(); + + // after open encoder, set specific encoder options + for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) + { + if( (*it).first == constants::avProfileIdentificator || + (*it).first == constants::avProfileIdentificatorHuman || + (*it).first == constants::avProfileType || + (*it).first == constants::avProfileCodec || + (*it).first == constants::avProfileWidth || + (*it).first == constants::avProfileHeight || + (*it).first == constants::avProfilePixelFormat || + (*it).first == constants::avProfileFrameRate || + (*it).first == constants::avProfileThreads ) + continue; + + try + { + Option& encodeOption = _codec.getOption( (*it).first ); + encodeOption.setString( (*it).second ); + } + catch( std::exception& e ) + { + LOG_WARN( "VideoEncoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) + } + } +} bool VideoEncoder::encodeFrame( const Frame& sourceFrame, Frame& codedFrame ) { @@ -126,67 +198,4 @@ bool VideoEncoder::encodeFrame( Frame& codedFrame ) #endif } -void VideoEncoder::setProfile( const ProfileLoader::Profile& profile, const avtranscoder::VideoFrameDesc& frameDesc ) -{ - LOG_DEBUG( "Set profile of video encoder with:\n" << profile ) - - // set width, height, pixel format, fps - _codec.setImageParameters( frameDesc ); - - // set threads before any other options - if( profile.count( constants::avProfileThreads ) ) - _codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) ); - else - _codec.getOption( constants::avProfileThreads ).setString( "auto" ); - - // set encoder options - for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) - { - if( (*it).first == constants::avProfileIdentificator || - (*it).first == constants::avProfileIdentificatorHuman || - (*it).first == constants::avProfileType || - (*it).first == constants::avProfileCodec || - (*it).first == constants::avProfileWidth || - (*it).first == constants::avProfileHeight || - (*it).first == constants::avProfilePixelFormat || - (*it).first == constants::avProfileFrameRate || - (*it).first == constants::avProfileThreads ) - continue; - - try - { - Option& encodeOption = _codec.getOption( (*it).first ); - encodeOption.setString( (*it).second ); - } - catch( std::exception& e ) - {} - } - - setup(); - - for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) - { - if( (*it).first == constants::avProfileIdentificator || - (*it).first == constants::avProfileIdentificatorHuman || - (*it).first == constants::avProfileType || - (*it).first == constants::avProfileCodec || - (*it).first == constants::avProfileWidth || - (*it).first == constants::avProfileHeight || - (*it).first == constants::avProfilePixelFormat || - (*it).first == constants::avProfileFrameRate || - (*it).first == constants::avProfileThreads ) - continue; - - try - { - Option& encodeOption = _codec.getOption( (*it).first ); - encodeOption.setString( (*it).second ); - } - catch( std::exception& e ) - { - LOG_WARN( "VideoEncoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() ) - } - } -} - } \ No newline at end of file diff --git a/src/AvTranscoder/encoder/VideoEncoder.hpp b/src/AvTranscoder/encoder/VideoEncoder.hpp index a6aaf373..b81b9758 100644 --- a/src/AvTranscoder/encoder/VideoEncoder.hpp +++ b/src/AvTranscoder/encoder/VideoEncoder.hpp @@ -14,7 +14,8 @@ class AvExport VideoEncoder : public IEncoder VideoEncoder( const std::string& videoCodecName ); ~VideoEncoder(); - void setup(); + void setupVideoEncoder( const VideoFrameDesc& frameDesc, const ProfileLoader::Profile& profile = ProfileLoader::Profile() ); + void setupEncoder( const ProfileLoader::Profile& profile = ProfileLoader::Profile() ); bool encodeFrame( const Frame& sourceFrame, Frame& codedFrame ); bool encodeFrame( Frame& codedFrame ); @@ -22,8 +23,6 @@ class AvExport VideoEncoder : public IEncoder ICodec& getCodec() { return _codec; } VideoCodec& getVideoCodec() { return _codec; } - void setProfile( const ProfileLoader::Profile& profile, const avtranscoder::VideoFrameDesc& frameDesc ); - private: VideoCodec _codec; AVFrame* _frame; ///< Contains the encoded data to pass to the Frame when encodeFrame diff --git a/src/AvTranscoder/profile/ProfileLoader.hpp b/src/AvTranscoder/profile/ProfileLoader.hpp index 16039117..aa98140e 100644 --- a/src/AvTranscoder/profile/ProfileLoader.hpp +++ b/src/AvTranscoder/profile/ProfileLoader.hpp @@ -29,6 +29,7 @@ namespace constants const std::string avProfileSampleRate = "ar"; const std::string avProfileChannel = "ac"; const std::string avProfileThreads = "threads"; + const std::string avProfileProcessStat = "processStat"; ///< Do statistics during the process. } class AvExport ProfileLoader diff --git a/src/AvTranscoder/stat/AudioStat.hpp b/src/AvTranscoder/stat/AudioStat.hpp new file mode 100644 index 00000000..54b68a47 --- /dev/null +++ b/src/AvTranscoder/stat/AudioStat.hpp @@ -0,0 +1,27 @@ +#ifndef _AV_TRANSCODER_AUDIOSTAT_HPP +#define _AV_TRANSCODER_AUDIOSTAT_HPP + +#include + +namespace avtranscoder +{ + +/** + * @brief Statistics related to an audio stream. + */ +class AvExport AudioStat +{ +public: + AudioStat( const double duration, const size_t nbPackets ) + : _duration( duration ) + , _nbPackets( nbPackets ) + {} + +public: + double _duration; + size_t _nbPackets; +}; + +} + +#endif diff --git a/src/AvTranscoder/stat/ProcessStat.cpp b/src/AvTranscoder/stat/ProcessStat.cpp new file mode 100644 index 00000000..a4343a83 --- /dev/null +++ b/src/AvTranscoder/stat/ProcessStat.cpp @@ -0,0 +1,18 @@ +#include "ProcessStat.hpp" + +#include + +namespace avtranscoder +{ + +void ProcessStat::addVideoStat( const size_t streamIndex, const VideoStat& videoStat ) +{ + _videoStats.insert( std::make_pair( streamIndex, videoStat ) ); +} + +void ProcessStat::addAudioStat( const size_t streamIndex, const AudioStat& audioStat ) +{ + _audioStats.insert( std::make_pair( streamIndex, audioStat ) ); +} + +} diff --git a/src/AvTranscoder/stat/ProcessStat.hpp b/src/AvTranscoder/stat/ProcessStat.hpp new file mode 100644 index 00000000..cec5a1ef --- /dev/null +++ b/src/AvTranscoder/stat/ProcessStat.hpp @@ -0,0 +1,37 @@ +#ifndef _AV_TRANSCODER_PROCESSSTAT_HPP +#define _AV_TRANSCODER_PROCESSSTAT_HPP + +#include +#include +#include + +#include + +namespace avtranscoder +{ + +/** + * @brief ProcessStat contains statistics given after the process. + * @see Transcoder::process methods + */ +class AvExport ProcessStat +{ +public: + ProcessStat() + : _videoStats() + {} + + void addVideoStat( const size_t streamIndex, const VideoStat& videoStat ); + void addAudioStat( const size_t streamIndex, const AudioStat& audioStat ); + + VideoStat& getVideoStat( const size_t streamIndex ) { return _videoStats.at(streamIndex); } + AudioStat& getAudioStat( const size_t streamIndex ) { return _audioStats.at(streamIndex); } + +private: + std::map _videoStats; ///< Key: streamIndex, Value: statistic video results + std::map _audioStats; ///< Key: streamIndex, Value: statistic audio results +}; + +} + +#endif diff --git a/src/AvTranscoder/stat/VideoStat.cpp b/src/AvTranscoder/stat/VideoStat.cpp new file mode 100644 index 00000000..88cf1507 --- /dev/null +++ b/src/AvTranscoder/stat/VideoStat.cpp @@ -0,0 +1,13 @@ +#include "ProcessStat.hpp" + +#include + +namespace avtranscoder +{ + +double VideoStat::psnr( const double d ) +{ + return -10.0 * log(d) / log(10.0); +} + +} diff --git a/src/AvTranscoder/stat/VideoStat.hpp b/src/AvTranscoder/stat/VideoStat.hpp new file mode 100644 index 00000000..23fb4ae8 --- /dev/null +++ b/src/AvTranscoder/stat/VideoStat.hpp @@ -0,0 +1,34 @@ +#ifndef _AV_TRANSCODER_VIDEOSTAT_HPP +#define _AV_TRANSCODER_VIDEOSTAT_HPP + +#include + +namespace avtranscoder +{ + +/** + * @brief Statistics related to a video stream. + */ +class AvExport VideoStat +{ +public: + VideoStat( const double duration, const size_t nbFrames ) + : _duration( duration ) + , _nbFrames( nbFrames ) + , _quality( 0 ) + , _psnr( 0 ) + {} + +public: + static double psnr( const double d ); + +public: + double _duration; + size_t _nbFrames; + size_t _quality; ///< Between 1 (good) and FF_LAMBDA_MAX (bad). 0 if unknown. + double _psnr; ///< 0 if unknown. +}; + +} + +#endif diff --git a/src/AvTranscoder/stat/stat.i b/src/AvTranscoder/stat/stat.i new file mode 100644 index 00000000..96927a68 --- /dev/null +++ b/src/AvTranscoder/stat/stat.i @@ -0,0 +1,9 @@ +%{ +#include +#include +#include +%} + +%include +%include +%include diff --git a/src/AvTranscoder/stream/IOutputStream.hpp b/src/AvTranscoder/stream/IOutputStream.hpp index b780c078..b9c86d87 100644 --- a/src/AvTranscoder/stream/IOutputStream.hpp +++ b/src/AvTranscoder/stream/IOutputStream.hpp @@ -26,6 +26,7 @@ class AvExport IOutputStream virtual size_t getStreamIndex() const = 0; virtual double getStreamDuration() const = 0; + virtual size_t getNbFrames() const = 0; virtual EWrappingStatus wrap( const CodedData& data ) = 0; }; diff --git a/src/AvTranscoder/stream/OutputStream.cpp b/src/AvTranscoder/stream/OutputStream.cpp index 1563c75b..6ded2d44 100644 --- a/src/AvTranscoder/stream/OutputStream.cpp +++ b/src/AvTranscoder/stream/OutputStream.cpp @@ -25,6 +25,12 @@ double OutputStream::getStreamDuration() const #endif } +size_t OutputStream::getNbFrames() const +{ + AVStream& outputStream = _outputFile->getFormatContext().getAVStream( _streamIndex ); + return outputStream.nb_frames; +} + IOutputStream::EWrappingStatus OutputStream::wrap( const CodedData& data ) { assert( _outputFile != NULL ); diff --git a/src/AvTranscoder/stream/OutputStream.hpp b/src/AvTranscoder/stream/OutputStream.hpp index d5141055..249f29fe 100644 --- a/src/AvTranscoder/stream/OutputStream.hpp +++ b/src/AvTranscoder/stream/OutputStream.hpp @@ -15,6 +15,7 @@ class AvExport OutputStream : public IOutputStream size_t getStreamIndex() const { return _streamIndex; } double getStreamDuration() const; + size_t getNbFrames() const; ///< If audio stream, returns number of packets IOutputStream::EWrappingStatus wrap( const CodedData& data ); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 85b549d5..56ccdef8 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -59,8 +59,7 @@ StreamTranscoder::StreamTranscoder( // output encoder VideoEncoder* outputVideo = new VideoEncoder( _inputStream->getVideoCodec().getCodecName() ); - outputVideo->getVideoCodec().setImageParameters( inputFrameDesc ); - outputVideo->setup(); + outputVideo->setupVideoEncoder( inputFrameDesc ); _outputEncoder = outputVideo; // output stream @@ -86,8 +85,7 @@ StreamTranscoder::StreamTranscoder( // output encoder AudioEncoder* outputAudio = new AudioEncoder( _inputStream->getAudioCodec().getCodecName() ); - outputAudio->getAudioCodec().setAudioParameters( inputFrameDesc ); - outputAudio->setup(); + outputAudio->setupAudioEncoder( inputFrameDesc ); _outputEncoder = outputAudio; // output stream @@ -133,9 +131,7 @@ StreamTranscoder::StreamTranscoder( { // input decoder VideoDecoder* inputVideo = new VideoDecoder( *static_cast( _inputStream ) ); - // set decoder options with empty profile to set some key options to specific values (example: threads to auto) - inputVideo->setProfile( ProfileLoader::Profile() ); - inputVideo->setup(); + inputVideo->setupDecoder(); _inputDecoder = inputVideo; _currentDecoder = _inputDecoder; @@ -145,7 +141,7 @@ StreamTranscoder::StreamTranscoder( VideoFrameDesc outputFrameDesc = _inputStream->getVideoCodec().getVideoFrameDesc(); outputFrameDesc.setParameters( profile ); - outputVideo->setProfile( profile, outputFrameDesc ); + outputVideo->setupVideoEncoder( outputFrameDesc, profile ); // output stream _outputStream = &outputFile.addVideoStream( outputVideo->getVideoCodec() ); @@ -168,9 +164,7 @@ StreamTranscoder::StreamTranscoder( { // input decoder AudioDecoder* inputAudio = new AudioDecoder( *static_cast( _inputStream ) ); - // set decoder options with empty profile to set some key options to specific values (example: threads to auto) - inputAudio->setProfile( ProfileLoader::Profile() ); - inputAudio->setup(); + inputAudio->setupDecoder(); _inputDecoder = inputAudio; _currentDecoder = _inputDecoder; @@ -185,7 +179,7 @@ StreamTranscoder::StreamTranscoder( // @todo manage downmix ? outputFrameDesc.setChannels( 1 ); } - outputAudio->setProfile( profile, outputFrameDesc ); + outputAudio->setupAudioEncoder( outputFrameDesc, profile ); // output stream _outputStream = &outputFile.addAudioStream( outputAudio->getAudioCodec() ); @@ -255,7 +249,7 @@ StreamTranscoder::StreamTranscoder( // output encoder VideoEncoder* outputVideo = new VideoEncoder( profile.at( constants::avProfileCodec ) ); - outputVideo->setProfile( profile, outputFrameDesc ); + outputVideo->setupVideoEncoder( outputFrameDesc, profile ); _outputEncoder = outputVideo; // output stream @@ -282,7 +276,7 @@ StreamTranscoder::StreamTranscoder( // output encoder AudioEncoder* outputAudio = new AudioEncoder( profile.at( constants::avProfileCodec ) ); - outputAudio->setProfile( profile, outputFrameDesc ); + outputAudio->setupAudioEncoder( outputFrameDesc, profile ); _outputEncoder = outputAudio; // output stream diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index fdb707cd..6fc9913c 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -215,20 +216,19 @@ bool Transcoder::processFrame() bool streamProcessStatus = _streamTranscoders.at( streamIndex )->processFrame(); if( ! streamProcessStatus ) { - _streamTranscoders.clear(); return false; } } return true; } -void Transcoder::process() +ProcessStat Transcoder::process() { NoDisplayProgress progress; - process( progress ); + return process( progress ); } -void Transcoder::process( IProgress& progress ) +ProcessStat Transcoder::process( IProgress& progress ) { if( _streamTranscoders.size() == 0 ) throw std::runtime_error( "missing input streams in transcoder" ); @@ -267,6 +267,12 @@ void Transcoder::process( IProgress& progress ) _outputFile.endWrap(); LOG_INFO( "End of process" ) + + LOG_INFO( "Get process statistics" ) + ProcessStat processStat; + fillProcessStat( processStat ); + + return processStat; } void Transcoder::setProcessMethod( const EProcessMethod eProcessMethod, const size_t indexBasedStream, const double outputDuration ) @@ -512,4 +518,35 @@ void Transcoder::manageSwitchToGenerator() } } +void Transcoder::fillProcessStat( ProcessStat& processStat ) +{ + for( size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex ) + { + IOutputStream& stream = _streamTranscoders.at( streamIndex )->getOutputStream(); + AVCodecContext& encoderContext = _streamTranscoders.at( streamIndex )->getEncoder().getCodec().getAVCodecContext(); + switch( encoderContext.codec_type ) + { + case AVMEDIA_TYPE_VIDEO: + { + VideoStat videoStat( stream.getStreamDuration(), stream.getNbFrames() ); + if( encoderContext.coded_frame && ( encoderContext.flags & CODEC_FLAG_PSNR) ) + { + videoStat._quality = encoderContext.coded_frame->quality; + videoStat._psnr = VideoStat::psnr(encoderContext.coded_frame->error[0] / (encoderContext.width * encoderContext.height * 255.0 * 255.0)); + } + processStat.addVideoStat( streamIndex, videoStat ); + break; + } + case AVMEDIA_TYPE_AUDIO: + { + AudioStat audioStat( stream.getStreamDuration(), stream.getNbFrames() ); + processStat.addAudioStat( streamIndex, audioStat ); + break; + } + default: + break; + } + } +} + } diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index b9984017..c8656f31 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "StreamTranscoder.hpp" @@ -119,10 +120,11 @@ class AvExport Transcoder * @brief Process all the streams, and ended the process depending on the transcode politic. * @note The function manages all process: init(), beginWrap(), processFrame()s, and endWrap(). * @param progress: choose a progress, or create your own in C++ or in bindings by inherit IProgress class. + * @return ProcessStat: object with statistics of the process for each stream. * @see IProgress */ - void process( IProgress& progress ); - void process(); ///< Call process with no display of progression + ProcessStat process( IProgress& progress ); + ProcessStat process(); ///< Call process with no display of progression /** * @brief Return the list of streams added to the transcoder. @@ -188,6 +190,11 @@ class AvExport Transcoder */ void manageSwitchToGenerator(); + /** + * @brief Fill the given ProcessStat to summarize the process. + */ + void fillProcessStat( ProcessStat& processStat ); + private: IOutputFile& _outputFile; ///< The output media file after process (has link) std::vector< InputFile* > _inputFiles; ///< The list of input files which contain added streams (has ownership)