diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e336bfd..933aac0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,17 +2,6 @@ cmake_minimum_required(VERSION 2.8.11) project(AvTranscoder) -# Set AvTranscoder versions -set(AVTRANSCODER_VERSION_MAJOR "0") -set(AVTRANSCODER_VERSION_MINOR "5") -set(AVTRANSCODER_VERSION_MICRO "10") -set(AVTRANSCODER_VERSION ${AVTRANSCODER_VERSION_MAJOR}.${AVTRANSCODER_VERSION_MINOR}.${AVTRANSCODER_VERSION_MICRO}) - -# Define AvTranscoder versions -add_definitions(-DAVTRANSCODER_VERSION_MAJOR=${AVTRANSCODER_VERSION_MAJOR}) -add_definitions(-DAVTRANSCODER_VERSION_MINOR=${AVTRANSCODER_VERSION_MINOR}) -add_definitions(-DAVTRANSCODER_VERSION_MICRO=${AVTRANSCODER_VERSION_MICRO}) - # Define AvTranscoder default path to profiles add_definitions(-DAVTRANSCODER_DEFAULT_AVPROFILES="${CMAKE_INSTALL_PREFIX}/share/avprofiles") @@ -37,8 +26,10 @@ if(AVTRANSCODER_COVERAGE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") endif() +# Build library add_subdirectory(src) +# Build apps if(AVTRANSCODER_DISABLE_APPS) message("Apps disabled, will not build applications.") else() diff --git a/cmake/AvTranscoderMacros.cmake b/cmake/AvTranscoderMacros.cmake index 4794bd21..2dc45379 100644 --- a/cmake/AvTranscoderMacros.cmake +++ b/cmake/AvTranscoderMacros.cmake @@ -2,3 +2,24 @@ set(AVTRANSCODER_APP_PATH "${PROJECT_SOURCE_DIR}/app") set(AVTRANSCODER_SRC_PATH "${PROJECT_SOURCE_DIR}/src") file(GLOB_RECURSE AVTRANSCODER_SRC_FILES "AvTranscoder/*.cpp" "AvTranscoder/*.hpp") + +# Get AvTranscoder versions +# AVTRANSCODER_VERSION_MAJOR +# AVTRANSCODER_VERSION_MINOR +# AVTRANSCODER_VERSION_MICRO +# AVTRANSCODER_VERSION +file(STRINGS "${AVTRANSCODER_SRC_PATH}/AvTranscoder/common.hpp" _avtranscoder_VERSION_HPP_CONTENTS REGEX "#define AVTRANSCODER_VERSION_") +foreach(v MAJOR MINOR MICRO) + if("${_avtranscoder_VERSION_HPP_CONTENTS}" MATCHES "#define AVTRANSCODER_VERSION_${v} ([0-9]+)") + set(AVTRANSCODER_VERSION_${v} "${CMAKE_MATCH_1}") + else() + set(AVTRANSCODER_RETRIEVE_VERSION_FAILED 1) + endif() +endforeach() +unset(_avtranscoder_VERSION_HPP_CONTENTS) + +set(AVTRANSCODER_VERSION "${AVTRANSCODER_VERSION_MAJOR}.${AVTRANSCODER_VERSION_MINOR}.${AVTRANSCODER_VERSION_MICRO}") + +if(AVTRANSCODER_RETRIEVE_VERSION_FAILED) + message(SEND_ERROR "Failed to retrieve AvTranscoder version: ${AVTRANSCODER_VERSION}") +endif() diff --git a/src/AvTranscoder/common.hpp b/src/AvTranscoder/common.hpp index 33bebcd9..010fa163 100644 --- a/src/AvTranscoder/common.hpp +++ b/src/AvTranscoder/common.hpp @@ -1,6 +1,10 @@ #ifndef _AV_TRANSCODER_COMMON_HPP_ #define _AV_TRANSCODER_COMMON_HPP_ +#define AVTRANSCODER_VERSION_MAJOR 0 +#define AVTRANSCODER_VERSION_MINOR 5 +#define AVTRANSCODER_VERSION_MICRO 12 + #include extern "C" { diff --git a/src/AvTranscoder/decoder/AudioDecoder.cpp b/src/AvTranscoder/decoder/AudioDecoder.cpp index eb9432fe..346ce765 100644 --- a/src/AvTranscoder/decoder/AudioDecoder.cpp +++ b/src/AvTranscoder/decoder/AudioDecoder.cpp @@ -62,7 +62,10 @@ void AudioDecoder::setupDecoder( const ProfileLoader::Profile& profile ) throw std::runtime_error( msg ); } - LOG_INFO( "Setup audio decoder with:\n" << profile ) + if( ! profile.empty() ) + { + LOG_INFO( "Setup audio decoder with:\n" << profile ) + } AudioCodec& codec = _inputStream->getAudioCodec(); diff --git a/src/AvTranscoder/decoder/VideoDecoder.cpp b/src/AvTranscoder/decoder/VideoDecoder.cpp index 08f87271..ae54d737 100644 --- a/src/AvTranscoder/decoder/VideoDecoder.cpp +++ b/src/AvTranscoder/decoder/VideoDecoder.cpp @@ -60,7 +60,10 @@ void VideoDecoder::setupDecoder( const ProfileLoader::Profile& profile ) throw std::runtime_error( msg ); } - LOG_INFO( "Setup video decoder with:\n" << profile ) + if( ! profile.empty() ) + { + LOG_INFO( "Setup video decoder with:\n" << profile ) + } VideoCodec& codec = _inputStream->getVideoCodec(); diff --git a/src/AvTranscoder/encoder/AudioEncoder.cpp b/src/AvTranscoder/encoder/AudioEncoder.cpp index 93e68342..85941c92 100644 --- a/src/AvTranscoder/encoder/AudioEncoder.cpp +++ b/src/AvTranscoder/encoder/AudioEncoder.cpp @@ -37,7 +37,10 @@ AudioEncoder::~AudioEncoder() void AudioEncoder::setupAudioEncoder( const AudioFrameDesc& frameDesc, const ProfileLoader::Profile& profile ) { - LOG_INFO( "Setup audio encoder with:\n" << profile ) + if( ! profile.empty() ) + { + LOG_INFO( "Setup audio encoder with:\n" << profile ) + } // set sampleRate, number of channels, sample format _codec.setAudioParameters( frameDesc ); diff --git a/src/AvTranscoder/encoder/VideoEncoder.cpp b/src/AvTranscoder/encoder/VideoEncoder.cpp index cca0820e..cce274ff 100644 --- a/src/AvTranscoder/encoder/VideoEncoder.cpp +++ b/src/AvTranscoder/encoder/VideoEncoder.cpp @@ -38,7 +38,10 @@ VideoEncoder::~VideoEncoder() void VideoEncoder::setupVideoEncoder( const VideoFrameDesc& frameDesc, const ProfileLoader::Profile& profile ) { - LOG_INFO( "Setup video encoder with:\n" << profile ) + if( ! profile.empty() ) + { + LOG_INFO( "Setup video encoder with:\n" << profile ) + } // set width, height, pixel format, fps _codec.setImageParameters( frameDesc ); diff --git a/src/AvTranscoder/file/FormatContext.cpp b/src/AvTranscoder/file/FormatContext.cpp index 7dd22cbc..1306347e 100644 --- a/src/AvTranscoder/file/FormatContext.cpp +++ b/src/AvTranscoder/file/FormatContext.cpp @@ -142,11 +142,9 @@ AVStream& FormatContext::addAVStream( const AVCodec& avCodec ) return *stream; } -bool FormatContext::seek( uint64_t position, const int flag ) +bool FormatContext::seek( const uint64_t position, const int flag ) { - if( (int)getStartTime() != AV_NOPTS_VALUE ) - position += getStartTime(); - + LOG_INFO( "Seek in '" << _avFormatContext->filename << "' at " << position << " (in AV_TIME_BASE units)" ) int err = av_seek_frame( _avFormatContext, -1, position, flag ); if( err < 0 ) { diff --git a/src/AvTranscoder/file/FormatContext.hpp b/src/AvTranscoder/file/FormatContext.hpp index b446d8a9..7c080531 100644 --- a/src/AvTranscoder/file/FormatContext.hpp +++ b/src/AvTranscoder/file/FormatContext.hpp @@ -77,10 +77,10 @@ class AvExport FormatContext * @brief Seek at a specific position * @param position: can be in AV_TIME_BASE units, in frames... depending on the flag value * @param flag: seeking mode (AVSEEK_FLAG_xxx) - * @note before seek, add offset of start time * @return seek status + * @see flushDecoder */ - bool seek( uint64_t position, const int flag ); + bool seek( const uint64_t position, const int flag ); size_t getNbStreams() const { return _avFormatContext->nb_streams; } /// Get duration of the program, in seconds diff --git a/src/AvTranscoder/file/IOutputFile.hpp b/src/AvTranscoder/file/IOutputFile.hpp index bce7b919..a8a4f9ad 100644 --- a/src/AvTranscoder/file/IOutputFile.hpp +++ b/src/AvTranscoder/file/IOutputFile.hpp @@ -26,7 +26,6 @@ class AvExport IOutputFile /** * @brief Add a video output stream - * @note call setup() before adding any stream * @param videoCodec description of output stream **/ virtual IOutputStream& addVideoStream( const VideoCodec& videoCodec ) @@ -36,7 +35,6 @@ class AvExport IOutputFile /** * @brief Add an audio output stream - * @note call setup() before adding any stream * @param audioCodec description of output stream **/ virtual IOutputStream& addAudioStream( const AudioCodec& audioCodec ) @@ -46,7 +44,6 @@ class AvExport IOutputFile /** * @brief Add a data output stream - * @note call setup() before adding any stream * @param dataCodec description of output stream **/ virtual IOutputStream& addDataStream( const DataCodec& dataCodec ) @@ -62,7 +59,9 @@ class AvExport IOutputFile /** * @brief Wrap a packet of data in the output ressource * @param data coded packet information for the current stream - * @param streamId refers to the stream in output ressource + * @param streamIndex refers to the stream in output ressource + * @return the wrapping status after wrapping + * @see EWrappingStatus **/ virtual IOutputStream::EWrappingStatus wrap( const CodedData& data, const size_t streamIndex ) = 0; @@ -73,7 +72,7 @@ class AvExport IOutputFile /** * @brief Get the output stream - * @param streamId select the output stream + * @param streamIndex select the output stream * @return the output stream reference **/ virtual IOutputStream& getStream( const size_t streamIndex ) = 0; diff --git a/src/AvTranscoder/file/InputFile.cpp b/src/AvTranscoder/file/InputFile.cpp index f780a090..6c945616 100644 --- a/src/AvTranscoder/file/InputFile.cpp +++ b/src/AvTranscoder/file/InputFile.cpp @@ -173,8 +173,10 @@ void InputFile::setupUnwrapping( const ProfileLoader::Profile& profile ) throw std::runtime_error( msg ); } - // set profile - LOG_INFO( "Setup unwrapping with:\n" << profile ) + if( ! profile.empty() ) + { + LOG_INFO( "Setup unwrapping with:\n" << profile ) + } for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) { diff --git a/src/AvTranscoder/file/OutputFile.cpp b/src/AvTranscoder/file/OutputFile.cpp index 910b7d95..057a33f2 100644 --- a/src/AvTranscoder/file/OutputFile.cpp +++ b/src/AvTranscoder/file/OutputFile.cpp @@ -73,7 +73,9 @@ IOutputStream& OutputFile::addAudioStream( const AudioCodec& audioDesc ) 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; // need to set the time_base on the AVCodecContext of the AVStream av_reduce( @@ -99,11 +101,11 @@ IOutputStream& OutputFile::addDataStream( const DataCodec& dataDesc ) return *outputStream; } -IOutputStream& OutputFile::getStream( const size_t streamId ) +IOutputStream& OutputFile::getStream( const size_t streamIndex ) { - if( streamId >= _outputStreams.size() ) + if( streamIndex >= _outputStreams.size() ) throw std::runtime_error( "unable to get output stream (out of range)" ); - return *_outputStreams.at( streamId ); + return *_outputStreams.at( streamIndex ); } std::string OutputFile::getFilename() const @@ -157,16 +159,16 @@ bool OutputFile::beginWrap( ) return true; } -IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const size_t streamId ) +IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const size_t streamIndex ) { if( ! data.getSize() ) return IOutputStream::eWrappingSuccess; - LOG_DEBUG( "Wrap on stream " << streamId << " (" << data.getSize() << " bytes for frame " << _frameCount.at( streamId ) << ")" ) + LOG_DEBUG( "Wrap on stream " << streamIndex << " (" << data.getSize() << " bytes for frame " << _frameCount.at( streamIndex ) << ")" ) AVPacket packet; av_init_packet( &packet ); - packet.stream_index = streamId; + packet.stream_index = streamIndex; packet.data = (uint8_t*)data.getData(); packet.size = data.getSize(); @@ -175,7 +177,7 @@ IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const si // free packet.side_data, set packet.data to NULL and packet.size to 0 av_free_packet( &packet ); - const double currentStreamDuration = _outputStreams.at( streamId )->getStreamDuration(); + const double currentStreamDuration = _outputStreams.at( streamIndex )->getStreamDuration(); if( currentStreamDuration < _previousProcessedStreamDuration ) { // if the current stream is strictly shorter than the previous, wait for more data @@ -183,7 +185,7 @@ IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const si } _previousProcessedStreamDuration = currentStreamDuration; - _frameCount.at( streamId )++; + _frameCount.at( streamIndex )++; return IOutputStream::eWrappingSuccess; } @@ -221,7 +223,10 @@ void OutputFile::setupWrapping( const ProfileLoader::Profile& profile ) throw std::runtime_error( msg ); } - LOG_INFO( "Setup wrapping with:\n" << profile ) + if( ! profile.empty() ) + { + LOG_INFO( "Setup wrapping with:\n" << profile ) + } // check if output format indicated is valid with the filename extension if( ! matchFormat( profile.find( constants::avProfileFormat )->second, getFilename() ) ) diff --git a/src/AvTranscoder/file/OutputFile.hpp b/src/AvTranscoder/file/OutputFile.hpp index 53819a9f..bf71f30d 100644 --- a/src/AvTranscoder/file/OutputFile.hpp +++ b/src/AvTranscoder/file/OutputFile.hpp @@ -37,10 +37,10 @@ class AvExport OutputFile : public IOutputFile * @brief Open ressource, write header, and setup specific wrapping options given when call setupWrapping. * @note Need to add the streams to mux before calling this method. * @note After this call, a new list of AVOption, relative to the format choosen, will be available for the OutputFile. - */ + */ bool beginWrap(); - IOutputStream::EWrappingStatus wrap( const CodedData& data, const size_t streamId ); + IOutputStream::EWrappingStatus wrap( const CodedData& data, const size_t streamIndex ); /** * @brief Close ressource and write trailer. @@ -54,7 +54,7 @@ class AvExport OutputFile : public IOutputFile void addMetadata( const PropertyVector& data ); void addMetadata( const std::string& key, const std::string& value ); - IOutputStream& getStream( const size_t streamId ); + IOutputStream& getStream( const size_t streamIndex ); std::string getFilename() const; diff --git a/src/AvTranscoder/log.cpp b/src/AvTranscoder/log.cpp index 8327f24b..58c32702 100644 --- a/src/AvTranscoder/log.cpp +++ b/src/AvTranscoder/log.cpp @@ -3,6 +3,8 @@ namespace avtranscoder { +std::string Logger::logHeaderMessage = ""; + void callbackToWriteInFile( void *ptr, int level, const char *fmt, va_list vl ) { std::ofstream outputFile; @@ -23,13 +25,10 @@ void callbackToWriteInFile( void *ptr, int level, const char *fmt, va_list vl ) void Logger::setLogLevel( const int level ) { + // set ffmpeg log level av_log_set_level( level ); -} - -void Logger::log( const int level, const std::string& msg ) -{ - std::string avTranscoderMsg( "[avTranscoder - " ); + // set avtranscoder header message std::string levelStr; switch( level ) { @@ -48,12 +47,15 @@ void Logger::log( const int level, const std::string& msg ) default: break; } + Logger::logHeaderMessage = "[avTranscoder - " + levelStr + "] "; +} - avTranscoderMsg += levelStr; - avTranscoderMsg += "] "; - avTranscoderMsg += msg; - avTranscoderMsg += "\n"; - av_log( NULL, level, avTranscoderMsg.c_str() ); +void Logger::log( const int level, const std::string& msg ) +{ + std::string logMessage = Logger::logHeaderMessage; + logMessage += msg; + logMessage += "\n"; + av_log( NULL, level, logMessage.c_str() ); } void Logger::logInFile() diff --git a/src/AvTranscoder/log.hpp b/src/AvTranscoder/log.hpp index d25067c9..e1102479 100644 --- a/src/AvTranscoder/log.hpp +++ b/src/AvTranscoder/log.hpp @@ -44,6 +44,9 @@ class AvExport Logger * @note log filename is avtranscoder.log */ static void logInFile(); + +private: + static std::string logHeaderMessage; ///< First caracters present for each logging message }; } diff --git a/src/AvTranscoder/mediaProperty/StreamProperties.cpp b/src/AvTranscoder/mediaProperty/StreamProperties.cpp index b16ee25d..196e425d 100644 --- a/src/AvTranscoder/mediaProperty/StreamProperties.cpp +++ b/src/AvTranscoder/mediaProperty/StreamProperties.cpp @@ -43,6 +43,13 @@ float StreamProperties::getDuration() const return ( timeBase.num / (float) timeBase.den ) * _formatContext->streams[_streamIndex]->duration; } +AVMediaType StreamProperties::getStreamType() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->streams[_streamIndex]->codec->codec_type; +} + PropertyVector StreamProperties::getPropertiesAsVector() const { PropertyVector data; diff --git a/src/AvTranscoder/mediaProperty/StreamProperties.hpp b/src/AvTranscoder/mediaProperty/StreamProperties.hpp index 86c798ac..a70a9dbe 100644 --- a/src/AvTranscoder/mediaProperty/StreamProperties.hpp +++ b/src/AvTranscoder/mediaProperty/StreamProperties.hpp @@ -19,10 +19,11 @@ class AvExport StreamProperties size_t getStreamId() const; Rational getTimeBase() const; float getDuration() const; ///< in seconds + AVMediaType getStreamType() const; const PropertyVector& getMetadatas() const { return _metadatas; } #ifndef SWIG - const AVFormatContext& getAVFormatContext() { return *_formatContext; } + const AVFormatContext& getAVFormatContext() const { return *_formatContext; } #endif PropertyMap getPropertiesAsMap() const; ///< Return all properties as a map (name of property, value) diff --git a/src/AvTranscoder/reader/IReader.cpp b/src/AvTranscoder/reader/IReader.cpp index 8f938805..a83608b2 100644 --- a/src/AvTranscoder/reader/IReader.cpp +++ b/src/AvTranscoder/reader/IReader.cpp @@ -2,6 +2,8 @@ #include +#include + namespace avtranscoder { @@ -49,6 +51,11 @@ Frame* IReader::readPrevFrame() Frame* IReader::readFrameAt( const size_t frame ) { + assert( _decoder != NULL ); + assert( _transform != NULL ); + assert( _srcFrame != NULL ); + assert( _dstFrame != NULL ); + if( (int)frame != _currentFrame + 1 ) { // seek @@ -65,6 +72,7 @@ Frame* IReader::readFrameAt( const size_t frame ) void IReader::printInfo() { + assert( _streamProperties != NULL ); std::cout << *_streamProperties << std::endl; } diff --git a/src/AvTranscoder/stream/IInputStream.hpp b/src/AvTranscoder/stream/IInputStream.hpp index 4e8ea4b8..b0d258ba 100644 --- a/src/AvTranscoder/stream/IInputStream.hpp +++ b/src/AvTranscoder/stream/IInputStream.hpp @@ -1,9 +1,12 @@ #ifndef _AV_TRANSCODER_CODED_STREAM_I_INPUT_STREAM_HPP_ #define _AV_TRANSCODER_CODED_STREAM_I_INPUT_STREAM_HPP_ +#include + #include #include #include + #include namespace avtranscoder @@ -21,9 +24,17 @@ class AvExport IInputStream **/ virtual bool readNextPacket( CodedData& data ) = 0; + /** + * @note The returned object could be cast depending on the type of the stream (video, audio...) + * @see VideoProperties, AudioProperties... + * @return the properties of the stream + */ + virtual const StreamProperties& getProperties() const = 0; + + /** + * @return the index of the stream + */ virtual size_t getStreamIndex() const = 0; - virtual float getDuration() const = 0; - virtual AVMediaType getStreamType() const = 0; //@{ /** @@ -35,12 +46,16 @@ class AvExport IInputStream virtual DataCodec& getDataCodec() = 0; //@} - /** - * @brief Activate the stream will buffered its data when read packets. - **/ + //@{ + /** + * @brief Functions about buffering + * Activate the stream will buffered its data when read packets. + * @see IInputStream methods + */ virtual void activate( const bool activate = true ) = 0; virtual bool isActivated() const = 0; virtual void clearBuffering() = 0; + //@} }; } diff --git a/src/AvTranscoder/stream/IOutputStream.hpp b/src/AvTranscoder/stream/IOutputStream.hpp index a45d16d7..83a00415 100644 --- a/src/AvTranscoder/stream/IOutputStream.hpp +++ b/src/AvTranscoder/stream/IOutputStream.hpp @@ -36,6 +36,11 @@ class AvExport IOutputStream */ virtual size_t getNbFrames() const = 0; + /** + * @brief Wrap a packet of data + * @return the wrapping status after wrapping + * @see EWrappingStatus + **/ virtual EWrappingStatus wrap( const CodedData& data ) = 0; }; diff --git a/src/AvTranscoder/stream/InputStream.cpp b/src/AvTranscoder/stream/InputStream.cpp index 851bd0f5..ef9bc6d0 100644 --- a/src/AvTranscoder/stream/InputStream.cpp +++ b/src/AvTranscoder/stream/InputStream.cpp @@ -76,7 +76,7 @@ VideoCodec& InputStream::getVideoCodec() { assert( _streamIndex <= _inputFile->getFormatContext().getNbStreams() ); - if( getStreamType() != AVMEDIA_TYPE_VIDEO ) + if( getProperties().getStreamType() != AVMEDIA_TYPE_VIDEO ) { throw std::runtime_error( "unable to get video descriptor on non-video stream" ); } @@ -88,7 +88,7 @@ AudioCodec& InputStream::getAudioCodec() { assert( _streamIndex <= _inputFile->getFormatContext().getNbStreams() ); - if( getStreamType() != AVMEDIA_TYPE_AUDIO ) + if( getProperties().getStreamType() != AVMEDIA_TYPE_AUDIO ) { throw std::runtime_error( "unable to get audio descriptor on non-audio stream" ); } @@ -100,7 +100,7 @@ DataCodec& InputStream::getDataCodec() { assert( _streamIndex <= _inputFile->getFormatContext().getNbStreams() ); - if( getStreamType() != AVMEDIA_TYPE_DATA ) + if( getProperties().getStreamType() != AVMEDIA_TYPE_DATA ) { throw std::runtime_error( "unable to get data descriptor on non-data stream" ); } @@ -108,14 +108,9 @@ DataCodec& InputStream::getDataCodec() return *static_cast( _codec ); } -AVMediaType InputStream::getStreamType() const +const StreamProperties& InputStream::getProperties() const { - return _inputFile->getFormatContext().getAVStream( _streamIndex ).codec->codec_type; -} - -float InputStream::getDuration() const -{ - return _inputFile->getProperties().getStreamPropertiesWithIndex( _streamIndex ).getDuration(); + return _inputFile->getProperties().getStreamPropertiesWithIndex( _streamIndex ); } void InputStream::addPacket( const AVPacket& packet ) diff --git a/src/AvTranscoder/stream/InputStream.hpp b/src/AvTranscoder/stream/InputStream.hpp index 2bb218f7..b0ea4a15 100644 --- a/src/AvTranscoder/stream/InputStream.hpp +++ b/src/AvTranscoder/stream/InputStream.hpp @@ -24,25 +24,17 @@ class AvExport InputStream : public IInputStream bool readNextPacket( CodedData& data ); + const StreamProperties& getProperties() const; size_t getStreamIndex() const { return _streamIndex; } - /// Get duration of the stream, in seconds - float getDuration() const; - AVMediaType getStreamType() const; VideoCodec& getVideoCodec(); AudioCodec& getAudioCodec(); DataCodec& getDataCodec(); - //@{ - /** - * @brief Functions about buffering - * @see IInputStream methods - */ void activate( const bool activate = true ){ _isActivated = activate; }; bool isActivated() const { return _isActivated; }; void addPacket( const AVPacket& packet ); void clearBuffering(); - //@} private: InputFile* _inputFile; ///< Has link (no ownership) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index fae22792..ef7a0157 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -39,7 +39,7 @@ StreamTranscoder::StreamTranscoder( , _needToSwitchToGenerator( false ) { // create a re-wrapping case - switch( _inputStream->getStreamType() ) + switch( _inputStream->getProperties().getStreamType() ) { case AVMEDIA_TYPE_VIDEO : { @@ -141,7 +141,7 @@ StreamTranscoder::StreamTranscoder( , _needToSwitchToGenerator( false ) { // create a transcode case - switch( _inputStream->getStreamType() ) + switch( _inputStream->getProperties().getStreamType() ) { case AVMEDIA_TYPE_VIDEO : { @@ -383,7 +383,7 @@ bool StreamTranscoder::processFrame() } else if( _offset < 0 ) { - const bool endOfStream = _outputStream->getStreamDuration() >= ( _inputStream->getDuration() + _offset ); + const bool endOfStream = _outputStream->getStreamDuration() >= ( _inputStream->getProperties().getDuration() + _offset ); if( endOfStream ) { LOG_INFO( "End of negative offset" ) @@ -516,10 +516,11 @@ float StreamTranscoder::getDuration() const { if( _inputStream ) { - const float totalDuration = _inputStream->getDuration() + _offset; + const StreamProperties& streamProperties = _inputStream->getProperties(); + const float totalDuration = streamProperties.getDuration() + _offset; if( totalDuration < 0 ) { - LOG_WARN( "Offset of " << _offset << "s applied to a stream with a duration of " << _inputStream->getDuration() << "s. Set its duration to 0s." ) + LOG_WARN( "Offset of " << _offset << "s applied to a stream with a duration of " << streamProperties.getDuration() << "s. Set its duration to 0s." ) return 0.; } return totalDuration; diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 6458fa93..723faebc 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -317,7 +317,7 @@ void Transcoder::addTranscodeStream( const std::string& filename, const size_t s // Add input file InputFile* referenceFile = addInputFile( filename, streamIndex, offset ); - switch( referenceFile->getStream( streamIndex ).getStreamType() ) + switch( referenceFile->getStream( streamIndex ).getProperties().getStreamType() ) { case AVMEDIA_TYPE_VIDEO: case AVMEDIA_TYPE_AUDIO: @@ -385,7 +385,7 @@ ProfileLoader::Profile Transcoder::getProfileFromFile( InputFile& inputFile, con const StreamProperties* streamProperties = &inputFile.getProperties().getStreamPropertiesWithIndex( streamIndex ); const VideoProperties* videoProperties = NULL; const AudioProperties* audioProperties = NULL; - switch( inputFile.getStream( streamIndex ).getStreamType() ) + switch( inputFile.getStream( streamIndex ).getProperties().getStreamType() ) { case AVMEDIA_TYPE_VIDEO: { @@ -522,7 +522,7 @@ void Transcoder::fillProcessStat( ProcessStat& processStat ) for( size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex ) { IOutputStream& stream = _streamTranscoders.at( streamIndex )->getOutputStream(); - const AVMediaType mediaType = _streamTranscoders.at( streamIndex )->getInputStream().getStreamType(); + const AVMediaType mediaType = _streamTranscoders.at( streamIndex )->getInputStream().getProperties().getStreamType(); switch( mediaType ) { case AVMEDIA_TYPE_VIDEO: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a895f98..ad8a4630 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,16 +2,17 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) include(AvTranscoderMacros) -# find package ffmpeg/libav -find_package(FFmpeg COMPONENTS avcodec avformat avutil swscale swresample avresample) +# AvTranscoder versions +message(STATUS "AvTranscoder version is ${AVTRANSCODER_VERSION}") -# Check if FFmpeg or libav dependency +# Find package ffmpeg/libav +find_package(FFmpeg COMPONENTS avcodec avformat avutil swscale swresample avresample) if(swresample_FOUND) add_definitions(-DAVTRANSCODER_FFMPEG_DEPENDENCY) - message("Build avTranscoder with dependency to ffmpeg.") + message(STATUS "Build avTranscoder with dependency to ffmpeg.") elseif(avresample_FOUND) add_definitions(-DAVTRANSCODER_LIBAV_DEPENDENCY) - message("Build avTranscoder with dependency to libav.") + message(STATUS "Build avTranscoder with dependency to libav.") else() message(SEND_ERROR "Can't define if you depend on ffmpeg or libav.") endif() diff --git a/test/pyTest/testOffset.py b/test/pyTest/testOffset.py index 3b611a60..fec33dc7 100644 --- a/test/pyTest/testOffset.py +++ b/test/pyTest/testOffset.py @@ -102,6 +102,7 @@ def testRewrapAudioPositiveOffset(): # check output duration assert_equals( src_audioStream.getDuration() + offset, dst_audioStream.getDuration() ) + assert_equals( src_audioStream.getNbSamples() + ( offset * dst_audioStream.getSampleRate() * dst_audioStream.getChannels() ), dst_audioStream.getNbSamples() ) def testRewrapAudioNegativeOffset(): @@ -132,6 +133,7 @@ def testRewrapAudioNegativeOffset(): # check output duration assert_almost_equals( src_audioStream.getDuration() + offset, dst_audioStream.getDuration(), delta=0.01 ) + assert_equals( src_audioStream.getNbSamples() + ( offset * dst_audioStream.getSampleRate() * dst_audioStream.getChannels() ), dst_audioStream.getNbSamples() ) def testTranscodeVideoPositiveOffset(): @@ -222,6 +224,7 @@ def testRewrapVideoPositiveOffset(): # check output duration assert_equals( src_videoStream.getDuration() + offset, dst_videoStream.getDuration() ) + assert_equals( src_videoStream.getNbFrames() + ( offset * dst_videoStream.getFps() ), dst_videoStream.getNbFrames() ) def testRewrapVideoNegativeOffset(): @@ -252,6 +255,7 @@ def testRewrapVideoNegativeOffset(): # check output duration assert_equals( src_videoStream.getDuration() + offset, dst_videoStream.getDuration() ) + assert_equals( src_videoStream.getNbFrames() + ( offset * dst_videoStream.getFps() ), dst_videoStream.getNbFrames() ) def testMultipleOffsetFromSameInputFile(): @@ -276,12 +280,51 @@ def testMultipleOffsetFromSameInputFile(): src_inputFile = av.InputFile( inputFileName ) src_properties = src_inputFile.getProperties() src_videoStream = src_properties.getVideoProperties()[0] + src_audioStream = src_properties.getAudioProperties()[0] # get dst file dst_inputFile = av.InputFile( outputFileName ) dst_properties = dst_inputFile.getProperties() dst_videoStream = dst_properties.getVideoProperties()[0] + dst_audioStream = dst_properties.getAudioProperties()[0] # check output duration assert_equals( src_videoStream.getDuration() + offset_1, dst_videoStream.getDuration() ) + assert_equals( src_audioStream.getDuration() + offset_1, dst_audioStream.getDuration() ) + + +def testMultipleOffsetFromSameStream(): + """ + Process same stream several times with different offset at the beginning of the process. + """ + inputFileName = os.environ['AVTRANSCODER_TEST_AUDIO_MOV_FILE'] + outputFileName = "testMultipleOffsetFromSameStream.mov" + offset_1 = 2 + offset_2 = -2 + + ouputFile = av.OutputFile( outputFileName ) + transcoder = av.Transcoder( ouputFile ) + + transcoder.add( inputFileName, 0, "", offset_1 ) + transcoder.add( inputFileName, 0, "", offset_2 ) + + progress = av.ConsoleProgress() + transcoder.process( progress ) + + # get src file + src_inputFile = av.InputFile( inputFileName ) + src_properties = src_inputFile.getProperties() + src_videoStream = src_properties.getVideoProperties()[0] + + # get dst file + dst_inputFile = av.InputFile( outputFileName ) + dst_properties = dst_inputFile.getProperties() + dst_videoStream_1 = dst_properties.getVideoProperties()[0] + dst_videoStream_2 = dst_properties.getVideoProperties()[1] + + # check output duration + assert_equals( src_videoStream.getDuration() + offset_1, dst_videoStream_1.getDuration() ) + assert_equals( src_videoStream.getDuration() + offset_1, dst_videoStream_2.getDuration() ) + assert_almost_equals( src_videoStream.getNbFrames() + ( offset_1 * dst_videoStream_1.getFps() ), dst_videoStream_1.getNbFrames(), delta=0.01 ) + assert_almost_equals( src_videoStream.getNbFrames() + ( offset_1 * dst_videoStream_2.getFps() ), dst_videoStream_2.getNbFrames(), delta=0.01 ) diff --git a/test/pyTest/testTranscoderRewrap.py b/test/pyTest/testTranscoderRewrap.py index 61c02c5b..b36539f0 100644 --- a/test/pyTest/testTranscoderRewrap.py +++ b/test/pyTest/testTranscoderRewrap.py @@ -30,7 +30,7 @@ def testRewrapAudioStream(): ouputFile = av.OutputFile( outputFileName ) transcoder = av.Transcoder( ouputFile ) - transcoder.add( inputFileName, 0, "" ) + transcoder.add( inputFileName, 0 ) transcoder.process( progress ) # get dst file of wrap @@ -44,7 +44,7 @@ def testRewrapAudioStream(): assert_equals( src_properties.getFormatLongName(), dst_properties.getFormatLongName() ) assert_equals( src_properties.getStartTime(), dst_properties.getStartTime() ) assert_equals( src_properties.getDuration(), dst_properties.getDuration() ) - deltaBitRateAudio = 10 + deltaBitRateAudio = dst_properties.getBitRate() * 0.01 assert_almost_equals( src_properties.getBitRate(), dst_properties.getBitRate(), delta=deltaBitRateAudio ) assert_equals( src_properties.getPacketSize(), dst_properties.getPacketSize() ) @@ -52,9 +52,6 @@ def testRewrapAudioStream(): src_propertiesMap = src_audioStream.getPropertiesAsMap() dst_propertiesMap = dst_audioStream.getPropertiesAsMap() for key in src_propertiesMap: - # @todo: don't skip channel layout - if key == "channelLayout": - continue assert_equals( src_propertiesMap[key], dst_propertiesMap[key] ) def testRewrapVideoStream(): @@ -74,7 +71,7 @@ def testRewrapVideoStream(): ouputFile = av.OutputFile( outputFileName ) transcoder = av.Transcoder( ouputFile ) - transcoder.add( inputFileName, 0, "" ) + transcoder.add( inputFileName, 0 ) transcoder.process( progress ) # get dst file of wrap @@ -88,7 +85,7 @@ def testRewrapVideoStream(): assert_equals( src_properties.getFormatLongName(), dst_properties.getFormatLongName() ) assert_equals( src_properties.getStartTime(), dst_properties.getStartTime() ) assert_equals( src_properties.getDuration(), dst_properties.getDuration() ) - deltaBitRateVideo = 500000 + deltaBitRateVideo = dst_properties.getBitRate() * 0.15 assert_almost_equals( src_properties.getBitRate(), dst_properties.getBitRate(), delta=deltaBitRateVideo ) assert_equals( src_properties.getPacketSize(), dst_properties.getPacketSize() ) diff --git a/test/pyTest/testTranscoderTranscodeAudioWave.py b/test/pyTest/testTranscoderTranscodeAudioWave.py index b10ad1fe..82ab2eea 100644 --- a/test/pyTest/testTranscoderTranscodeAudioWave.py +++ b/test/pyTest/testTranscoderTranscodeAudioWave.py @@ -39,7 +39,6 @@ def testTranscodeWave24b48k5_1(): assert_equals( "s32", dst_audioStream.getSampleFormatName() ) assert_equals( "signed 32 bits", dst_audioStream.getSampleFormatLongName() ) assert_equals( 48000, dst_audioStream.getSampleRate() ) - # assert_equals( "1 channels", dst_audioStream.getChannelLayout() ) # '1 channels' != '0 channels' assert_equals( 6, dst_audioStream.getChannels() ) def testTranscodeWave24b48kstereo(): @@ -68,7 +67,6 @@ def testTranscodeWave24b48kstereo(): assert_equals( "s32", dst_audioStream.getSampleFormatName() ) assert_equals( "signed 32 bits", dst_audioStream.getSampleFormatLongName() ) assert_equals( 48000, dst_audioStream.getSampleRate() ) - # assert_equals( "1 channels", dst_audioStream.getChannelLayout() ) # '1 channels' != '0 channels' assert_equals( 2, dst_audioStream.getChannels() ) def testTranscodeWave24b48kmono(): @@ -97,7 +95,6 @@ def testTranscodeWave24b48kmono(): assert_equals( "s32", dst_audioStream.getSampleFormatName() ) assert_equals( "signed 32 bits", dst_audioStream.getSampleFormatLongName() ) assert_equals( 48000, dst_audioStream.getSampleRate() ) - # assert_equals( "1 channels", dst_audioStream.getChannelLayout() ) # '1 channels' != '0 channels' assert_equals( 1, dst_audioStream.getChannels() ) def testTranscodeWave16b48kmono(): @@ -126,5 +123,4 @@ def testTranscodeWave16b48kmono(): assert_equals( "s16", dst_audioStream.getSampleFormatName() ) assert_equals( "signed 16 bits", dst_audioStream.getSampleFormatLongName() ) assert_equals( 48000, dst_audioStream.getSampleRate() ) - # assert_equals( "1 channels", dst_audioStream.getChannelLayout() ) # '1 channels' != '0 channels' assert_equals( 1, dst_audioStream.getChannels() ) diff --git a/test/pyTest/testTranscoderTranscodeVideo.py b/test/pyTest/testTranscoderTranscodeVideo.py index 3538fe9a..5e38d7c8 100644 --- a/test/pyTest/testTranscoderTranscodeVideo.py +++ b/test/pyTest/testTranscoderTranscodeVideo.py @@ -36,7 +36,9 @@ def testTranscodeDnxhd120(): assert_equals( "dnxhd", dst_videoStream.getCodecName() ) assert_equals( "VC3/DNxHD", dst_videoStream.getCodecLongName() ) - # assert_equals( 120000000, dst_videoStream.getBitRate() ) # 120000000 != 0L + expectedBitRate = 120000000 + deltaBitRate = expectedBitRate * 0.05 + assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p", dst_videoStream.getPixelProperties().getPixelName() ) # assert_equals( 1, dst_videoStream.getGopSize() ) # 1 != 12L @@ -63,7 +65,9 @@ def testTranscodeDnxhd185(): assert_equals( "dnxhd", dst_videoStream.getCodecName() ) assert_equals( "VC3/DNxHD", dst_videoStream.getCodecLongName() ) - # assert_equals( 185000000, dst_videoStream.getBitRate() ) # 185000000 != 0L + expectedBitRate = 185000000 + deltaBitRate = expectedBitRate * 0.05 + assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p", dst_videoStream.getPixelProperties().getPixelName() ) # assert_equals( 1, dst_videoStream.getGopSize() ) # 1 != 12L @@ -90,7 +94,9 @@ def testTranscodeDnxhd185x(): assert_equals( "dnxhd", dst_videoStream.getCodecName() ) assert_equals( "VC3/DNxHD", dst_videoStream.getCodecLongName() ) - # assert_equals( 185000000, dst_videoStream.getBitRate() ) # 185000000 != 0L + expectedBitRate = 185000000 + deltaBitRate = expectedBitRate * 0.05 + assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p10le", dst_videoStream.getPixelProperties().getPixelName() ) # assert_equals( 1, dst_videoStream.getGopSize() ) # 1 != 12L @@ -125,4 +131,3 @@ def testTranscodeYUV420(): assert_equals( "mpeg2video", dst_videoStream.getCodecName() ) assert_equals( "yuv420p", dst_videoStream.getPixelProperties().getPixelName() ) -