diff --git a/CMakeLists.txt b/CMakeLists.txt index ce0dc4a0..294458dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ project(AvTranscoder) # Set AvTranscoder versions set(AVTRANSCODER_VERSION_MAJOR "0") -set(AVTRANSCODER_VERSION_MINOR "3") -set(AVTRANSCODER_VERSION_MICRO "0") +set(AVTRANSCODER_VERSION_MINOR "4") +set(AVTRANSCODER_VERSION_MICRO "1") set(AVTRANSCODER_VERSION ${AVTRANSCODER_VERSION_MAJOR}.${AVTRANSCODER_VERSION_MINOR}.${AVTRANSCODER_VERSION_MICRO}) # Define AvTranscoder versions diff --git a/README.md b/README.md index f7294798..7a681c3a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,48 @@ # avTranscoder -C++ API for LibAV / FFMpeg +C++ API for Libav / FFmpeg -Based on LibAV/FFMpeg libraries to support various video formats, avTranscoder provides the high level API to re-wrap or transcode media easily. +Based on Libav/FFmpeg libraries to support various video and audio formats, avTranscoder provides the high level API to re-wrap or transcode media easily. -You can also use its Java & Python bindings for simpler integration in your own projects. +#### What you need to know +* C++ library +* Java and Python bindings generated with SWIG +* multiplateform (Linux, MAC, Windows) +* your call to be based on Libav, FFmpeg, or your custom fork of one of these librairies + +#### How to use +Check out applications contained in the project to see examples of how to use the library in C++, Java or Python. + +To encode, avTranscoder manipulates profiles. +A profile is a text file which discribes, with a set of key-value, what we want as output for the format, the video, or the audio. +You can create your own profiles and export a variable called ```AVPROFILES``` to indicate the path to them. + +The minimum format profile is: +``` +avProfileName=profileName +avProfileLongName=profileLongName +avProfileType=avProfileTypeFormat +format=formatName +``` + +The minimum video profile is: +``` +avProfileName=profileName +avProfileLongName=profileLongName +avProfileType=avProfileTypeVideo +codec=codecName +pix_fmt=pixelFormat +r=frameRate +``` + +The minimum audio profile is: +``` +avProfileName=profileName +avProfileLongName=profileLongName +avProfileType=avProfileTypeAudio +codec=codecName +sample_fmt=sampleFormat +``` #### Continuous Integration @@ -26,8 +64,16 @@ You can also use its Java & Python bindings for simpler integration in your own Python tests using nosetests. Create environment variables to use your files in tests. -* AVTRANSCODER_TEST_AUDIO_FILE -* AVTRANSCODER_TEST_VIDEO_FILE +* ```AVTRANSCODER_TEST_AUDIO_FILE``` +* ```AVTRANSCODER_TEST_VIDEO_FILE``` + +Note: for continuous integration, we launch tests with media files contained in ```avTranscoder-data``` repository. + +Launch the tests: +``` +cd test/pyTest +nosetests +``` #### Packaging diff --git a/app/avMeta/avMeta.cpp b/app/avMeta/avMeta.cpp index d74e4ae9..ce466112 100644 --- a/app/avMeta/avMeta.cpp +++ b/app/avMeta/avMeta.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -16,7 +16,7 @@ int main( int argc, char** argv ) avtranscoder::NoDisplayProgress p; avtranscoder::InputFile input( argv[1] ); - input.analyse( p, avtranscoder::InputFile::eAnalyseLevelFull ); + input.analyse( p, avtranscoder::eAnalyseLevelFirstGop ); // a simply metadata display std::cout << input; diff --git a/app/avTranscoder/avTranscoder.cpp b/app/avTranscoder/avTranscoder.cpp index 218a3ccd..781894d7 100644 --- a/app/avTranscoder/avTranscoder.cpp +++ b/app/avTranscoder/avTranscoder.cpp @@ -28,7 +28,7 @@ void transcodeVideo( const char* inputfilename, const char* outputFilename ) InputFile input( inputfilename ); input.analyse( p ); - input.readStream( input.getProperties().videoStreams.at( 0 ).streamId ); + input.activateStream( input.getProperties().getVideoProperties().at( 0 ).getStreamId() ); // init video decoders AvInputVideo inputVideo( input.getStream( 0 ) ); diff --git a/app/avplay/AvReader.hpp b/app/avplay/AvReader.hpp index 5cda2c80..b3d1ef2f 100644 --- a/app/avplay/AvReader.hpp +++ b/app/avplay/AvReader.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include @@ -23,9 +23,9 @@ class AvReader : public Reader avtranscoder::ConsoleProgress p; _inputFile.analyse( p ); - _videoStream = _inputFile.getProperties().videoStreams.at(0).streamId; + _videoStream = _inputFile.getProperties().getVideoProperties().at(0).getStreamId(); - _inputFile.readStream( _videoStream ); + _inputFile.activateStream( _videoStream ); _inputVideo = new avtranscoder::AvInputVideo( _inputFile.getStream( _videoStream ) ); @@ -58,17 +58,17 @@ class AvReader : public Reader size_t getWidth() { - return _inputFile.getProperties().videoStreams.at(0).width; + return _inputFile.getProperties().getVideoProperties().at(0).getWidth(); }; size_t getHeight() { - return _inputFile.getProperties().videoStreams.at(0).height; + return _inputFile.getProperties().getVideoProperties().at(0).getHeight(); } size_t getComponents() { - return _inputFile.getProperties().videoStreams.at(0).componentsCount; + return _inputFile.getProperties().getVideoProperties().at(0).getComponentsCount(); } size_t getBitDepth() diff --git a/app/genericProcessor/genericProcessor.cpp b/app/genericProcessor/genericProcessor.cpp index 381c10e4..db03b50e 100644 --- a/app/genericProcessor/genericProcessor.cpp +++ b/app/genericProcessor/genericProcessor.cpp @@ -114,15 +114,11 @@ int main( int argc, char** argv ) // set verbose of all stream transcoder.setVerbose( verbose ); transcoder.setProcessMethod( avtranscoder::eProcessMethodLongest ); - //transcoder.setOutputFps( 12 ); - transcoder.init(); if( verbose ) std::cout << "start Transcode" << std::endl; avtranscoder::ConsoleProgress progress; - - // video re-wrapping or transcoding if necessary transcoder.process( progress ); std::cout << std::endl; diff --git a/app/presetChecker/presetChecker.cpp b/app/presetChecker/presetChecker.cpp index e3ca2ac7..d987f3b7 100644 --- a/app/presetChecker/presetChecker.cpp +++ b/app/presetChecker/presetChecker.cpp @@ -34,7 +34,7 @@ int main( int argc, char** argv ) if( profile.find( avtranscoder::constants::avProfileType )->second == avtranscoder::constants::avProfileTypeAudio ) { avtranscoder::AvOutputAudio outputAudio; - outputAudio.setProfile( profile, outputAudio.getAudioCodec().getFrameDesc() ); + outputAudio.setProfile( profile, outputAudio.getAudioCodec().getAudioFrameDesc() ); } } catch( ... ) diff --git a/src/AvTranscoder/ProfileLoader.hpp b/src/AvTranscoder/ProfileLoader.hpp index ed18cecf..d4d08bdf 100644 --- a/src/AvTranscoder/ProfileLoader.hpp +++ b/src/AvTranscoder/ProfileLoader.hpp @@ -13,8 +13,8 @@ namespace avtranscoder namespace constants { - const std::string avProfileIdentificator = "avProfile"; - const std::string avProfileIdentificatorHuman = "avProfileLong"; + const std::string avProfileIdentificator = "avProfileName"; + const std::string avProfileIdentificatorHuman = "avProfileLongName"; const std::string avProfileType = "avProfileType"; const std::string avProfileTypeFormat = "avProfileTypeFormat"; const std::string avProfileTypeVideo = "avProfileTypeVideo"; diff --git a/src/AvTranscoder/avTranscoder.i b/src/AvTranscoder/avTranscoder.i index 5768f912..23e0c360 100644 --- a/src/AvTranscoder/avTranscoder.i +++ b/src/AvTranscoder/avTranscoder.i @@ -15,18 +15,11 @@ %{ #include -#include -#include -#include -#include - #include #include #include #include -#include - #include #include @@ -40,43 +33,31 @@ #include #include #include - -#include -#include +#include +#include #include #include %} -namespace std { +namespace std { %template(IntPair) pair< size_t, size_t >; -%template(VideoVector) vector< avtranscoder::VideoProperties >; -%template(AudioVector) vector< avtranscoder::AudioProperties >; -%template(MetadataPair) pair< string, string >; -%template(MetadatasVector) vector< pair< string, string > >; -%template(GopPair) pair< char, bool >; -%template(GopVector) vector< pair< char, bool > >; -%template(ChannelVector) vector< avtranscoder::Channel >; %template(ProfileMap) map< string, string >; %template(ProfilesVector) vector< map< string, string > >; +%template(DataBuffer) std::vector< unsigned char >; } %include "AvTranscoder/progress/progress.i" +%include "AvTranscoder/mediaProperty/mediaProperty.i" +%include "AvTranscoder/frame/frame.i" %include -%include -%include -%include -%include - %include %include %include %include -%include - %include %include @@ -90,9 +71,10 @@ namespace std { %include %include %include +%include +%include -%include -%include +%include "AvTranscoder/file/file.i" %include %include diff --git a/src/AvTranscoder/codec/AudioCodec.cpp b/src/AvTranscoder/codec/AudioCodec.cpp index b96bbdaf..ba94746e 100644 --- a/src/AvTranscoder/codec/AudioCodec.cpp +++ b/src/AvTranscoder/codec/AudioCodec.cpp @@ -20,7 +20,7 @@ AudioCodec::AudioCodec( const ICodec& codec ) { } -AudioFrameDesc AudioCodec::getFrameDesc() const +AudioFrameDesc AudioCodec::getAudioFrameDesc() const { assert( _codecContext != NULL ); AudioFrameDesc audioFrameDesc; @@ -33,24 +33,6 @@ AudioFrameDesc AudioCodec::getFrameDesc() const return audioFrameDesc; } -const size_t AudioCodec::getSampleRate() const -{ - assert( _codecContext != NULL ); - return _codecContext->sample_rate; -} - -const size_t AudioCodec::getChannels() const -{ - assert( _codecContext != NULL ); - return _codecContext->channels; -} - -const AVSampleFormat AudioCodec::getAVSampleFormat() const -{ - assert( _codecContext != NULL ); - return _codecContext->sample_fmt; -} - void AudioCodec::setAudioParameters( const AudioFrameDesc& audioFrameDesc ) { setAudioParameters( audioFrameDesc.getSampleRate(), audioFrameDesc.getChannels(), audioFrameDesc.getAVSampleFormat() ); diff --git a/src/AvTranscoder/codec/AudioCodec.hpp b/src/AvTranscoder/codec/AudioCodec.hpp index 5d86e1aa..75c0734c 100644 --- a/src/AvTranscoder/codec/AudioCodec.hpp +++ b/src/AvTranscoder/codec/AudioCodec.hpp @@ -14,11 +14,8 @@ class AvExport AudioCodec : public ICodec AudioCodec( const ECodecType type, const AVCodecID codecId ); AudioCodec( const ICodec& codec ); - AudioFrameDesc getFrameDesc() const; - const size_t getSampleRate() const; - const size_t getChannels() const; - const AVSampleFormat getAVSampleFormat() const; - + AudioFrameDesc getAudioFrameDesc() const; + void setAudioParameters( const AudioFrameDesc& audioFrameDesc ); void setAudioParameters( const size_t sampleRate, const size_t channels, const AVSampleFormat sampleFormat ); }; diff --git a/src/AvTranscoder/codec/VideoCodec.cpp b/src/AvTranscoder/codec/VideoCodec.cpp index faae1076..f29b581b 100644 --- a/src/AvTranscoder/codec/VideoCodec.cpp +++ b/src/AvTranscoder/codec/VideoCodec.cpp @@ -23,14 +23,16 @@ VideoCodec::VideoCodec( const ICodec& codec ) VideoFrameDesc VideoCodec::getVideoFrameDesc() const { assert( _codecContext != NULL ); - VideoFrameDesc VideoFrameDesc; + + VideoFrameDesc videoFrameDesc; + videoFrameDesc.setWidth ( _codecContext->width ); + videoFrameDesc.setHeight( _codecContext->height ); + videoFrameDesc.setDar( _codecContext->width, _codecContext->height ); + Pixel pixel( _codecContext->pix_fmt ); + videoFrameDesc.setPixel( pixel ); - VideoFrameDesc.setWidth ( _codecContext->width ); - VideoFrameDesc.setHeight( _codecContext->height ); - VideoFrameDesc.setPixel ( pixel ); - VideoFrameDesc.setDar ( _codecContext->height, _codecContext->width ); - return VideoFrameDesc; + return videoFrameDesc; } std::pair< size_t, size_t > VideoCodec::getTimeBase() const diff --git a/src/AvTranscoder/codedStream/AvInputStream.cpp b/src/AvTranscoder/codedStream/AvInputStream.cpp index 3f143b7f..9e7a3fad 100644 --- a/src/AvTranscoder/codedStream/AvInputStream.cpp +++ b/src/AvTranscoder/codedStream/AvInputStream.cpp @@ -17,9 +17,9 @@ AvInputStream::AvInputStream( InputFile& inputFile, const size_t streamIndex ) : IInputStream( ) , _inputFile( &inputFile ) , _codec( NULL ) - , _packetDuration( 0 ) + , _streamCache() , _streamIndex( streamIndex ) - , _bufferized( false ) + , _isActivated( false ) { AVCodecContext* context = _inputFile->getFormatContext().streams[_streamIndex]->codec; @@ -36,13 +36,6 @@ AvInputStream::AvInputStream( InputFile& inputFile, const size_t streamIndex ) } case AVMEDIA_TYPE_AUDIO: { - double outputFps = 25; - size_t bytePerSample = av_get_bytes_per_sample( context->sample_fmt ); - - context->block_align = 1.0 * context->sample_rate * context->channels * bytePerSample / outputFps; - // std::cout << "channels " << context->channel_layout << std::endl; - // std::cout << "audio buffer read size " << context->block_align << std::endl; - AudioCodec* audioCodec = new AudioCodec( eCodecTypeDecoder, context->codec_id ); audioCodec->setAudioParameters( context->sample_rate, context->channels, context->sample_fmt ); @@ -65,8 +58,9 @@ AvInputStream::AvInputStream( const AvInputStream& inputStream ) : IInputStream( ) , _inputFile( inputStream._inputFile ) , _codec( inputStream._codec ) + , _streamCache() , _streamIndex( inputStream._streamIndex ) - , _bufferized( inputStream._bufferized ) + , _isActivated( inputStream._isActivated ) { } @@ -77,47 +71,33 @@ AvInputStream::~AvInputStream( ) bool AvInputStream::readNextPacket( CodedData& data ) { - if( ! _bufferized ) - throw std::runtime_error( "Can't read packet on non-bufferized input stream." ); - - if( _streamCache.empty() ) - _inputFile->readNextPacket( _streamIndex ); - - if( _streamCache.empty() ) - return false; - - _streamCache.front().getBuffer().swap( data.getBuffer() ); + if( ! _isActivated ) + throw std::runtime_error( "Can't read packet on non-activated input stream." ); - _streamCache.erase( _streamCache.begin() ); + // if packet is already cached + if( ! _streamCache.empty() ) + { + _streamCache.front().getBuffer().swap( data.getBuffer() ); + _streamCache.pop(); + } + // else read next packet + else + { + return _inputFile->readNextPacket( data, _streamIndex ) && _streamCache.empty(); + } return true; } void AvInputStream::addPacket( AVPacket& packet ) { - //std::cout << "add packet for stream " << _streamIndex << std::endl; - CodedData data; - _streamCache.push_back( data ); - _packetDuration = packet.duration; - - if( ! _bufferized ) + // Do not cache data if the stream is declared as unused in process + if( ! _isActivated ) return; - // is it possible to remove this copy ? - // using : av_packet_unref ? - _streamCache.back().getBuffer().resize( packet.size ); - if( packet.size != 0 ) - memcpy( _streamCache.back().getPtr(), packet.data, packet.size ); - - // std::vector tmpData( 0,0 ); - // &tmpData[0] = packet.data; - // tmpData.size( packet.size ); - - // remove reference on packet because it's passed to CodedData - // packet.data = NULL; - // packet.size = 0; - - // std::cout << this << " buffer size " << _streamCache.size() << std::endl; + CodedData data; + _streamCache.push( data ); + _streamCache.back().copyData( packet.data, packet.size ); } VideoCodec& AvInputStream::getVideoCodec() @@ -166,14 +146,9 @@ double AvInputStream::getDuration() const return 1.0 * _inputFile->getFormatContext().duration / AV_TIME_BASE; } -double AvInputStream::getPacketDuration() const -{ - return _packetDuration * av_q2d( _inputFile->getFormatContext().streams[_streamIndex]->time_base ); -} - void AvInputStream::clearBuffering() { - _streamCache.clear(); + _streamCache = std::queue(); } AVStream* AvInputStream::getAVStream() const diff --git a/src/AvTranscoder/codedStream/AvInputStream.hpp b/src/AvTranscoder/codedStream/AvInputStream.hpp index e13ebbdf..88aed087 100644 --- a/src/AvTranscoder/codedStream/AvInputStream.hpp +++ b/src/AvTranscoder/codedStream/AvInputStream.hpp @@ -3,6 +3,8 @@ #include "IInputStream.hpp" +#include + struct AVStream; namespace avtranscoder @@ -30,12 +32,11 @@ class AvExport AvInputStream : public IInputStream AVMediaType getStreamType() const; double getDuration() const; - double getPacketDuration() const; void addPacket( AVPacket& packet ); - void setBufferred( const bool bufferized ){ _bufferized = bufferized; }; - bool getBufferred() const { return _bufferized; }; + void activate( const bool activate = true ){ _isActivated = activate; }; + bool isActivated() const { return _isActivated; }; void clearBuffering(); @@ -43,14 +44,13 @@ class AvExport AvInputStream : public IInputStream AVStream* getAVStream() const; private: - InputFile* _inputFile; - std::vector _streamCache; - + InputFile* _inputFile; ///< Has link (no ownership) ICodec* _codec; ///< Has ownership - int _packetDuration; - size_t _streamIndex; - bool _bufferized; + std::queue _streamCache; ///< Cache of packet data already read and corresponding to this stream + + size_t _streamIndex; ///< Index of the stream in the input file + bool _isActivated; ///< If the stream is activated, data read from it will be buffered }; } diff --git a/src/AvTranscoder/codedStream/AvOutputStream.hpp b/src/AvTranscoder/codedStream/AvOutputStream.hpp index 2b23ea83..bda78453 100644 --- a/src/AvTranscoder/codedStream/AvOutputStream.hpp +++ b/src/AvTranscoder/codedStream/AvOutputStream.hpp @@ -18,9 +18,9 @@ class AvExport AvOutputStream : public IOutputStream IOutputStream::EWrappingStatus wrap( const CodedData& data ); private: - OutputFile* _outputFile; + OutputFile* _outputFile; ///< Has link (no ownership) - size_t _streamIndex; + size_t _streamIndex; ///< Index of the stream in the output file }; } diff --git a/src/AvTranscoder/codedStream/IInputStream.hpp b/src/AvTranscoder/codedStream/IInputStream.hpp index 1557b0e7..13074fa1 100644 --- a/src/AvTranscoder/codedStream/IInputStream.hpp +++ b/src/AvTranscoder/codedStream/IInputStream.hpp @@ -26,9 +26,9 @@ class IInputStream virtual AVMediaType getStreamType() const = 0; virtual double getDuration() const = 0; - virtual double getPacketDuration() const = 0; - virtual void setBufferred( const bool bufferized ) = 0; + virtual void activate( const bool activate = true ) = 0; + virtual bool isActivated() const = 0; virtual void clearBuffering() = 0; diff --git a/src/AvTranscoder/essenceStream/AvInputAudio.cpp b/src/AvTranscoder/essenceStream/AvInputAudio.cpp index 0187f20e..77711fc9 100644 --- a/src/AvTranscoder/essenceStream/AvInputAudio.cpp +++ b/src/AvTranscoder/essenceStream/AvInputAudio.cpp @@ -20,9 +20,8 @@ namespace avtranscoder AvInputAudio::AvInputAudio( AvInputStream& inputStream ) : IInputEssence() , _inputStream ( &inputStream ) - , _codec( eCodecTypeDecoder, inputStream.getAudioCodec().getCodecId() ) + , _codec( &inputStream.getAudioCodec() ) , _frame ( NULL ) - , _selectedStream( -1 ) { } @@ -46,10 +45,10 @@ AvInputAudio::~AvInputAudio() void AvInputAudio::setup() { - AVCodecContext* avCodecContext = _codec.getAVCodecContext(); - AVCodec* avCodec = _codec.getAVCodec(); + AVCodecContext* avCodecContext = _codec->getAVCodecContext(); + AVCodec* avCodec = _codec->getAVCodec(); - avCodecContext->channels = _inputStream->getAudioCodec().getChannels(); + avCodecContext->channels = _inputStream->getAudioCodec().getAudioFrameDesc().getChannels(); int ret = avcodec_open2( avCodecContext, avCodec, NULL ); @@ -59,13 +58,13 @@ void AvInputAudio::setup() msg += avCodec->long_name; msg += " ("; msg += avCodec->name; - msg += ")"; + msg += ") "; avcodec_close( avCodecContext ); - char err[250]; + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); + msg += err; - av_strerror( ret, err, 250 ); - std::cout << err << std::endl; throw std::runtime_error( msg ); } @@ -82,15 +81,12 @@ void AvInputAudio::setup() bool AvInputAudio::readNextFrame( Frame& frameBuffer ) { - if( ! getNextFrame() ) + if( ! decodeNextFrame() ) return false; - AVCodecContext* avCodecContext = _codec.getAVCodecContext(); + AVCodecContext* avCodecContext = _codec->getAVCodecContext(); - size_t decodedSize = av_samples_get_buffer_size( - NULL, avCodecContext->channels, - _frame->nb_samples, - avCodecContext->sample_fmt, 1 ); + size_t decodedSize = av_samples_get_buffer_size( NULL, avCodecContext->channels, _frame->nb_samples, avCodecContext->sample_fmt, 1 ); AudioFrame& audioBuffer = static_cast( frameBuffer ); @@ -105,10 +101,7 @@ bool AvInputAudio::readNextFrame( Frame& frameBuffer ) unsigned char* const src = _frame->data[0]; unsigned char* dst = audioBuffer.getPtr(); - av_samples_copy( - &dst, &src, 0, - 0, _frame->nb_samples, avCodecContext->channels, - avCodecContext->sample_fmt ); + av_samples_copy( &dst, &src, 0, 0, _frame->nb_samples, avCodecContext->channels, avCodecContext->sample_fmt ); } return true; @@ -116,14 +109,14 @@ bool AvInputAudio::readNextFrame( Frame& frameBuffer ) bool AvInputAudio::readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ) { - if( ! getNextFrame() ) + if( ! decodeNextFrame() ) return false; const int output_nbChannels = 1; const int output_align = 1; - size_t decodedSize = av_samples_get_buffer_size(NULL, output_nbChannels, _frame->nb_samples, _codec.getAVCodecContext()->sample_fmt, output_align); + size_t decodedSize = av_samples_get_buffer_size(NULL, output_nbChannels, _frame->nb_samples, _codec->getAVCodecContext()->sample_fmt, output_align); - size_t nbSubStreams = _codec.getAVCodecContext()->channels; + size_t nbSubStreams = _codec->getAVCodecContext()->channels; size_t bytePerSample = av_get_bytes_per_sample( (AVSampleFormat)_frame->format ); if( subStreamIndex > nbSubStreams - 1 ) @@ -156,33 +149,34 @@ bool AvInputAudio::readNextFrame( Frame& frameBuffer, const size_t subStreamInde return true; } -bool AvInputAudio::getNextFrame() +bool AvInputAudio::decodeNextFrame() { int got_frame = 0; while( ! got_frame ) { CodedData data; - if( ! _inputStream->readNextPacket( data ) ) // error or end of file - return false; AVPacket packet; av_init_packet( &packet ); - packet.stream_index = _selectedStream; - packet.data = data.getPtr(); - packet.size = data.getSize(); + bool nextPacketRead = _inputStream->readNextPacket( data ); + + packet.stream_index = _inputStream->getStreamIndex(); + packet.data = nextPacketRead ? data.getPtr(): NULL; + packet.size = data.getSize(); - int ret = avcodec_decode_audio4( _codec.getAVCodecContext(), _frame, &got_frame, &packet ); + int ret = avcodec_decode_audio4( _codec->getAVCodecContext(), _frame, &got_frame, &packet ); + av_free_packet( &packet ); + if( ! nextPacketRead && ret == 0 && got_frame == 0 ) // error or end of file + return false; + if( ret < 0 ) { - char err[250]; - av_strerror( ret, err, 250 ); - + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); throw std::runtime_error( "an error occured during audio decoding" + std::string( err ) ); } - - av_free_packet( &packet ); } return true; } diff --git a/src/AvTranscoder/essenceStream/AvInputAudio.hpp b/src/AvTranscoder/essenceStream/AvInputAudio.hpp index 394fbf0d..2ee95a9d 100644 --- a/src/AvTranscoder/essenceStream/AvInputAudio.hpp +++ b/src/AvTranscoder/essenceStream/AvInputAudio.hpp @@ -23,13 +23,11 @@ class AvExport AvInputAudio : public IInputEssence bool readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); private: - bool getNextFrame(); + bool decodeNextFrame(); - AvInputStream* _inputStream; - AudioCodec _codec; - AVFrame* _frame; - - int _selectedStream; + AvInputStream* _inputStream; ///< Stream from which we read next frames + const AudioCodec* _codec; ///< Audio decoder. Has link (no ownership) + AVFrame* _frame; ///< Libav object to store decoded data }; } diff --git a/src/AvTranscoder/essenceStream/AvInputVideo.cpp b/src/AvTranscoder/essenceStream/AvInputVideo.cpp index f11e7e12..a50fabb6 100644 --- a/src/AvTranscoder/essenceStream/AvInputVideo.cpp +++ b/src/AvTranscoder/essenceStream/AvInputVideo.cpp @@ -20,7 +20,7 @@ namespace avtranscoder AvInputVideo::AvInputVideo( AvInputStream& inputStream ) : IInputEssence() , _inputStream ( &inputStream ) - , _codec( eCodecTypeDecoder, inputStream.getVideoCodec().getCodecId() ) + , _codec( &inputStream.getVideoCodec() ) , _frame ( NULL ) { } @@ -44,8 +44,8 @@ AvInputVideo::~AvInputVideo() void AvInputVideo::setup() { - AVCodecContext* avCodecContext = _codec.getAVCodecContext(); - AVCodec* avCodec = _codec.getAVCodec(); + AVCodecContext* avCodecContext = _codec->getAVCodecContext(); + AVCodec* avCodec = _codec->getAVCodec(); // if( avCodec->capabilities & CODEC_CAP_TRUNCATED ) // avCodecContext->flags |= CODEC_FLAG_TRUNCATED; @@ -76,8 +76,32 @@ void AvInputVideo::setup() bool AvInputVideo::readNextFrame( Frame& frameBuffer ) { - int got_frame = 0; + if( ! decodeNextFrame() ) + return false; + + VideoFrame& imageBuffer = static_cast( frameBuffer ); + + size_t decodedSize = avpicture_get_size( (AVPixelFormat)_frame->format, _frame->width, _frame->height ); + if( ! decodedSize ) + return false; + + if( imageBuffer.getBuffer().size() != decodedSize ) + imageBuffer.getBuffer().resize( decodedSize ); + + // Copy pixel data from an AVPicture into one contiguous buffer. + avpicture_layout( (AVPicture*)_frame, (AVPixelFormat)_frame->format, _frame->width, _frame->height, &imageBuffer.getBuffer()[0], frameBuffer.getBuffer().size() ); + + return true; +} + +bool AvInputVideo::readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ) +{ + return false; +} +bool AvInputVideo::decodeNextFrame() +{ + int got_frame = 0; while( ! got_frame ) { CodedData data; @@ -86,52 +110,35 @@ bool AvInputVideo::readNextFrame( Frame& frameBuffer ) av_init_packet( &packet ); bool nextPacketRead = _inputStream->readNextPacket( data ); - + packet.stream_index = _inputStream->getStreamIndex(); packet.data = nextPacketRead ? data.getPtr(): NULL; packet.size = data.getSize(); - int ret = avcodec_decode_video2( _codec.getAVCodecContext(), _frame, &got_frame, &packet ); - + int ret = avcodec_decode_video2( _codec->getAVCodecContext(), _frame, &got_frame, &packet ); av_free_packet( &packet ); - if( ! nextPacketRead && ret == 0 && got_frame == 0 ) + if( ! nextPacketRead && ret == 0 && got_frame == 0 ) // error or end of file return false; if( ret < 0 ) { - char err[250]; - av_strerror( ret, err, 250); - + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); throw std::runtime_error( "an error occured during video decoding - " + std::string(err) ); } } - - VideoFrame& imageBuffer = static_cast( frameBuffer ); - - size_t decodedSize = avpicture_get_size( (AVPixelFormat)_frame->format, _frame->width, _frame->height ); - if( imageBuffer.getBuffer().size() != decodedSize ) - imageBuffer.getBuffer().resize( decodedSize ); - - // Copy pixel data from an AVPicture into one contiguous buffer. - avpicture_layout( (AVPicture*)_frame, (AVPixelFormat)_frame->format, _frame->width, _frame->height, &imageBuffer.getBuffer()[0], frameBuffer.getBuffer().size() ); - return true; } -bool AvInputVideo::readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ) -{ - return false; -} - void AvInputVideo::flushDecoder() { - avcodec_flush_buffers( _codec.getAVCodecContext() ); + avcodec_flush_buffers( _codec->getAVCodecContext() ); } void AvInputVideo::setProfile( const ProfileLoader::Profile& profile ) { - Context codecContext( _codec.getAVCodecContext() ); + Context codecContext( _codec->getAVCodecContext() ); for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it ) { diff --git a/src/AvTranscoder/essenceStream/AvInputVideo.hpp b/src/AvTranscoder/essenceStream/AvInputVideo.hpp index 9132662c..90b7e03f 100644 --- a/src/AvTranscoder/essenceStream/AvInputVideo.hpp +++ b/src/AvTranscoder/essenceStream/AvInputVideo.hpp @@ -28,9 +28,12 @@ class AvExport AvInputVideo : public IInputEssence void setProfile( const ProfileLoader::Profile& profile ); private: - AvInputStream* _inputStream; - VideoCodec _codec; - AVFrame* _frame; + bool decodeNextFrame(); + +private: + AvInputStream* _inputStream; ///< Stream from which we read next frames + const VideoCodec* _codec; ///< Video decoder. Has link (no ownership) + AVFrame* _frame; ///< Libav object to store decoded data }; } diff --git a/src/AvTranscoder/essenceStream/AvOutputAudio.cpp b/src/AvTranscoder/essenceStream/AvOutputAudio.cpp index 1f1100ce..0cfe67ce 100644 --- a/src/AvTranscoder/essenceStream/AvOutputAudio.cpp +++ b/src/AvTranscoder/essenceStream/AvOutputAudio.cpp @@ -34,8 +34,8 @@ void AvOutputAudio::setup() int ret = avcodec_open2( codecContext, _codec.getAVCodec(), NULL ); if( ret < 0 ) { - char err[250]; - av_strerror( ret, err, 250); + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); std::string msg = "could not open audio encoder: "; msg += err; throw std::runtime_error( msg ); @@ -69,18 +69,16 @@ bool AvOutputAudio::encodeFrame( const Frame& sourceFrame, Frame& codedFrame ) int buffer_size = av_samples_get_buffer_size( NULL, codecContext->channels, frame->nb_samples, codecContext->sample_fmt, 0 ); if( buffer_size < 0 ) { - char err[250]; - av_strerror( buffer_size, err, 250 ); - + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( buffer_size, err, sizeof(err) ); throw std::runtime_error( "EncodeFrame error: buffer size < 0 - " + std::string(err) ); } int retvalue = avcodec_fill_audio_frame( frame, codecContext->channels, codecContext->sample_fmt, sourceAudioFrame.getPtr(), buffer_size, 0 ); if( retvalue < 0 ) { - char err[250]; - av_strerror( retvalue, err, 250); - + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( retvalue, err, sizeof(err) ); throw std::runtime_error( "EncodeFrame error: avcodec fill audio frame - " + std::string( err ) ); } @@ -108,15 +106,13 @@ bool AvOutputAudio::encodeFrame( const Frame& sourceFrame, Frame& codedFrame ) int ret = avcodec_encode_audio2( codecContext, &packet, frame, &gotPacket ); if( ret == 0 && gotPacket == 1 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } #else int ret = avcodec_encode_audio( codecContext, packet.data, packet.size, frame ); if( ret > 0 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } #endif @@ -152,8 +148,7 @@ bool AvOutputAudio::encodeFrame( Frame& codedFrame ) int ret = avcodec_encode_audio2( codecContext, &packet, NULL, &gotPacket ); if( ret == 0 && gotPacket == 1 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } av_free_packet( &packet ); return ret == 0 && gotPacket == 1; @@ -162,8 +157,7 @@ bool AvOutputAudio::encodeFrame( Frame& codedFrame ) int ret = avcodec_encode_audio( codecContext, packet.data, packet.size, NULL ); if( ret > 0 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } av_free_packet( &packet ); return ret == 0; diff --git a/src/AvTranscoder/essenceStream/AvOutputVideo.cpp b/src/AvTranscoder/essenceStream/AvOutputVideo.cpp index 128e3e22..1444d3e2 100644 --- a/src/AvTranscoder/essenceStream/AvOutputVideo.cpp +++ b/src/AvTranscoder/essenceStream/AvOutputVideo.cpp @@ -35,8 +35,8 @@ void AvOutputVideo::setup( ) int ret = avcodec_open2( codecContext, _codec.getAVCodec(), NULL ); if( ret < 0 ) { - char err[250]; - av_strerror( ret, err, 250); + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); std::string msg = "could not open video encoder: "; msg += err; throw std::runtime_error( msg ); @@ -92,36 +92,16 @@ bool AvOutputVideo::encodeFrame( const Frame& sourceFrame, Frame& codedFrame ) int ret = avcodec_encode_video2( codecContext, &packet, frame, &gotPacket ); if( ret == 0 && gotPacket == 1 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } #else int ret = avcodec_encode_video( codecContext, packet.data, packet.size, frame ); if( ret > 0 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } #endif -/* - std::string imgType = ""; - switch( codecContext->coded_frame->pict_type ) - { - case AV_PICTURE_TYPE_NONE : imgType = "None"; break; - case AV_PICTURE_TYPE_I : imgType = "I"; break; - case AV_PICTURE_TYPE_P : imgType = "P"; break; - case AV_PICTURE_TYPE_B : imgType = "B"; break; - case AV_PICTURE_TYPE_S : imgType = "S"; break; - case AV_PICTURE_TYPE_SI : imgType = "SI"; break; - case AV_PICTURE_TYPE_SP : imgType = "SP"; break; - case AV_PICTURE_TYPE_BI : imgType = "BI"; break; - } - std::clog << "\tframe " << codecContext->coded_frame->display_picture_number; - std::clog << " coded @ " << codecContext->coded_frame->coded_picture_number; - std::clog << " type : " << imgType; - std::clog << " quality : " << codecContext->coded_frame->quality << std::endl; -*/ av_free_packet( &packet ); #if LIBAVCODEC_VERSION_MAJOR > 54 av_frame_free( &frame ); @@ -153,8 +133,7 @@ bool AvOutputVideo::encodeFrame( Frame& codedFrame ) int ret = avcodec_encode_video2( codecContext, &packet, NULL, &gotPacket ); if( ret == 0 && gotPacket == 1 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } av_free_packet( &packet ); return ret == 0 && gotPacket == 1; @@ -163,8 +142,7 @@ bool AvOutputVideo::encodeFrame( Frame& codedFrame ) int ret = avcodec_encode_video( codecContext, packet.data, packet.size, NULL ); if( ret > 0 ) { - codedFrame.getBuffer().resize( packet.size ); - memcpy( codedFrame.getPtr(), packet.data, packet.size ); + codedFrame.copyData( packet.data, packet.size ); } av_free_packet( &packet ); return ret == 0; diff --git a/src/AvTranscoder/essenceStream/GeneratorAudio.cpp b/src/AvTranscoder/essenceStream/GeneratorAudio.cpp index bd13ef4d..7c34a852 100644 --- a/src/AvTranscoder/essenceStream/GeneratorAudio.cpp +++ b/src/AvTranscoder/essenceStream/GeneratorAudio.cpp @@ -5,25 +5,15 @@ namespace avtranscoder GeneratorAudio::GeneratorAudio( ) : IInputEssence( ) - , _codec( NULL ) , _inputFrame( NULL ) , _frameDesc() { } -void GeneratorAudio::setAudioCodec( const AudioCodec& codec ) +void GeneratorAudio::setAudioFrameDesc( const AudioFrameDesc& frameDesc ) { - _frameDesc.setFps ( 25.0 ); - _codec = &codec; - - _frameDesc.setSampleRate( _codec->getAVCodecContext()->sample_rate ); - _frameDesc.setChannels( _codec->getAVCodecContext()->channels ); - _frameDesc.setSampleFormat( _codec->getAVCodecContext()->sample_fmt ); -} - -const AudioCodec& GeneratorAudio::getAudioCodec() -{ - return *_codec; + _frameDesc = frameDesc; + _frameDesc.setFps( 25. ); } void GeneratorAudio::setFrame( Frame& inputFrame ) @@ -33,8 +23,6 @@ void GeneratorAudio::setFrame( Frame& inputFrame ) bool GeneratorAudio::readNextFrame( Frame& frameBuffer ) { - frameBuffer.getBuffer().resize( _frameDesc.getDataSize() ); - if( ! _inputFrame ) { AudioFrame& audioFrameBuffer = static_cast( frameBuffer ); @@ -46,13 +34,14 @@ bool GeneratorAudio::readNextFrame( Frame& frameBuffer ) _frameDesc.getAVSampleFormat() == AV_SAMPLE_FMT_U8P ) ? 0x80 : 0x00; + if( frameBuffer.getSize() != _frameDesc.getDataSize() ) + frameBuffer.getBuffer().resize( _frameDesc.getDataSize() ); memset( frameBuffer.getPtr(), fill_char, frameBuffer.getSize() ); - return true; } - - if( frameBuffer.getSize() != _inputFrame->getSize() ) - frameBuffer.getBuffer().resize( _inputFrame->getSize() ); - std::memcpy( frameBuffer.getPtr(), _inputFrame->getPtr(), _inputFrame->getSize() ); + else + { + frameBuffer.copyData( _inputFrame->getPtr(), _inputFrame->getSize() ); + } return true; } diff --git a/src/AvTranscoder/essenceStream/GeneratorAudio.hpp b/src/AvTranscoder/essenceStream/GeneratorAudio.hpp index 0c8e80d1..2f14c946 100644 --- a/src/AvTranscoder/essenceStream/GeneratorAudio.hpp +++ b/src/AvTranscoder/essenceStream/GeneratorAudio.hpp @@ -12,9 +12,8 @@ class AvExport GeneratorAudio : public IInputEssence public: GeneratorAudio( ); - void setAudioCodec( const AudioCodec& codec ); - - const AudioCodec& getAudioCodec(); + AudioFrameDesc& getAudioFrameDesc() { return _frameDesc; } + void setAudioFrameDesc( const AudioFrameDesc& frameDesc ); void setup() {} @@ -24,8 +23,7 @@ class AvExport GeneratorAudio : public IInputEssence bool readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); private: - const AudioCodec* _codec; - Frame* _inputFrame; + Frame* _inputFrame; ///< Has link (no ownership) AudioFrameDesc _frameDesc; }; diff --git a/src/AvTranscoder/essenceStream/GeneratorVideo.cpp b/src/AvTranscoder/essenceStream/GeneratorVideo.cpp index e1a37861..b9de5f3a 100644 --- a/src/AvTranscoder/essenceStream/GeneratorVideo.cpp +++ b/src/AvTranscoder/essenceStream/GeneratorVideo.cpp @@ -7,22 +7,14 @@ namespace avtranscoder GeneratorVideo::GeneratorVideo( ) : IInputEssence( ) - , _codec( NULL ) , _inputFrame( NULL ) - , _videoFrameDesc() - , _numberOfView( 1 ) + , _frameDesc() { } -void GeneratorVideo::setVideoCodec( const VideoCodec& codec ) +void GeneratorVideo::setVideoFrameDesc( const VideoFrameDesc& frameDesc ) { - _codec = &codec; - _videoFrameDesc = _codec->getVideoFrameDesc(); -} - -const VideoCodec& GeneratorVideo::getVideoCodec() -{ - return *_codec; + _frameDesc = frameDesc; } void GeneratorVideo::setFrame( Frame& inputFrame ) @@ -32,33 +24,30 @@ void GeneratorVideo::setFrame( Frame& inputFrame ) bool GeneratorVideo::readNextFrame( Frame& frameBuffer ) { + // Generate black image if( ! _inputFrame ) { // @todo support PAL (0 to 255) and NTFS (16 to 235) - int fillChar = 0; - - if( frameBuffer.getSize() != _videoFrameDesc.getDataSize() ) - frameBuffer.getBuffer().resize( _videoFrameDesc.getDataSize() ); + char fillChar = 0; - VideoFrameDesc desc( _codec->getVideoFrameDesc() ); + VideoFrameDesc desc( _frameDesc ); Pixel rgbPixel; rgbPixel.setColorComponents( eComponentRgb ); rgbPixel.setPlanar( false ); desc.setPixel( rgbPixel ); VideoFrame intermediateBuffer( desc ); - intermediateBuffer.getBuffer().resize( _videoFrameDesc.getDataSize() ); - memset( intermediateBuffer.getPtr(), fillChar, _videoFrameDesc.getDataSize() ); + intermediateBuffer.getBuffer().resize( _frameDesc.getDataSize() ); + memset( intermediateBuffer.getPtr(), fillChar, _frameDesc.getDataSize() ); VideoTransform videoEssenceTransform; videoEssenceTransform.convert( intermediateBuffer, frameBuffer ); - - return true; } - - if( frameBuffer.getSize() != _inputFrame->getSize() ) - frameBuffer.getBuffer().resize( _inputFrame->getSize() ); - std::memcpy( frameBuffer.getPtr(), _inputFrame->getPtr(), _inputFrame->getSize() ); + // Take image from _inputFrame + else + { + frameBuffer.copyData( _inputFrame->getPtr(), _inputFrame->getSize() ); + } return true; } diff --git a/src/AvTranscoder/essenceStream/GeneratorVideo.hpp b/src/AvTranscoder/essenceStream/GeneratorVideo.hpp index 54a206ab..f32513bf 100644 --- a/src/AvTranscoder/essenceStream/GeneratorVideo.hpp +++ b/src/AvTranscoder/essenceStream/GeneratorVideo.hpp @@ -12,10 +12,8 @@ class AvExport GeneratorVideo : public IInputEssence public: GeneratorVideo( ); - // Stream properties - void setVideoCodec( const VideoCodec& codec ); - - const VideoCodec& getVideoCodec(); + VideoFrameDesc& getVideoFrameDesc() { return _frameDesc; } + void setVideoFrameDesc( const VideoFrameDesc& frameDesc ); void setup() {} @@ -25,11 +23,8 @@ class AvExport GeneratorVideo : public IInputEssence bool readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ); private: - const VideoCodec* _codec; - Frame* _inputFrame; - VideoFrameDesc _videoFrameDesc; - - size_t _numberOfView; + Frame* _inputFrame; ///< Has link (no ownership) + VideoFrameDesc _frameDesc; }; } diff --git a/src/AvTranscoder/essenceStream/IInputEssence.hpp b/src/AvTranscoder/essenceStream/IInputEssence.hpp index 33f7968a..8e232dc0 100644 --- a/src/AvTranscoder/essenceStream/IInputEssence.hpp +++ b/src/AvTranscoder/essenceStream/IInputEssence.hpp @@ -31,6 +31,13 @@ class AvExport IInputEssence * @return status of decoding */ virtual bool readNextFrame( Frame& frameBuffer, const size_t subStreamIndex ) = 0; + + /** + * Set the next frame of the input stream + * @note Not yet implemented for AvInputVideo and AvInputAudio + * @param inputFrame: the new next frame + */ + virtual void setFrame( Frame& inputFrame ) {} }; } diff --git a/src/AvTranscoder/file/InputFile.cpp b/src/AvTranscoder/file/InputFile.cpp index 79c50753..e8885dfa 100644 --- a/src/AvTranscoder/file/InputFile.cpp +++ b/src/AvTranscoder/file/InputFile.cpp @@ -1,13 +1,13 @@ #include "InputFile.hpp" #include -#include -#include -#include -#include -#include -#include - +#include +#include +#include +#include +#include +#include +#include extern "C" { #include @@ -24,7 +24,8 @@ namespace avtranscoder InputFile::InputFile( const std::string& filename ) : _formatContext ( NULL ) - , _filename ( filename ) + , _properties( NULL ) + , _filename( filename ) { av_register_all(); if( avformat_open_input( &_formatContext, _filename.c_str(), NULL, NULL ) < 0 ) @@ -42,6 +43,10 @@ InputFile::InputFile( const std::string& filename ) throw std::runtime_error( "unable to find stream informations" ); } + // Initialize FileProperties + _properties = FileProperties( _formatContext ); + + // Create streams for( size_t streamIndex = 0; streamIndex < _formatContext->nb_streams; ++streamIndex ) { _inputStreams.push_back( new AvInputStream( *this, streamIndex ) ); @@ -68,56 +73,44 @@ InputFile& InputFile::analyse( IProgress& progress, const EAnalyseLevel level ) seekAtFrame( 0 ); - _properties.filename = _formatContext->filename; - _properties.formatName = _formatContext->iformat->name; - _properties.formatLongName = _formatContext->iformat->long_name; - _properties.streamsCount = _formatContext->nb_streams; - _properties.programsCount = _formatContext->nb_programs; - _properties.startTime = 1.0 * (unsigned int)_formatContext->start_time / AV_TIME_BASE; - _properties.duration = 1.0 * _formatContext->duration / AV_TIME_BASE; - _properties.bitRate = _formatContext->bit_rate; - _properties.packetSize = _formatContext->packet_size; - - detail::fillMetadataDictionnary( _formatContext->metadata, _properties.metadatas ); - for( size_t streamId = 0; streamId < _formatContext->nb_streams; streamId++ ) { switch( _formatContext->streams[streamId]->codec->codec_type ) { case AVMEDIA_TYPE_VIDEO: { - _properties.videoStreams.push_back( videoStreamInfo( _formatContext, streamId, progress, level ) ); - detail::fillMetadataDictionnary( _formatContext->streams[streamId]->metadata, _properties.videoStreams.back().metadatas ); + VideoProperties properties( _formatContext, streamId, progress, level ); + _properties.getVideoProperties().push_back( properties ); break; } case AVMEDIA_TYPE_AUDIO: { - _properties.audioStreams.push_back( audioStreamInfo( _formatContext, streamId ) ); - detail::fillMetadataDictionnary( _formatContext->streams[streamId]->metadata, _properties.audioStreams.back().metadatas ); + AudioProperties properties( _formatContext, streamId ); + _properties.getAudioProperties().push_back( properties ); break; } case AVMEDIA_TYPE_DATA: { - _properties.dataStreams.push_back( dataStreamInfo( _formatContext, streamId ) ); - detail::fillMetadataDictionnary( _formatContext->streams[streamId]->metadata, _properties.dataStreams.back().metadatas ); + DataProperties properties( _formatContext, streamId ); + _properties.getDataProperties().push_back( properties ); break; } case AVMEDIA_TYPE_SUBTITLE: { - _properties.subtitleStreams.push_back( subtitleStreamInfo( _formatContext, streamId ) ); - detail::fillMetadataDictionnary( _formatContext->streams[streamId]->metadata, _properties.subtitleStreams.back().metadatas ); + SubtitleProperties properties( _formatContext, streamId ); + _properties.getSubtitleProperties().push_back( properties ); break; } case AVMEDIA_TYPE_ATTACHMENT: { - _properties.attachementStreams.push_back( attachementStreamInfo( _formatContext, streamId ) ); - detail::fillMetadataDictionnary( _formatContext->streams[streamId]->metadata, _properties.attachementStreams.back().metadatas ); + AttachementProperties properties( _formatContext, streamId ); + _properties.getAttachementProperties().push_back( properties ); break; } case AVMEDIA_TYPE_UNKNOWN: { - _properties.unknownStreams.push_back( unknownStreamInfo( _formatContext, streamId ) ); - detail::fillMetadataDictionnary( _formatContext->streams[streamId]->metadata, _properties.unknownStreams.back().metadatas ); + UnknownProperties properties( _formatContext, streamId ); + _properties.getUnknownPropertiesProperties().push_back( properties ); break; } case AVMEDIA_TYPE_NB: @@ -132,13 +125,11 @@ InputFile& InputFile::analyse( IProgress& progress, const EAnalyseLevel level ) return *this; } -Properties InputFile::analyseFile( const std::string& filename, IProgress& progress, const EAnalyseLevel level ) +FileProperties InputFile::analyseFile( const std::string& filename, IProgress& progress, const EAnalyseLevel level ) { InputFile file( filename ); file.analyse( progress, level ); - Properties properties; - file.getProperties( properties ); - return properties; + return file.getProperties(); } AVMediaType InputFile::getStreamType( size_t index ) @@ -153,12 +144,13 @@ AvInputStream& InputFile::getStream( size_t index ) return *_inputStreams.at( index ); } -bool InputFile::readNextPacket( const size_t streamIndex ) +bool InputFile::readNextPacket( CodedData& data, const size_t streamIndex ) { AVPacket packet; - av_init_packet( &packet ); - while( 1 ) + bool nextPacketFound = false; + while( ! nextPacketFound ) { + av_init_packet( &packet ); int ret = av_read_frame( _formatContext, &packet ); if( ret < 0 ) // error or end of file { @@ -166,21 +158,21 @@ bool InputFile::readNextPacket( const size_t streamIndex ) return false; } - // send packet to stream buffer - _inputStreams.at( packet.stream_index )->addPacket( packet ); - - // We only read one stream and skip others + // if the packet stream is the expected one + // copy and return the packet data if( packet.stream_index == (int)streamIndex ) { - av_free_packet( &packet ); - return true; + data.copyData( packet.data, packet.size ); + nextPacketFound = true; + } + // else add the packet data to the stream cache + else + { + _inputStreams.at( packet.stream_index )->addPacket( packet ); } - - // do not delete these 2 lines - // need to skip packet, delete this one and re-init for reading the next one av_free_packet( &packet ); - av_init_packet( &packet ); } + return true; } void InputFile::seekAtFrame( const size_t frame ) @@ -201,14 +193,14 @@ void InputFile::seekAtFrame( const size_t frame ) } } -void InputFile::readStream( const size_t streamIndex, bool readStream ) +void InputFile::activateStream( const size_t streamIndex, bool activate ) { - _inputStreams.at( streamIndex )->setBufferred( readStream ); + _inputStreams.at( streamIndex )->activate( activate ); } -bool InputFile::getReadStream( const size_t streamIndex ) +bool InputFile::isStreamActivated( const size_t streamIndex ) { - return _inputStreams.at( streamIndex )->getBufferred(); + return _inputStreams.at( streamIndex )->isActivated(); } void InputFile::setProfile( const ProfileLoader::Profile& profile ) @@ -229,9 +221,9 @@ void InputFile::setProfile( const ProfileLoader::Profile& profile ) } catch( std::exception& e ) { - std::cout << "[InputFile] warning - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what() << std::endl; + std::cout << "[InputFile] warning: " << e.what() << std::endl; } } } -} +} \ No newline at end of file diff --git a/src/AvTranscoder/file/InputFile.hpp b/src/AvTranscoder/file/InputFile.hpp index a0542a09..9ac80f9d 100644 --- a/src/AvTranscoder/file/InputFile.hpp +++ b/src/AvTranscoder/file/InputFile.hpp @@ -3,12 +3,14 @@ #include +#include + #include #include #include -#include +#include #include @@ -34,12 +36,6 @@ class AvExport InputFile virtual ~InputFile(); - enum EAnalyseLevel - { - eAnalyseLevelFast = 0, - eAnalyseLevelFull = 0, - }; - /** * @return Return the resource to access **/ @@ -50,24 +46,14 @@ class AvExport InputFile * call this function before getProperties(). * @param progress callback to get analysis progression **/ - InputFile& analyse( IProgress& progress, const EAnalyseLevel level = eAnalyseLevelFull ); + InputFile& analyse( IProgress& progress, const EAnalyseLevel level = eAnalyseLevelFirstGop ); /** * @brief Return media properties on the current InputFile. * @note require to launch analyse() before to fill the property struture * @return structure of media metadatas **/ - const Properties& getProperties() const { return _properties; } - - void getProperties( Properties& properties ) const { properties = _properties; } - - /** - * @brief Get media file properties using static method. - * @param filename input filename - * @param progress callback to get analysis progression - * @return structure of media metadatas - **/ - static Properties analyseFile( const std::string& filename, IProgress& progress, const EAnalyseLevel level = eAnalyseLevelFull ); + const FileProperties& getProperties() const { return _properties; } /** * @brief Get stream type: video, audio, subtitle, etc. @@ -90,32 +76,29 @@ class AvExport InputFile AVFormatContext& getFormatContext() const { return *_formatContext; } /** - * @brief Read the next packet for the specified stream - * @note For performances, each readed stream needs to be bufferized using the readStream() method. - * @return if next packet was succefully readed + * @brief Read the next packet of the specified stream + * @param data: data of next packet read + * @return if next packet was read succefully **/ - bool readNextPacket( const size_t streamIndex ); + bool readNextPacket( CodedData& data, const size_t streamIndex ); /** * @brief Seek input stream at specified frame * @note clean also buffers in each InputStream - * @return if next packet was succefully readed + * @return if next packet was read succefully **/ void seekAtFrame( const size_t frame ); /** - * @brief Indicate that the stream should be bufferized - * @param streamIndex index of the stream need to be read - * @param readStream specify if the stream need to be buffurized + * @brief Activate the indicated stream + * @note Activate a stream results in buffered its data when processing **/ - void readStream( const size_t streamIndex, const bool readStream = true ); + void activateStream( const size_t streamIndex, const bool activate = true ); /** - * @brief Indicate that the stream will be bufferized during the read - * @param streamIndex specify stream index - * @return the reading status of the streamIndex + * @brief Indicate that the stream is activated **/ - bool getReadStream( const size_t streamIndex ); + bool isStreamActivated( const size_t streamIndex ); /** * @brief Set the format of the input file @@ -123,9 +106,18 @@ class AvExport InputFile */ virtual void setProfile( const ProfileLoader::Profile& profile ); +public: + /** + * @brief Get media file properties using static method. + * @param filename input filename + * @param progress callback to get analysis progression + * @return structure of media metadatas + **/ + static FileProperties analyseFile( const std::string& filename, IProgress& progress, const EAnalyseLevel level = eAnalyseLevelFirstGop ); + protected: AVFormatContext* _formatContext; - Properties _properties; + FileProperties _properties; std::string _filename; std::vector _inputStreams; }; diff --git a/src/AvTranscoder/file/OutputFile.cpp b/src/AvTranscoder/file/OutputFile.cpp index 617c1867..d143b6ff 100644 --- a/src/AvTranscoder/file/OutputFile.cpp +++ b/src/AvTranscoder/file/OutputFile.cpp @@ -136,8 +136,8 @@ bool OutputFile::beginWrap( ) int ret = avformat_write_header( _formatContext, NULL ); if( ret != 0 ) { - char err[250]; - av_strerror( ret, err, 250); + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); std::string msg = "could not write header: "; msg += err; throw std::runtime_error( msg ); @@ -170,8 +170,8 @@ IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const si if( ret != 0 ) { - char err[250]; - av_strerror( ret, err, 250); + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); std::string msg = "error when writting packet in stream: "; msg += err; // throw std::runtime_error( msg ); @@ -216,9 +216,9 @@ bool OutputFile::endWrap( ) return true; } -void OutputFile::addMetadata( const MetadatasMap& dataMap ) +void OutputFile::addMetadata( const PropertiesMap& dataMap ) { - for( MetadatasMap::const_iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + for( PropertiesMap::const_iterator it = dataMap.begin(); it != dataMap.end(); ++it ) { addMetadata( it->first, it->second ); } @@ -229,8 +229,8 @@ void OutputFile::addMetadata( const std::string& key, const std::string& value ) int ret = av_dict_set( &_formatContext->metadata, key.c_str(), value.c_str(), 0 ); if( ret < 0 ) { - char err[250]; - av_strerror( ret, err, 250 ); + char err[AV_ERROR_MAX_STRING_SIZE]; + av_strerror( ret, err, sizeof(err) ); std::cout << err << std::endl; } } @@ -291,4 +291,12 @@ void OutputFile::setProfile( const ProfileLoader::Profile& profile ) } } +double OutputFile::getProgressDuration() +{ + if( _formatContext->nb_streams == 0 ) + throw std::runtime_error( "at least one stream must be set to get the progress duration" ); + AVStream* firstOutputStream = _formatContext->streams[0]; + return av_q2d( firstOutputStream->time_base ) * firstOutputStream->cur_dts; +} + } diff --git a/src/AvTranscoder/file/OutputFile.hpp b/src/AvTranscoder/file/OutputFile.hpp index 99cfd6f8..37ae379e 100644 --- a/src/AvTranscoder/file/OutputFile.hpp +++ b/src/AvTranscoder/file/OutputFile.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -104,12 +104,12 @@ class AvExport OutputFile * @brief Add metadata to the output file. * @note Depending on the format, you are not sure to find your metadata after the transcode. */ - virtual void addMetadata( const MetadatasMap& dataMap ); + virtual void addMetadata( const PropertiesMap& dataMap ); virtual void addMetadata( const std::string& key, const std::string& value ); virtual void setVerbose( bool verbose = false ){ _verbose = verbose; } - AVFormatContext& getFormatContext() { return *_formatContext; } + virtual double getProgressDuration(); private: std::vector _outputStreams; diff --git a/src/AvTranscoder/file/file.i b/src/AvTranscoder/file/file.i new file mode 100644 index 00000000..a0c3ee0e --- /dev/null +++ b/src/AvTranscoder/file/file.i @@ -0,0 +1,9 @@ +%{ +#include +#include +#include +%} + +%include +%include +%include diff --git a/src/AvTranscoder/file/util.hpp b/src/AvTranscoder/file/util.hpp new file mode 100644 index 00000000..95dcaea4 --- /dev/null +++ b/src/AvTranscoder/file/util.hpp @@ -0,0 +1,20 @@ +#ifndef _AV_TRANSCODER_FILE_UTIL_HPP_ +#define _AV_TRANSCODER_FILE_UTIL_HPP_ + +namespace avtranscoder +{ + +/** + * @brief Level of file analysis. + */ +enum EAnalyseLevel +{ + eAnalyseLevelHeader = 0, + eAnalyseLevelFirstGop = 1, + //eAnalyseLevelFull = 2, +}; + +} + +#endif + diff --git a/src/AvTranscoder/frame/Frame.hpp b/src/AvTranscoder/frame/Frame.hpp index c0da63fd..d04ebf9a 100644 --- a/src/AvTranscoder/frame/Frame.hpp +++ b/src/AvTranscoder/frame/Frame.hpp @@ -14,16 +14,25 @@ class AvExport Frame { public: Frame(){}; - + ~Frame(){}; + void copyData(unsigned char* buffer, const size_t size) + { + _dataBuffer.resize( size ); + if ( size != 0 ) + memcpy( getPtr(), buffer, size ); + } + DataBuffer& getBuffer() { return _dataBuffer; } unsigned char* getPtr() { return &_dataBuffer[0]; } + #ifndef SWIG const unsigned char* getPtr() const { return &_dataBuffer[0]; } #endif + size_t getSize() const { return _dataBuffer.size(); } - + protected: DataBuffer _dataBuffer; }; diff --git a/src/AvTranscoder/frame/Pixel.cpp b/src/AvTranscoder/frame/Pixel.cpp index 145140fc..ec2b6a73 100644 --- a/src/AvTranscoder/frame/Pixel.cpp +++ b/src/AvTranscoder/frame/Pixel.cpp @@ -18,20 +18,12 @@ Pixel::Pixel( const std::string& avPixelFormat ) } Pixel::Pixel( const AVPixelFormat avPixelFormat ) - : _pixelSize ( 24 ) - , _components ( 3 ) - , _componentType ( eComponentYuv ) - , _subsamplingType ( eSubsamplingNone ) - , _endianess ( false ) - , _withAlpha ( false ) - , _planar ( true ) { init( avPixelFormat ); } AVPixelFormat Pixel::findPixel() const { - //av_register_all(); #if LIBAVUTIL_VERSION_MAJOR > 51 const AVPixFmtDescriptor *pix_desc = NULL; while( ( pix_desc = av_pix_fmt_desc_next( pix_desc ) ) ) @@ -72,10 +64,10 @@ void Pixel::init( const AVPixelFormat avPixelFormat ) } setBitsPerPixel ( av_get_bits_per_pixel( pix_desc ) ); - setBigEndian ( pix_desc->flags & PIX_FMT_BE ); + setBigEndian ( ( pix_desc->flags & PIX_FMT_BE ) == PIX_FMT_BE ); setComponents ( pix_desc->nb_components ); - setAlpha ( pix_desc->flags & PIX_FMT_ALPHA ); - setPlanar ( ( pix_desc->flags & PIX_FMT_PLANAR ) != 0 ); + setAlpha ( ( pix_desc->flags & PIX_FMT_ALPHA ) == PIX_FMT_ALPHA ); + setPlanar ( ( pix_desc->flags & PIX_FMT_PLANAR ) == PIX_FMT_PLANAR ); if( pix_desc->nb_components == 1 ) setColorComponents( eComponentGray ); @@ -87,16 +79,31 @@ void Pixel::init( const AVPixelFormat avPixelFormat ) setSubsampling( eSubsamplingNone ); - if( ( pix_desc->log2_chroma_w == true ) && - ( pix_desc->log2_chroma_h == false ) ) + if( ( pix_desc->log2_chroma_w == 0 ) && + ( pix_desc->log2_chroma_h == 1 ) ) + { + setSubsampling( eSubsampling440 ); + } + else if( ( pix_desc->log2_chroma_w == 1 ) && + ( pix_desc->log2_chroma_h == 0 ) ) { setSubsampling( eSubsampling422 ); } - if( ( pix_desc->log2_chroma_w == true ) && - ( pix_desc->log2_chroma_h == true ) ) + else if( ( pix_desc->log2_chroma_w == 1 ) && + ( pix_desc->log2_chroma_h == 1 ) ) { setSubsampling( eSubsampling420 ); } + else if( ( pix_desc->log2_chroma_w == 3 ) && + ( pix_desc->log2_chroma_h == 0 ) ) + { + setSubsampling( eSubsampling411 ); + } + else if( ( pix_desc->log2_chroma_w == 2 ) && + ( pix_desc->log2_chroma_h == 2 ) ) + { + setSubsampling( eSubsampling410 ); + } } bool Pixel::asCorrectColorComponents( const AVPixFmtDescriptor* pix_desc, const EComponentType componentType ) const @@ -114,18 +121,33 @@ bool Pixel::asCorrectSubsampling( const AVPixFmtDescriptor* pix_desc, const ESub { case eSubsamplingNone : { - return ( pix_desc->log2_chroma_w == false ) && - ( pix_desc->log2_chroma_h == false ); + return ( pix_desc->log2_chroma_w == 0 ) && + ( pix_desc->log2_chroma_h == 0 ); + } + case eSubsampling440 : + { + return ( pix_desc->log2_chroma_w == 0 ) && + ( pix_desc->log2_chroma_h == 1 ); } case eSubsampling422 : { - return ( pix_desc->log2_chroma_w == true ) && - ( pix_desc->log2_chroma_h == false ); + return ( pix_desc->log2_chroma_w == 1 ) && + ( pix_desc->log2_chroma_h == 0 ); } case eSubsampling420 : { - return ( pix_desc->log2_chroma_w == true ) && - ( pix_desc->log2_chroma_h == true ); + return ( pix_desc->log2_chroma_w == 1 ) && + ( pix_desc->log2_chroma_h == 1 ); + } + case eSubsampling411: + { + return ( pix_desc->log2_chroma_w == 3 ) && + ( pix_desc->log2_chroma_h == 0 ); + } + case eSubsampling410 : + { + return ( pix_desc->log2_chroma_w == 2 ) && + ( pix_desc->log2_chroma_h == 2 ); } } return false; diff --git a/src/AvTranscoder/frame/Pixel.hpp b/src/AvTranscoder/frame/Pixel.hpp index c5f9aaf2..206c8e38 100644 --- a/src/AvTranscoder/frame/Pixel.hpp +++ b/src/AvTranscoder/frame/Pixel.hpp @@ -23,8 +23,11 @@ enum EComponentType enum ESubsamplingType { eSubsamplingNone = 0, // 4:4:4 + eSubsampling440, // 4:4:0 eSubsampling422, // 4:2:2 - eSubsampling420 // 4:2:0 + eSubsampling420, // 4:2:0 + eSubsampling411, // 4:1:1 + eSubsampling410 // 4:1:0 }; class AvExport Pixel @@ -41,7 +44,6 @@ class AvExport Pixel { } Pixel( const std::string& avPixelFormat ); - Pixel( const AVPixelFormat avPixelFormat ); void setBitsPerPixel ( const size_t pixelSize ) { _pixelSize = pixelSize; } diff --git a/src/AvTranscoder/frame/VideoFrame.hpp b/src/AvTranscoder/frame/VideoFrame.hpp index 169dc3ee..4423d41f 100644 --- a/src/AvTranscoder/frame/VideoFrame.hpp +++ b/src/AvTranscoder/frame/VideoFrame.hpp @@ -40,7 +40,7 @@ class AvExport VideoFrameDesc void setWidth ( const size_t width ) { _width = width; } void setHeight( const size_t height ) { _height = height; } - void setPixel ( const Pixel pixel ) { _pixel = pixel; } + void setPixel( const Pixel& pixel ) { _pixel = pixel; } void setDar( const size_t num, const size_t den ) { _displayAspectRatio.num = num; _displayAspectRatio.den = den; } void setDar( const Rational ratio ) { _displayAspectRatio = ratio; } diff --git a/src/AvTranscoder/frame/frame.i b/src/AvTranscoder/frame/frame.i new file mode 100644 index 00000000..f8ce9205 --- /dev/null +++ b/src/AvTranscoder/frame/frame.i @@ -0,0 +1,13 @@ +%apply char * { unsigned char * }; + +%{ +#include +#include +#include +#include +%} + +%include +%include +%include +%include diff --git a/src/AvTranscoder/mediaProperty/AttachementProperties.cpp b/src/AvTranscoder/mediaProperty/AttachementProperties.cpp new file mode 100644 index 00000000..3745b2da --- /dev/null +++ b/src/AvTranscoder/mediaProperty/AttachementProperties.cpp @@ -0,0 +1,28 @@ +#include "AttachementProperties.hpp" + +namespace avtranscoder +{ + +AttachementProperties::AttachementProperties( const AVFormatContext* formatContext, const size_t index ) + : _formatContext( formatContext ) + , _streamId( index ) +{ + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); +} + +PropertiesMap AttachementProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "streamId", _streamId ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +} diff --git a/src/AvTranscoder/mediaProperty/AttachementProperties.hpp b/src/AvTranscoder/mediaProperty/AttachementProperties.hpp new file mode 100644 index 00000000..3b63aca2 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/AttachementProperties.hpp @@ -0,0 +1,37 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_ATTACHEMENT_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_ATTACHEMENT_PROPERTIES_HPP + +#include +#include + +extern "C" { +#include +} + +namespace avtranscoder +{ + +class AvExport AttachementProperties +{ +public: + AttachementProperties( const AVFormatContext* formatContext, const size_t index ); + + size_t getStreamId() const { return _streamId; } + PropertiesMap& getMetadatas() { return _metadatas; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return all attachement properties as a map (name of property: value) + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + + size_t _streamId; + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/AttachementStreamProperty.hpp b/src/AvTranscoder/mediaProperty/AttachementStreamProperty.hpp deleted file mode 100644 index 93de0ae5..00000000 --- a/src/AvTranscoder/mediaProperty/AttachementStreamProperty.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _AV_TRANSCODER_ATTACHEMENT_STREAM_PROPERTIES_HPP_ -#define _AV_TRANSCODER_ATTACHEMENT_STREAM_PROPERTIES_HPP_ - -class AVFormatContext; - -namespace avtranscoder -{ - -AttachementProperties attachementStreamInfo( const AVFormatContext* formatContext, const size_t index ) -{ - AttachementProperties ap; - ap.streamId = index; - return ap; -} - -} - -#endif \ No newline at end of file diff --git a/src/AvTranscoder/mediaProperty/AudioProperties.cpp b/src/AvTranscoder/mediaProperty/AudioProperties.cpp new file mode 100644 index 00000000..83e83c57 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/AudioProperties.cpp @@ -0,0 +1,182 @@ +#include "AudioProperties.hpp" + +#include + +extern "C" { +#include +#include +#include +#include +#include +} + +namespace avtranscoder +{ + +AudioProperties::AudioProperties( const AVFormatContext* formatContext, const size_t index ) + : _formatContext( formatContext ) + , _codecContext( NULL ) + , _codec( NULL ) + , _streamId( index ) +{ + if( _formatContext ) + _codecContext = formatContext->streams[index]->codec; + + if( _formatContext && _codecContext ) + _codec = avcodec_find_decoder( _codecContext->codec_id ); + + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); +} + +std::string AudioProperties::getCodecName() const +{ + if( _codec && _codec->name ) + return std::string( _codec->name ); + else + return "unknown codec"; +} + +std::string AudioProperties::getCodecLongName() const +{ + if( _codec && _codec->long_name ) + return std::string( _codec->long_name ); + return "unknown codec"; +} + +std::string AudioProperties::getSampleFormatName() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + const char* fmtName = av_get_sample_fmt_name( _codecContext->sample_fmt ); + if( fmtName ) + return std::string( fmtName ); + return "unknown sample format"; +} + +std::string AudioProperties::getSampleFormatLongName() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->sample_fmt ) + { + case AV_SAMPLE_FMT_NONE: + return "none"; + case AV_SAMPLE_FMT_U8: + return "unsigned 8 bits"; + case AV_SAMPLE_FMT_S16: + return "signed 16 bits"; + case AV_SAMPLE_FMT_S32: + return "signed 32 bits"; + case AV_SAMPLE_FMT_FLT: + return "float"; + case AV_SAMPLE_FMT_DBL: + return "double"; + case AV_SAMPLE_FMT_U8P: + return "unsigned 8 bits, planar"; + case AV_SAMPLE_FMT_S16P: + return "signed 16 bits, planar"; + case AV_SAMPLE_FMT_S32P: + return "signed 32 bits, planar"; + case AV_SAMPLE_FMT_FLTP: + return "float, planar"; + case AV_SAMPLE_FMT_DBLP: + return "double, planar"; + case AV_SAMPLE_FMT_NB: + return "number of sample formats"; + } + return "unknown sample format"; +} + +std::string AudioProperties::getChannelLayout() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + char buf1[1024]; + av_get_channel_layout_string( buf1, sizeof( buf1 ), -1, _codecContext->channel_layout ); + return std::string( buf1 ); +} + +std::string AudioProperties::getChannelName() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + const char* channelName = av_get_channel_name( _codecContext->channel_layout ); + if( channelName ) + return std::string( channelName ); + return "unknown channel name"; +} + +std::string AudioProperties::getChannelDescription() const +{ + if( ! _codecContext ) + return "unknown codec context"; + +#ifdef FF_RESAMPLE_LIBRARY + const char* channelDescription = av_get_channel_description( _codecContext->channel_layout ); + if( channelDescription ) + return std::string( channelDescription ); + return "unknown channel description"; +#else + return "can't access channel description"; +#endif +} + +size_t AudioProperties::getCodecId() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->codec_id; +} + +size_t AudioProperties::getSampleRate() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->sample_rate; +} + +size_t AudioProperties::getChannels() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->channels; +} + +size_t AudioProperties::getBitRate() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->bit_rate; +} + +PropertiesMap AudioProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "streamId", getStreamId() ); + detail::add( dataMap, "codecId", getCodecId() ); + detail::add( dataMap, "codecName", getCodecName() ); + detail::add( dataMap, "codecLongName", getCodecLongName() ); + detail::add( dataMap, "sampleFormatName", getSampleFormatName() ); + detail::add( dataMap, "sampleFormatLongName", getSampleFormatLongName() ); + detail::add( dataMap, "sampleRate", getSampleRate() ); + detail::add( dataMap, "bitRate", getBitRate() ); + detail::add( dataMap, "channels", getChannels() ); + detail::add( dataMap, "channelLayout", getChannelLayout() ); + detail::add( dataMap, "channelName", getChannelName() ); + detail::add( dataMap, "channelDescription", getChannelDescription() ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +} diff --git a/src/AvTranscoder/mediaProperty/AudioProperties.hpp b/src/AvTranscoder/mediaProperty/AudioProperties.hpp new file mode 100644 index 00000000..7d209d55 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/AudioProperties.hpp @@ -0,0 +1,56 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_AUDIO_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_AUDIO_PROPERTIES_HPP + +#include +#include + +extern "C" { +#include +#include +} + +#include + +class AVFormatContext; + +namespace avtranscoder +{ + +class AvExport AudioProperties +{ +public: + AudioProperties( const AVFormatContext* formatContext, const size_t index ); + + std::string getCodecName() const; + std::string getCodecLongName() const; + std::string getSampleFormatName() const; + std::string getSampleFormatLongName() const; + std::string getChannelLayout() const; + std::string getChannelName() const; + std::string getChannelDescription() const; + size_t getStreamId() const { return _streamId; } + size_t getCodecId() const; + size_t getSampleRate() const; + size_t getChannels() const; + size_t getBitRate() const; + PropertiesMap& getMetadatas() { return _metadatas; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } + AVCodecContext& getAVCodecContext() { return *_codecContext; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return all audio properties as a map (name of property: value) + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + AVCodecContext* _codecContext; ///< Has link (no ownership) + AVCodec* _codec; ///< Has link (no ownership) + + size_t _streamId; + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/AudioStreamProperty.hpp b/src/AvTranscoder/mediaProperty/AudioStreamProperty.hpp deleted file mode 100644 index 7b651cfa..00000000 --- a/src/AvTranscoder/mediaProperty/AudioStreamProperty.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _AV_TRANSCODER_AUDIO_STREAM_PROPERTIES_HPP_ -#define _AV_TRANSCODER_AUDIO_STREAM_PROPERTIES_HPP_ - -extern "C" { -#include -#include -#include -#include -#include -} - -namespace avtranscoder -{ - -avtranscoder::AudioProperties audioStreamInfo( const AVFormatContext* formatContext, const size_t index ) -{ - AudioProperties ap; - AVCodecContext* codec_context = formatContext->streams[index]->codec; - - ap.codecId = codec_context->codec_id; - ap.sampleRate = codec_context->sample_rate; - ap.channels = codec_context->channels; - ap.bit_rate = codec_context->bit_rate; - ap.streamId = index; - - AVCodec* codec = avcodec_find_decoder( codec_context->codec_id ); - if( codec != NULL ) - { - ap.codecName = codec->name; - ap.codecLongName = codec->long_name; - } - - char buf1[1024]; - av_get_channel_layout_string( buf1, sizeof( buf1 ), -1, codec_context->channel_layout ); - - ap.channelLayout = std::string( buf1 ); - - const char* channelName = av_get_channel_name( codec_context->channel_layout ); - if( channelName ) - ap.channelName = std::string( channelName ); -#ifdef FF_RESAMPLE_LIBRARY - const char* channelDescription = av_get_channel_description( codec_context->channel_layout ); - if( channelDescription ) - ap.channelDescription = std::string( channelDescription ); -#endif - const char* fmtName = av_get_sample_fmt_name( codec_context->sample_fmt ); - if( fmtName ) - ap.sampleFormatName = std::string( fmtName ); - - std::string sampleFormat = ""; - switch( codec_context->sample_fmt ) - { - case AV_SAMPLE_FMT_NONE : ap.sampleFormatLongName = "none"; break; - case AV_SAMPLE_FMT_U8 : ap.sampleFormatLongName = "unsigned 8 bits"; break; - case AV_SAMPLE_FMT_S16 : ap.sampleFormatLongName = "signed 16 bits"; break; - case AV_SAMPLE_FMT_S32 : ap.sampleFormatLongName = "signed 32 bits"; break; - case AV_SAMPLE_FMT_FLT : ap.sampleFormatLongName = "float"; break; - case AV_SAMPLE_FMT_DBL : ap.sampleFormatLongName = "double"; break; - case AV_SAMPLE_FMT_U8P : ap.sampleFormatLongName = "unsigned 8 bits, planar"; break; - case AV_SAMPLE_FMT_S16P : ap.sampleFormatLongName = "signed 16 bits, planar"; break; - case AV_SAMPLE_FMT_S32P : ap.sampleFormatLongName = "signed 32 bits, planar"; break; - case AV_SAMPLE_FMT_FLTP : ap.sampleFormatLongName = "float, planar"; break; - case AV_SAMPLE_FMT_DBLP : ap.sampleFormatLongName = "double, planar"; break; - case AV_SAMPLE_FMT_NB : ap.sampleFormatLongName = "Number of sample formats."; break; - } - - return ap; -} - -} - -#endif diff --git a/src/AvTranscoder/mediaProperty/DataStreamProperty.hpp b/src/AvTranscoder/mediaProperty/DataProperties.cpp similarity index 78% rename from src/AvTranscoder/mediaProperty/DataStreamProperty.hpp rename to src/AvTranscoder/mediaProperty/DataProperties.cpp index 6669ad99..24f32578 100644 --- a/src/AvTranscoder/mediaProperty/DataStreamProperty.hpp +++ b/src/AvTranscoder/mediaProperty/DataProperties.cpp @@ -1,28 +1,51 @@ -#ifndef _AV_TRANSCODER_DATA_STREAM_PROPERTIES_HPP_ -#define _AV_TRANSCODER_DATA_STREAM_PROPERTIES_HPP_ +#include "DataProperties.hpp" extern "C" { #include -#include #include #include } #include +#include namespace avtranscoder { -void detectAncillaryData( AVFormatContext* formatContext, const int index ) +DataProperties::DataProperties( const AVFormatContext* formatContext, const size_t index ) + : _formatContext( formatContext ) + , _streamId( index ) +{ + //detectAncillaryData( _formatContext, _streamId ); + + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); +} + +PropertiesMap DataProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "streamId", _streamId ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +void DataProperties::detectAncillaryData() { AVPacket pkt; av_init_packet( &pkt ); bool detection = false; - while( ! av_read_frame( formatContext, &pkt ) ) + while( ! av_read_frame( const_cast( _formatContext ), &pkt ) ) { - if( pkt.stream_index == index ) + if( pkt.stream_index == (int)_streamId ) { std::cout << "start detect packet" << std::endl; size_t offset = 0; @@ -62,20 +85,4 @@ void detectAncillaryData( AVFormatContext* formatContext, const int index ) } } -DataProperties dataStreamInfo( AVFormatContext* formatContext, const size_t index ) -{ - DataProperties dp; - dp.streamId = index; - - // AVCodecContext* codec_context = formatContext->streams[index]->codec; - - // dp.codecId = codec_context->codec_id; - - //detectAncillaryData( formatContext, index ); - - return dp; -} - } - -#endif \ No newline at end of file diff --git a/src/AvTranscoder/mediaProperty/DataProperties.hpp b/src/AvTranscoder/mediaProperty/DataProperties.hpp new file mode 100644 index 00000000..337f7ad9 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/DataProperties.hpp @@ -0,0 +1,40 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_DATA_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_DATA_PROPERTIES_HPP + +#include +#include + +extern "C" { +#include +} + +namespace avtranscoder +{ + +class AvExport DataProperties +{ +public: + DataProperties( const AVFormatContext* formatContext, const size_t index ); + + size_t getStreamId() const { return _streamId; } + PropertiesMap& getMetadatas() { return _metadatas; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return all data properties as a map (name of property: value) + +private: + void detectAncillaryData(); + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + + size_t _streamId; + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/FileProperties.cpp b/src/AvTranscoder/mediaProperty/FileProperties.cpp new file mode 100644 index 00000000..39221883 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/FileProperties.cpp @@ -0,0 +1,112 @@ +#include "FileProperties.hpp" + +#include + +namespace avtranscoder +{ + +FileProperties::FileProperties( const AVFormatContext* formatContext ) + : _formatContext( formatContext ) + , _videoStreams() + , _audioStreams() + , _dataStreams() + , _subtitleStreams() + , _attachementStreams() + , _unknownStreams() +{ + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->metadata, _metadatas ); +} + +std::string FileProperties::getFilename() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->filename; +} + +std::string FileProperties::getFormatName() const +{ + if( ! _formatContext || ! _formatContext->iformat ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->iformat->name; +} + +std::string FileProperties::getFormatLongName() const +{ + if( ! _formatContext || ! _formatContext->iformat ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->iformat->long_name; +} + +size_t FileProperties::getProgramsCount() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->nb_programs; +} + +double FileProperties::getStartTime() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return 1.0 * (unsigned int)_formatContext->start_time / AV_TIME_BASE; +} + +double FileProperties::getDuration() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return 1.0 * _formatContext->duration / AV_TIME_BASE; +} + +size_t FileProperties::getBitRate() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->bit_rate; +} + +size_t FileProperties::getPacketSize() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->packet_size; +} + +size_t FileProperties::getNbStreams() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + return _formatContext->nb_streams; +} + +PropertiesMap FileProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "filename", getFilename() ); + detail::add( dataMap, "formatName", getFormatName() ); + detail::add( dataMap, "formatLongName", getFormatLongName() ); + + detail::add( dataMap, "startTime", getStartTime() ); + detail::add( dataMap, "duration", getDuration() ); + detail::add( dataMap, "bitrate", getBitRate() ); + detail::add( dataMap, "numberOfStreams", getNbStreams() ); + detail::add( dataMap, "numberOfPrograms", getProgramsCount() ); + detail::add( dataMap, "numberOfVideoStreams", getNbVideoStreams() ); + detail::add( dataMap, "numberOfAudioStreams", getNbAudioStreams() ); + detail::add( dataMap, "numberOfDataStreams", getNbDataStreams() ); + detail::add( dataMap, "numberOfSubtitleStreams", getNbSubtitleStreams() ); + detail::add( dataMap, "numberOfAttachementStreams", getNbAttachementStreams() ); + detail::add( dataMap, "numberOfUnknownStreams", getNbUnknownStreams() ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +} diff --git a/src/AvTranscoder/mediaProperty/FileProperties.hpp b/src/AvTranscoder/mediaProperty/FileProperties.hpp new file mode 100644 index 00000000..c9ce8ce4 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/FileProperties.hpp @@ -0,0 +1,82 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_FILE_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_FILE_PROPERTIES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +#include +#include + +namespace avtranscoder +{ + +class AvExport FileProperties +{ +public: + FileProperties( const AVFormatContext* formatContext ); + + std::string getFilename() const; + std::string getFormatName() const; + std::string getFormatLongName() const; + + size_t getProgramsCount() const; + double getStartTime() const; + double getDuration() const; + size_t getBitRate() const; + size_t getPacketSize() const; + + PropertiesMap& getMetadatas() { return _metadatas; } + + size_t getNbStreams() const; + size_t getNbVideoStreams() const { return _videoStreams.size(); } + size_t getNbAudioStreams() const { return _audioStreams.size(); } + size_t getNbDataStreams() const { return _dataStreams.size(); } + size_t getNbSubtitleStreams() const { return _subtitleStreams.size(); } + size_t getNbAttachementStreams() const { return _attachementStreams.size(); } + size_t getNbUnknownStreams() const { return _unknownStreams.size(); } + + std::vector< avtranscoder::VideoProperties >& getVideoProperties() { return _videoStreams; } + std::vector< avtranscoder::AudioProperties >& getAudioProperties() { return _audioStreams; } + std::vector< avtranscoder::DataProperties >& getDataProperties() { return _dataStreams; } + std::vector< avtranscoder::SubtitleProperties >& getSubtitleProperties() { return _subtitleStreams; } + std::vector< avtranscoder::AttachementProperties >& getAttachementProperties() { return _attachementStreams; } + std::vector< avtranscoder::UnknownProperties >& getUnknownPropertiesProperties() { return _unknownStreams; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } + const std::vector< avtranscoder::VideoProperties >& getVideoProperties() const { return _videoStreams; } + const std::vector< avtranscoder::AudioProperties >& getAudioProperties() const { return _audioStreams; } + const std::vector< avtranscoder::DataProperties >& getDataProperties() const { return _dataStreams; } + const std::vector< avtranscoder::SubtitleProperties >& getSubtitleProperties() const { return _subtitleStreams; } + const std::vector< avtranscoder::AttachementProperties >& getAttachementProperties() const { return _attachementStreams; } + const std::vector< avtranscoder::UnknownProperties >& getUnknownPropertiesProperties() const { return _unknownStreams; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return all file properties as a map (name of property: value) + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + + std::vector< VideoProperties > _videoStreams; ///< Array of properties per video stream + std::vector< AudioProperties > _audioStreams; ///< Array of properties per audio stream + std::vector< DataProperties > _dataStreams; ///< Array of properties per data stream + std::vector< SubtitleProperties > _subtitleStreams; ///< Array of properties per subtitle stream + std::vector< AttachementProperties > _attachementStreams; ///< Array of properties per attachement stream + std::vector< UnknownProperties > _unknownStreams; ///< Array of properties per unknown stream + + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/SubtitleProperties.cpp b/src/AvTranscoder/mediaProperty/SubtitleProperties.cpp new file mode 100644 index 00000000..28dcb324 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/SubtitleProperties.cpp @@ -0,0 +1,28 @@ +#include "SubtitleProperties.hpp" + +namespace avtranscoder +{ + +SubtitleProperties::SubtitleProperties( const AVFormatContext* formatContext, const size_t index ) + : _formatContext( formatContext ) + , _streamId( index ) +{ + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); +} + +PropertiesMap SubtitleProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "streamId", _streamId ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +} diff --git a/src/AvTranscoder/mediaProperty/SubtitleProperties.hpp b/src/AvTranscoder/mediaProperty/SubtitleProperties.hpp new file mode 100644 index 00000000..b0430e86 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/SubtitleProperties.hpp @@ -0,0 +1,37 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_SUBTITLE_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_SUBTITLE_PROPERTIES_HPP + +#include +#include + +extern "C" { +#include +} + +namespace avtranscoder +{ + +class AvExport SubtitleProperties +{ +public: + SubtitleProperties( const AVFormatContext* formatContext, const size_t index ); + + size_t getStreamId() const { return _streamId; } + PropertiesMap& getMetadatas() { return _metadatas; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return all subtitle properties as a map (name of property: value) + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + + size_t _streamId; + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/SubtitleStreamProperty.hpp b/src/AvTranscoder/mediaProperty/SubtitleStreamProperty.hpp deleted file mode 100644 index 9253a319..00000000 --- a/src/AvTranscoder/mediaProperty/SubtitleStreamProperty.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _AV_TRANSCODER_SUBTITLE_STREAM_PROPERTIES_HPP_ -#define _AV_TRANSCODER_SUBTITLE_STREAM_PROPERTIES_HPP_ - -class AVFormatContext; - -namespace avtranscoder -{ - -SubtitleProperties subtitleStreamInfo( const AVFormatContext* formatContext, const size_t index ) -{ - SubtitleProperties sp; - sp.streamId = index; - - return sp; -} - -} - -#endif \ No newline at end of file diff --git a/src/AvTranscoder/mediaProperty/UnknownProperties.cpp b/src/AvTranscoder/mediaProperty/UnknownProperties.cpp new file mode 100644 index 00000000..14d449e3 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/UnknownProperties.cpp @@ -0,0 +1,28 @@ +#include "UnknownProperties.hpp" + +namespace avtranscoder +{ + +UnknownProperties::UnknownProperties( const AVFormatContext* formatContext, const size_t index ) + : _formatContext( formatContext ) + , _streamId( index ) +{ + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); +} + +PropertiesMap UnknownProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "streamId", _streamId ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +} diff --git a/src/AvTranscoder/mediaProperty/UnknownProperties.hpp b/src/AvTranscoder/mediaProperty/UnknownProperties.hpp new file mode 100644 index 00000000..ebb42717 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/UnknownProperties.hpp @@ -0,0 +1,37 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_UNKNOWN_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_UNKNOWN_PROPERTIES_HPP + +#include +#include + +extern "C" { +#include +} + +namespace avtranscoder +{ + +class AvExport UnknownProperties +{ +public: + UnknownProperties( const AVFormatContext* formatContext, const size_t index ); + + size_t getStreamId() const { return _streamId; } + PropertiesMap& getMetadatas() { return _metadatas; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return unknown properties as a map (name of property: value) + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + + size_t _streamId; + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/UnknownStreamProperty.hpp b/src/AvTranscoder/mediaProperty/UnknownStreamProperty.hpp deleted file mode 100644 index 3d2b21e4..00000000 --- a/src/AvTranscoder/mediaProperty/UnknownStreamProperty.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _AV_TRANSCODER_UNKNOWN_STREAM_PROPERTIES_HPP_ -#define _AV_TRANSCODER_UNKNOWN_STREAM_PROPERTIES_HPP_ - -class AVFormatContext; - -namespace avtranscoder -{ - -UnknownProperties unknownStreamInfo( const AVFormatContext* formatContext, const size_t index ) -{ - UnknownProperties up; - up.streamId = index; - - return up; -} - -} - -#endif \ No newline at end of file diff --git a/src/AvTranscoder/mediaProperty/VideoProperties.cpp b/src/AvTranscoder/mediaProperty/VideoProperties.cpp new file mode 100644 index 00000000..64503bda --- /dev/null +++ b/src/AvTranscoder/mediaProperty/VideoProperties.cpp @@ -0,0 +1,722 @@ +#include "VideoProperties.hpp" + +#include + +extern "C" { +#include +} + +#include +#include + +#ifdef _MSC_VER +#include +#define isnan _isnan +#define isinf(x) (!_finite(x)) +#endif + +namespace avtranscoder +{ + +VideoProperties::VideoProperties( const AVFormatContext* formatContext, const size_t index, IProgress& progress, const EAnalyseLevel level ) + : _formatContext( formatContext ) + , _codecContext( NULL ) + , _codec( NULL ) + , _pixFmt( NULL ) + , _streamId( index ) + , _isInterlaced( false ) + , _isTopFieldFirst( false ) + , _gopStructure() +{ + if( _formatContext ) + _codecContext = formatContext->streams[index]->codec; + + if( _formatContext && _codecContext ) + _codec = avcodec_find_decoder( _codecContext->codec_id ); + + if( formatContext ) + detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); + + // Skip decoding for selected frames + _codecContext->skip_frame = AVDISCARD_NONE; + + // Get pixel format +#if LIBAVUTIL_VERSION_MAJOR > 51 + _pixFmt = av_pix_fmt_desc_get( _codecContext->pix_fmt ); +#else + if( _codecContext->pix_fmt >= 0 && _codecContext->pix_fmt < PIX_FMT_NB ) + _pixFmt = &av_pix_fmt_descriptors[ _codecContext->pix_fmt ]; +#endif + + if( level == eAnalyseLevelFirstGop ) + analyseGopStructure( progress ); +} + +std::string VideoProperties::getCodecName() const +{ + if( _codecContext && _codec ) + { + if( _codec->capabilities & CODEC_CAP_TRUNCATED ) + _codecContext->flags|= CODEC_FLAG_TRUNCATED; + + if( _codec->name ) + return std::string( _codec->name ); + } + return "unknown codec"; +} + +std::string VideoProperties::getCodecLongName() const +{ + if( _codecContext && _codec ) + { + if( _codec->capabilities & CODEC_CAP_TRUNCATED ) + _codecContext->flags|= CODEC_FLAG_TRUNCATED; + + if( _codec->long_name ) + return std::string( _codec->long_name ); + } + return "unknown codec"; +} + +std::string VideoProperties::getProfileName() const +{ + if( _codecContext && _codec ) + { + if( _codec->capabilities & CODEC_CAP_TRUNCATED ) + _codecContext->flags|= CODEC_FLAG_TRUNCATED; + + if( _codecContext->profile != -99 ) + { + const char* profile; + if( ( profile = av_get_profile_name( _codec, _codecContext->profile ) ) != NULL ) + return std::string( profile ); + } + } + return "unknown profile"; +} + +std::string VideoProperties::getColorTransfert() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->color_trc ) + { + case AVCOL_TRC_BT709: + return "Rec 709 / ITU-R BT1361"; + case AVCOL_TRC_UNSPECIFIED: + return "unspecified"; + case AVCOL_TRC_GAMMA22: + return "Gamma 2.2"; + case AVCOL_TRC_GAMMA28: + return "Gamma 2.8"; +#if LIBAVCODEC_VERSION_MAJOR > 53 + case AVCOL_TRC_SMPTE240M: + return "Smpte 240M"; +#endif +#if LIBAVCODEC_VERSION_MAJOR > 54 +#ifdef AVCOL_TRC_SMPTE170M + case AVCOL_TRC_SMPTE170M: + return "Rec 601 / ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC"; +#endif +#ifdef AVCOL_TRC_LINEAR + case AVCOL_TRC_LINEAR: + return "Linear transfer characteristics"; +#endif +#ifdef AVCOL_TRC_LOG + case AVCOL_TRC_LOG: + return "Logarithmic transfer characteristic (100:1 range)"; +#endif +#ifdef AVCOL_TRC_LOG_SQRT + case AVCOL_TRC_LOG_SQRT: + return "Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range)"; +#endif +#ifdef AVCOL_TRC_IEC61966_2_4 + case AVCOL_TRC_IEC61966_2_4: + return "IEC 61966-2-4"; +#endif +#ifdef AVCOL_TRC_BT1361_ECG + case AVCOL_TRC_BT1361_ECG: + return "ITU-R BT1361 Extended Colour Gamut"; +#endif +#ifdef AVCOL_TRC_IEC61966_2_1 + case AVCOL_TRC_IEC61966_2_1: + return "IEC 61966-2-1 (sRGB or sYCC)"; +#endif +#ifdef AVCOL_TRC_BT2020_10 + case AVCOL_TRC_BT2020_10: + return "ITU-R BT2020 for 10 bit system"; +#endif +#ifdef AVCOL_TRC_BT2020_12 + case AVCOL_TRC_BT2020_12: + return "ITU-R BT2020 for 12 bit system"; +#endif +#endif + case AVCOL_TRC_NB: + return "Not ABI"; + default: + return ""; + } +} + +std::string VideoProperties::getColorspace() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->colorspace ) + { + case AVCOL_SPC_RGB: + return "RGB"; + case AVCOL_SPC_BT709: + return "Rec 709"; + case AVCOL_SPC_UNSPECIFIED: + return "unspecified"; + case AVCOL_SPC_FCC: + return "Four CC"; + case AVCOL_SPC_BT470BG: + return "BT470 (PAL - 625)"; + case AVCOL_SPC_SMPTE170M: + return "Smpte 170M (NTSC)"; + case AVCOL_SPC_SMPTE240M: + return "Smpte 240M"; +#if LIBAVCODEC_VERSION_MAJOR > 53 + case AVCOL_SPC_YCOCG: + return "Y Co Cg"; +//#else +// case AVCOL_SPC_YCGCO: +// return "Y Cg Co"; +#endif +#if LIBAVCODEC_VERSION_MAJOR > 54 +#ifdef AVCOL_TRC_BT2020_12 + case AVCOL_SPC_BT2020_NCL: + return "ITU-R BT2020 non-constant luminance system"; +#endif +#ifdef AVCOL_TRC_BT2020_CL + case AVCOL_SPC_BT2020_CL: + return "ITU-R BT2020 constant luminance system"; +#endif +#endif + case AVCOL_SPC_NB: + return "Not ABI"; + default: + return ""; + } +} + +std::string VideoProperties::getColorRange() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->color_range ) + { + case AVCOL_RANGE_UNSPECIFIED: + return "unspecified"; + case AVCOL_RANGE_MPEG: + return "Head"; + case AVCOL_RANGE_JPEG: + return "Full"; + case AVCOL_RANGE_NB: + return "Not ABI"; + default: + return ""; + } +} + +std::string VideoProperties::getColorPrimaries() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->color_primaries ) + { + case AVCOL_PRI_BT709: + return "Rec 709"; + case AVCOL_PRI_UNSPECIFIED: + return "unspecified"; + case AVCOL_PRI_BT470M: + return "BT 470M"; + case AVCOL_PRI_BT470BG: + return "Rec 601 (PAL & SECAM)"; + case AVCOL_PRI_SMPTE170M: + return "Rec 601 (NTSC)"; + case AVCOL_PRI_SMPTE240M: + return "Smpte 240 (NTSC)"; + case AVCOL_PRI_FILM: + return "Film"; +#if LIBAVCODEC_VERSION_MAJOR > 54 +#ifdef AVCOL_TRC_BT2020_CL + case AVCOL_PRI_BT2020: + return "ITU-R BT2020"; +#endif +#endif + case AVCOL_PRI_NB: + return "Not ABI"; + default: + return ""; + } +} + +std::string VideoProperties::getChromaSampleLocation() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->chroma_sample_location ) + { + case AVCHROMA_LOC_UNSPECIFIED: + return "unspecified"; + case AVCHROMA_LOC_LEFT: + return "left (mpeg2/4, h264 default)"; + case AVCHROMA_LOC_CENTER: + return "center (mpeg1, jpeg, h263)"; + case AVCHROMA_LOC_TOPLEFT: + return "top left"; + case AVCHROMA_LOC_TOP: + return "top"; + case AVCHROMA_LOC_BOTTOMLEFT: + return "bottom left"; + case AVCHROMA_LOC_BOTTOM: + return "bottom"; + case AVCHROMA_LOC_NB: + return "Not ABI"; + default: + return ""; + } +} + +std::string VideoProperties::getFieldOrder() const +{ + if( ! _codecContext ) + return "unknown codec context"; + + switch( _codecContext->field_order ) + { + case AV_FIELD_UNKNOWN: + return "unknown"; + case AV_FIELD_PROGRESSIVE: + return "progressive"; + case AV_FIELD_TT: + return "top top"; + case AV_FIELD_BB: + return "bottom bottom"; + case AV_FIELD_TB: + return "top bottom"; + case AV_FIELD_BT: + return "bottom top"; + default: + return ""; + } +} + +std::string VideoProperties::getPixelName() const +{ + if( _pixFmt && _pixFmt->name ) + return std::string( _pixFmt->name ); + return "unknown pixel name"; +} + +std::string VideoProperties::getEndianess() const +{ + if( _pixFmt ) + return ( _pixFmt->flags & PIX_FMT_BE ) ? "big" : "little"; + return "unknown pixel format"; +} + + +int64_t VideoProperties::getStartTimecode() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->timecode_frame_start; +} + +std::string VideoProperties::getStartTimecodeString() const +{ + int64_t stratTimeCode = getStartTimecode(); + std::ostringstream os; + os << std::setfill( '0' ); + os << std::setw(2) << ( stratTimeCode >> 19 & 0x1f ) << ":"; // 5-bit hours + os << std::setw(2) << ( stratTimeCode >> 13 & 0x3f ) << ":"; // 6-bit minutes + os << std::setw(2) << ( stratTimeCode >> 6 & 0x3f ) ; // 6-bit seconds + os << ( stratTimeCode & 1 << 24 ? ';' : ':' ); // 1-bit drop flag + os << std::setw(2) << ( stratTimeCode & 0x3f ); // 6-bit frames + return os.str(); +} + + +Rational VideoProperties::getTimeBase() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + + Rational timeBase = { + _codecContext->time_base.num, + _codecContext->time_base.den, + }; + return timeBase; +} + +Rational VideoProperties::getSar() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + + Rational sar = { + _codecContext->sample_aspect_ratio.num, + _codecContext->sample_aspect_ratio.den, + }; + return sar; +} + +Rational VideoProperties::getDar() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + + int darNum, darDen; + av_reduce( &darNum, &darDen, + _codecContext->width * getSar().num, + _codecContext->height * getSar().den, + 1024 * 1024); + + Rational dar = { + darNum, + darDen, + }; + return dar; +} + +size_t VideoProperties::getCodecId() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->codec_id; +} + +size_t VideoProperties::getBitRate() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->bit_rate; +} + +size_t VideoProperties::getMaxBitRate() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->rc_max_rate; +} + +size_t VideoProperties::getMinBitRate() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->rc_min_rate; +} + +size_t VideoProperties::getTicksPerFrame() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->ticks_per_frame; +} + +size_t VideoProperties::getWidth() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->width; +} + +size_t VideoProperties::getHeight() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->height; +} + +size_t VideoProperties::getGopSize() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->gop_size; +} + +size_t VideoProperties::getDtgActiveFormat() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->dtg_active_format; +} + +size_t VideoProperties::getReferencesFrames() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->refs; +} + +int VideoProperties::getProfile() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->profile; +} + +int VideoProperties::getLevel() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->level; +} + +size_t VideoProperties::getComponentsCount() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return _pixFmt->nb_components; +} + +size_t VideoProperties::getBitDepth() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return av_get_bits_per_pixel( _pixFmt ); +} + +size_t VideoProperties::getChromaWidth() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return _pixFmt->log2_chroma_w; +} + +size_t VideoProperties::getChromaHeight() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return _pixFmt->log2_chroma_h; +} + +double VideoProperties::getFps() const +{ + Rational timeBase = getTimeBase(); + double fps = 1.0 * timeBase.den / ( timeBase.num * getTicksPerFrame() ); + if( isinf( fps ) ) + fps = 0.0; + return fps; +} + +bool VideoProperties::hasBFrames() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return (bool) _codecContext->has_b_frames; +} + +bool VideoProperties::isIndexedColors() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return (bool) _pixFmt->flags & PIX_FMT_PAL; +} + +bool VideoProperties::isBitWisePacked() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return (bool) _pixFmt->flags & PIX_FMT_BITSTREAM; +} + +bool VideoProperties::isHardwareAccelerated() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return (bool) _pixFmt->flags & PIX_FMT_HWACCEL; +} + +bool VideoProperties::isPlanar() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return (bool) _pixFmt->flags & PIX_FMT_PLANAR; +} + +bool VideoProperties::isRgbPixelData() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + return (bool) _pixFmt->flags & PIX_FMT_RGB; +} + +bool VideoProperties::isPseudoPaletted() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + +#if LIBAVCODEC_VERSION_MAJOR > 53 + return (bool) _pixFmt->flags & PIX_FMT_PSEUDOPAL; +#else + return false; +#endif +} + +bool VideoProperties::hasAlpha() const +{ + if( ! _pixFmt ) + throw std::runtime_error( "unknown pixel format" ); + +#if LIBAVCODEC_VERSION_MAJOR > 53 + return (bool) _pixFmt->flags & PIX_FMT_ALPHA; +#else + return false; +#endif +} + +void VideoProperties::analyseGopStructure( IProgress& progress ) +{ + if( _formatContext && _codecContext && _codec ) + { + if( _codec->capabilities & CODEC_CAP_TRUNCATED ) + _codecContext->flags|= CODEC_FLAG_TRUNCATED; + + if( _codecContext->width && _codecContext->height ) + { + AVPacket pkt; + +#if LIBAVCODEC_VERSION_MAJOR > 54 + AVFrame* frame = av_frame_alloc(); +#else + AVFrame* frame = avcodec_alloc_frame(); +#endif + + av_init_packet( &pkt ); + avcodec_open2( _codecContext, _codec, NULL ); + + int count = 0; + int gotFrame = 0; + bool stopAnalyse = false; + + while( ! av_read_frame( const_cast( _formatContext ), &pkt ) ) + { + if( pkt.stream_index == (int)_streamId ) + { + avcodec_decode_video2( _codecContext, frame, &gotFrame, &pkt ); + if( gotFrame ) + { + _gopStructure.push_back( std::make_pair( av_get_picture_type_char( frame->pict_type ), frame->key_frame ) ); + _isInterlaced = frame->interlaced_frame; + _isTopFieldFirst = frame->top_field_first; + ++count; + if( progress.progress( count, _codecContext->gop_size ) == eJobStatusCancel ) + stopAnalyse = true; + } + } + + av_free_packet( &pkt ); + + if( _codecContext->gop_size == count ) + { + stopAnalyse = true; + } + + if( stopAnalyse ) + break; + } +#if LIBAVCODEC_VERSION_MAJOR > 54 + av_frame_free( &frame ); +#else +#if LIBAVCODEC_VERSION_MAJOR > 53 + avcodec_free_frame( &frame ); +#else + av_free( frame ); +#endif +#endif + } + } +} + +std::vector VideoProperties::getChannels() const +{ + std::vector channels; + if( _pixFmt ) + { + for( size_t channel = 0; channel < (size_t)_pixFmt->nb_components; ++channel ) + { + Channel c; + c.id = channel; + c.chromaHeight = (size_t)_pixFmt->comp[channel].plane; + c.bitStep = (size_t)_pixFmt->comp[channel].step_minus1; + channels.push_back( c ); + } + } + return channels; +} + +PropertiesMap VideoProperties::getPropertiesAsMap() const +{ + PropertiesMap dataMap; + + detail::add( dataMap, "streamId", getStreamId() ); + detail::add( dataMap, "codecId", getCodecId() ); + detail::add( dataMap, "codecName", getCodecName() ); + detail::add( dataMap, "codecLongName", getCodecLongName() ); + detail::add( dataMap, "profile", getProfile() ); + detail::add( dataMap, "profileName", getProfileName() ); + detail::add( dataMap, "level", getLevel() ); + detail::add( dataMap, "startTimecode", getStartTimecode() ); + detail::add( dataMap, "width", getWidth() ); + detail::add( dataMap, "height", getHeight() ); + detail::add( dataMap, "pixelAspectRatio", getSar().num / getSar().den ); + detail::add( dataMap, "displayAspectRatio", getDar().num / getDar().den ); + detail::add( dataMap, "dtgActiveFormat", getDtgActiveFormat() ); + detail::add( dataMap, "componentsCount", getComponentsCount() ); + detail::add( dataMap, "pixelType", getPixelName() ); + detail::add( dataMap, "bitWiseAcked", isBitWisePacked() ); + detail::add( dataMap, "rgbPixel", isRgbPixelData() ); + detail::add( dataMap, "asAlpha", hasAlpha() ); + detail::add( dataMap, "chromaWidth", getChromaWidth() ); + detail::add( dataMap, "chromaHeight", getChromaHeight() ); + detail::add( dataMap, "endianess", getEndianess() ); + detail::add( dataMap, "colorTransfert", getColorTransfert() ); + detail::add( dataMap, "colorspace", getColorspace() ); + detail::add( dataMap, "colorRange", getColorRange() ); + detail::add( dataMap, "colorPrimaries", getColorPrimaries() ); + detail::add( dataMap, "indexedColors", isIndexedColors() ); + detail::add( dataMap, "pseudoPaletted", isPseudoPaletted() ); + detail::add( dataMap, "chromaSampleLocation", getChromaSampleLocation() ); + detail::add( dataMap, "interlaced ", isInterlaced() ); + detail::add( dataMap, "topFieldFirst", isTopFieldFirst() ); + detail::add( dataMap, "fieldOrder", getFieldOrder() ); + detail::add( dataMap, "timeBase", getTimeBase().num / getTimeBase().den ); + detail::add( dataMap, "fps", getFps() ); + detail::add( dataMap, "ticksPerFrame", getTicksPerFrame() ); + detail::add( dataMap, "bitRate", getBitRate() ); + detail::add( dataMap, "maxBitRate", getMaxBitRate() ); + detail::add( dataMap, "minBitRate", getMinBitRate() ); + detail::add( dataMap, "gopSize", getGopSize() ); + + std::string gop; + NoDisplayProgress progress; + std::vector< std::pair< char, bool > > gopStructure = getGopStructure(); + for( size_t frameIndex = 0; frameIndex < gopStructure.size(); ++frameIndex ) + { + gop += gopStructure.at( frameIndex ).first; + gop += ( gopStructure.at( frameIndex ).second ? "*" : " " ); + } + detail::add( dataMap, "gop", gop ); + + detail::add( dataMap, "hasBFrames", hasBFrames() ); + detail::add( dataMap, "referencesFrames", getReferencesFrames() ); + + for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) + { + detail::add( dataMap, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); + } + + return dataMap; +} + +} diff --git a/src/AvTranscoder/mediaProperty/VideoProperties.hpp b/src/AvTranscoder/mediaProperty/VideoProperties.hpp new file mode 100644 index 00000000..315d77a1 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/VideoProperties.hpp @@ -0,0 +1,129 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_VIDEO_PROPERTIES_HPP +#define _AV_TRANSCODER_MEDIA_PROPERTY_VIDEO_PROPERTIES_HPP + +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +#include +#include +#include + +namespace avtranscoder +{ + +struct AvExport Channel +{ + size_t id; + size_t chromaHeight; + size_t bitStep; +}; + +class AvExport VideoProperties +{ +public: + VideoProperties( const AVFormatContext* formatContext, const size_t index, IProgress& progress, const EAnalyseLevel level = eAnalyseLevelFirstGop ); + + std::string getCodecName() const; + std::string getCodecLongName() const; + std::string getProfileName() const; + std::string getColorTransfert() const; + std::string getColorspace() const; + std::string getColorRange() const; + std::string getColorPrimaries() const; + std::string getChromaSampleLocation() const; + std::string getFieldOrder() const; + + std::string getPixelName() const; + std::string getEndianess() const; + + int64_t getStartTimecode() const; + std::string getStartTimecodeString() const; + + Rational getTimeBase() const; + Rational getSar() const; // sample/pixel aspect ratio + Rational getDar() const; // display aspect ratio + + size_t getStreamId() const { return _streamId; } + size_t getCodecId() const; + size_t getBitRate() const; + size_t getMaxBitRate() const; + size_t getMinBitRate() const; + size_t getTicksPerFrame() const; + size_t getWidth() const; + size_t getHeight() const; + size_t getGopSize() const; + size_t getDtgActiveFormat() const; + size_t getReferencesFrames() const; + int getProfile() const; + int getLevel() const; + size_t getComponentsCount() const; + size_t getBitDepth() const; + size_t getChromaWidth() const; + size_t getChromaHeight() const; + + double getFps() const; + + bool hasBFrames() const; + bool isIndexedColors() const; + bool isBitWisePacked() const; + bool isHardwareAccelerated() const; + bool isPlanar() const; + bool isRgbPixelData() const; + bool isPseudoPaletted() const; + bool hasAlpha() const; + + //@{ + // Warning: Can acces these data when analyse first gop + // @see EAnalyseLevel + // @see analyseGopStructure + bool isInterlaced() const { return _isInterlaced; } + bool isTopFieldFirst() const { return _isTopFieldFirst; } + std::vector< std::pair< char, bool > > getGopStructure() const { return _gopStructure; } + //@} + + std::vector getChannels() const; + + PropertiesMap& getMetadatas() { return _metadatas; } + +#ifndef SWIG + const AVFormatContext& getAVFormatContext() { return *_formatContext; } + AVCodecContext& getAVCodecContext() { return *_codecContext; } + const AVPixFmtDescriptor& getAVPixFmtDescriptor() { return *_pixFmt; } +#endif + + PropertiesMap getPropertiesAsMap() const; ///< Return all video properties as a map (name of property: value) + +private: + /** + * @brief frame type / is key frame + * @param progress: callback to get analysis progression + */ + void analyseGopStructure( IProgress& progress ); + +private: + const AVFormatContext* _formatContext; ///< Has link (no ownership) + AVCodecContext* _codecContext; ///< Has link (no ownership) + AVCodec* _codec; ///< Has link (no ownership) + const AVPixFmtDescriptor* _pixFmt; ///< Has link (no ownership) + + size_t _streamId; + //@{ + // Can acces these data when analyse first gop + bool _isInterlaced; + bool _isTopFieldFirst; + std::vector< std::pair< char, bool > > _gopStructure; + //@} + PropertiesMap _metadatas; +}; + +} + +#endif diff --git a/src/AvTranscoder/mediaProperty/VideoStreamProperty.hpp b/src/AvTranscoder/mediaProperty/VideoStreamProperty.hpp deleted file mode 100644 index da3f0778..00000000 --- a/src/AvTranscoder/mediaProperty/VideoStreamProperty.hpp +++ /dev/null @@ -1,344 +0,0 @@ -#ifndef _AV_TRANSCODER_VIDEO_STREAM_PROPERTIES_HPP_ -#define _AV_TRANSCODER_VIDEO_STREAM_PROPERTIES_HPP_ - -extern "C" { -#include -#include -#include -#include -} - -#include -#include -#include - -#ifdef _MSC_VER -#include -#define isnan _isnan -#define isinf(x) (!_finite(x)) -#endif - -namespace avtranscoder -{ - -namespace details -{ - -void getGopProperties( - VideoProperties& vp, - AVFormatContext* formatContext, - AVCodecContext* codecContext, - AVCodec* codec, - const int videoStreamIndex, - IProgress& progress - ) -{ - AVPacket pkt; - -#if LIBAVCODEC_VERSION_MAJOR > 54 - AVFrame* frame = av_frame_alloc(); -#else - AVFrame* frame = avcodec_alloc_frame(); -#endif - - av_init_packet( &pkt ); - avcodec_open2( codecContext, codec, NULL ); - - int count = 0; - int gotFrame = 0; - bool stopAnalyse = false; - - while( ! av_read_frame( formatContext, &pkt ) ) - { - if( pkt.stream_index == videoStreamIndex ) - { - // std::cout << "decode frame" << std::endl; - avcodec_decode_video2( codecContext, frame, &gotFrame, &pkt ); - if( gotFrame ) - { - // std::cout << "inteleaved " << frame->interlaced_frame << std::endl; - vp.gopStructure.push_back( std::pair( av_get_picture_type_char( frame->pict_type ), frame->key_frame ) ); - vp.isInterlaced = frame->interlaced_frame; - vp.topFieldFirst = frame->top_field_first; - ++count; - if( progress.progress( count, codecContext->gop_size ) == eJobStatusCancel ) - stopAnalyse = true; - } - } - - av_free_packet( &pkt ); - - if( codecContext->gop_size == count ) - { - stopAnalyse = true; - } - - if( stopAnalyse ) - break; - } -#if LIBAVCODEC_VERSION_MAJOR > 54 - av_frame_free( &frame ); -#else - #if LIBAVCODEC_VERSION_MAJOR > 53 - avcodec_free_frame( &frame ); - #else - av_free( frame ); - #endif -#endif -} - -} - -std::string makeTimecodeMpegToString( uint32_t tc25bit ) -{ - std::ostringstream os; - os << std::setfill( '0' ); - os << std::setw(2) << ( tc25bit >> 19 & 0x1f ) << ":"; // 5-bit hours - os << std::setw(2) << ( tc25bit >> 13 & 0x3f ) << ":"; // 6-bit minutes - os << std::setw(2) << ( tc25bit >> 6 & 0x3f ) ; // 6-bit seconds - os << ( tc25bit & 1 << 24 ? ';' : ':' ); // 1-bit drop flag - os << std::setw(2) << ( tc25bit & 0x3f ); // 6-bit frames - return os.str(); -} - - -VideoProperties videoStreamInfo( - AVFormatContext* formatContext, - const size_t videoStreamIndex, - IProgress& progress, - const InputFile::EAnalyseLevel level - ) -{ - VideoProperties vp; - AVCodecContext* codec_context = formatContext->streams[videoStreamIndex]->codec; - - codec_context->skip_frame = AVDISCARD_NONE; - - vp.streamId = videoStreamIndex; - - vp.codecId = codec_context->codec_id; - vp.bitRate = codec_context->bit_rate; - vp.maxBitRate = codec_context->rc_max_rate; - vp.minBitRate = codec_context->rc_min_rate; - vp.isInterlaced = false; - vp.topFieldFirst = false; - - vp.ticksPerFrame = codec_context->ticks_per_frame, - vp.width = codec_context->width, - vp.height = codec_context->height, - vp.gopSize = codec_context->gop_size, - vp.dtgActiveFormat = codec_context->dtg_active_format, - vp.referencesFrames = codec_context->refs, - vp.profile = codec_context->profile, - vp.level = codec_context->level; - - vp.timeBase.num = codec_context->time_base.num; - vp.timeBase.den = codec_context->time_base.den; - vp.sar.num = codec_context->sample_aspect_ratio.num; - vp.sar.den = codec_context->sample_aspect_ratio.den; - - vp.startTimecode = makeTimecodeMpegToString( codec_context->timecode_frame_start ); - - int darNum, darDen; - av_reduce( &darNum, &darDen, - codec_context->width * codec_context->sample_aspect_ratio.num, - codec_context->height * codec_context->sample_aspect_ratio.den, - 1024 * 1024); - vp.dar.num = darNum; - vp.dar.den = darDen; - - vp.fps = 1.0 * codec_context->time_base.den / ( codec_context->time_base.num * codec_context->ticks_per_frame ); - - if( isinf( vp.fps ) ) - vp.fps = 0.0; - - vp.hasBFrames = (bool) codec_context->has_b_frames; - - - vp.colorspace = ""; - vp.colorTransfert = ""; - vp.colorRange = ""; - vp.colorPrimaries = ""; - vp.chromaSampleLocation = ""; - vp.fieldOrder = ""; - - switch( codec_context->color_trc ) - { - case AVCOL_TRC_BT709: vp.colorTransfert = "Rec 709 / ITU-R BT1361"; break; - case AVCOL_TRC_UNSPECIFIED: vp.colorTransfert = "unspecified"; break; - case AVCOL_TRC_GAMMA22: vp.colorTransfert = "Gamma 2.2"; break; - case AVCOL_TRC_GAMMA28: vp.colorTransfert = "Gamma 2.8"; break; -#if LIBAVCODEC_VERSION_MAJOR > 53 - case AVCOL_TRC_SMPTE240M: vp.colorTransfert = "Smpte 240M"; break; -#endif -#if LIBAVCODEC_VERSION_MAJOR > 54 - #ifdef AVCOL_TRC_SMPTE170M - case AVCOL_TRC_SMPTE170M: vp.colorTransfert = "Rec 601 / ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC"; break; - #endif - #ifdef AVCOL_TRC_LINEAR - case AVCOL_TRC_LINEAR: vp.colorTransfert = "Linear transfer characteristics"; break; - #endif - #ifdef AVCOL_TRC_LOG - case AVCOL_TRC_LOG: vp.colorTransfert = "Logarithmic transfer characteristic (100:1 range)"; break; - #endif - #ifdef AVCOL_TRC_LOG_SQRT - case AVCOL_TRC_LOG_SQRT: vp.colorTransfert = "Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range)"; break; - #endif - #ifdef AVCOL_TRC_IEC61966_2_4 - case AVCOL_TRC_IEC61966_2_4: vp.colorTransfert = "IEC 61966-2-4"; break; - #endif - #ifdef AVCOL_TRC_BT1361_ECG - case AVCOL_TRC_BT1361_ECG: vp.colorTransfert = "ITU-R BT1361 Extended Colour Gamut"; break; - #endif - #ifdef AVCOL_TRC_IEC61966_2_1 - case AVCOL_TRC_IEC61966_2_1: vp.colorTransfert = "IEC 61966-2-1 (sRGB or sYCC)"; break; - #endif - #ifdef AVCOL_TRC_BT2020_10 - case AVCOL_TRC_BT2020_10: vp.colorTransfert = "ITU-R BT2020 for 10 bit system"; break; - #endif - #ifdef AVCOL_TRC_BT2020_12 - case AVCOL_TRC_BT2020_12: vp.colorTransfert = "ITU-R BT2020 for 12 bit system"; break; - #endif -#endif - case AVCOL_TRC_NB: vp.colorTransfert = "Not ABI"; break; - default: break; - } - switch( codec_context->colorspace ) - { - case AVCOL_SPC_RGB: vp.colorspace = "RGB"; break; - case AVCOL_SPC_BT709: vp.colorspace = "Rec 709"; break; - case AVCOL_SPC_UNSPECIFIED: vp.colorspace = "unspecified"; break; - case AVCOL_SPC_FCC: vp.colorspace = "Four CC"; break; - case AVCOL_SPC_BT470BG: vp.colorspace = "BT470 (PAL - 625)"; break; - case AVCOL_SPC_SMPTE170M: vp.colorspace = "Smpte 170M (NTSC)"; break; - case AVCOL_SPC_SMPTE240M: vp.colorspace = "Smpte 240M"; break; -#if LIBAVCODEC_VERSION_MAJOR > 53 - case AVCOL_SPC_YCOCG: vp.colorspace = "Y Co Cg"; break; -//#else -// case AVCOL_SPC_YCGCO: vp.colorspace = "Y Cg Co"; break; -#endif -#if LIBAVCODEC_VERSION_MAJOR > 54 - #ifdef AVCOL_TRC_BT2020_12 - case AVCOL_SPC_BT2020_NCL: vp.colorspace = "ITU-R BT2020 non-constant luminance system"; break; - #endif - #ifdef AVCOL_TRC_BT2020_CL - case AVCOL_SPC_BT2020_CL: vp.colorspace = "ITU-R BT2020 constant luminance system"; break; - #endif -#endif - case AVCOL_SPC_NB: vp.colorspace = "Not ABI"; break; - default: break; - } - switch( codec_context->color_range ) - { - case AVCOL_RANGE_UNSPECIFIED: vp.colorRange = "unspecified"; break; - case AVCOL_RANGE_MPEG: vp.colorRange = "Head"; break; - case AVCOL_RANGE_JPEG: vp.colorRange = "Full"; break; - case AVCOL_RANGE_NB: vp.colorRange = "Not ABI"; break; - default: break; - } - switch( codec_context->color_primaries ) - { - case AVCOL_PRI_BT709: vp.colorPrimaries = "Rec 709"; break; - case AVCOL_PRI_UNSPECIFIED: vp.colorPrimaries = "unspecified"; break; - case AVCOL_PRI_BT470M: vp.colorPrimaries = "BT 470M"; break; - case AVCOL_PRI_BT470BG: vp.colorPrimaries = "Rec 601 (PAL & SECAM)"; break; - case AVCOL_PRI_SMPTE170M: vp.colorPrimaries = "Rec 601 (NTSC)"; break; - case AVCOL_PRI_SMPTE240M: vp.colorPrimaries = "Smpte 240 (NTSC)"; break; - case AVCOL_PRI_FILM: vp.colorPrimaries = "Film"; break; -#if LIBAVCODEC_VERSION_MAJOR > 54 - #ifdef AVCOL_TRC_BT2020_CL - case AVCOL_PRI_BT2020: vp.colorPrimaries = "ITU-R BT2020"; break; - #endif -#endif - case AVCOL_PRI_NB: vp.colorPrimaries = "Not ABI"; break; - default: break; - } - switch( codec_context->chroma_sample_location ) - { - case AVCHROMA_LOC_UNSPECIFIED: vp.chromaSampleLocation = "unspecified"; break; - case AVCHROMA_LOC_LEFT: vp.chromaSampleLocation = "left (mpeg2/4, h264 default)"; break; - case AVCHROMA_LOC_CENTER: vp.chromaSampleLocation = "center (mpeg1, jpeg, h263)"; break; - case AVCHROMA_LOC_TOPLEFT: vp.chromaSampleLocation = "top left"; break; - case AVCHROMA_LOC_TOP: vp.chromaSampleLocation = "top"; break; - case AVCHROMA_LOC_BOTTOMLEFT: vp.chromaSampleLocation = "bottom left"; break; - case AVCHROMA_LOC_BOTTOM: vp.chromaSampleLocation = "bottom"; break; - case AVCHROMA_LOC_NB: vp.chromaSampleLocation = "Not ABI"; break; - default: break; - } - switch( codec_context->field_order ) - { - case AV_FIELD_UNKNOWN: vp.fieldOrder = "unknown"; break; - case AV_FIELD_PROGRESSIVE: vp.fieldOrder = "progressive"; break; - case AV_FIELD_TT: vp.fieldOrder = "top top"; break; - case AV_FIELD_BB: vp.fieldOrder = "bottom bottom"; break; - case AV_FIELD_TB: vp.fieldOrder = "top bottom"; break; - case AV_FIELD_BT: vp.fieldOrder = "bottom top"; break; - default: break; - } -#if LIBAVUTIL_VERSION_MAJOR > 51 - const AVPixFmtDescriptor* pixFmt = av_pix_fmt_desc_get( codec_context->pix_fmt ); -#else - const AVPixFmtDescriptor* pixFmt = NULL; - if( codec_context->pix_fmt >= 0 && codec_context->pix_fmt < PIX_FMT_NB ) - pixFmt = &av_pix_fmt_descriptors[ codec_context->pix_fmt ]; -#endif - - if( pixFmt != NULL ) - { - vp.pixelName = pixFmt->name; - vp.componentsCount = pixFmt->nb_components; - vp.chromaWidth = pixFmt->log2_chroma_w; - vp.chromaHeight = pixFmt->log2_chroma_h; - vp.endianess = ( pixFmt->flags & PIX_FMT_BE ) ? "big" : "little"; - vp.indexedColors = (bool) pixFmt->flags & PIX_FMT_PAL; - vp.bitWisePacked = (bool) pixFmt->flags & PIX_FMT_BITSTREAM; - vp.hardwareAcceleration = (bool) pixFmt->flags & PIX_FMT_HWACCEL; - vp.notFirstPlane = (bool) pixFmt->flags & PIX_FMT_PLANAR; - vp.rgbPixelData = (bool) pixFmt->flags & PIX_FMT_RGB; -#if LIBAVCODEC_VERSION_MAJOR > 53 - vp.pseudoPaletted = (bool) pixFmt->flags & PIX_FMT_PSEUDOPAL; - vp.asAlpha = (bool) pixFmt->flags & PIX_FMT_ALPHA; -#else -#endif - - for( size_t channel = 0; channel < (size_t)pixFmt->nb_components; ++channel ) - { - Channel c; - c.id = channel; - c.chromaHeight = (size_t)pixFmt->comp[channel].plane; - c.bitStep = (size_t)pixFmt->comp[channel].step_minus1; - vp.channels.push_back( c ); - } - } - - AVCodec* codec = NULL; - if( ( codec = avcodec_find_decoder( codec_context->codec_id ) ) != NULL ) - { - if( codec->capabilities & CODEC_CAP_TRUNCATED ) - codec_context->flags|= CODEC_FLAG_TRUNCATED; - - vp.codecName = codec->name; - vp.codecLongName = codec->long_name; - - if( codec_context->profile != -99 ) - { - const char* profile; - if( ( profile = av_get_profile_name( codec, codec_context->profile ) ) != NULL ) - vp.profileName = profile; - } - - // std::cout << "pass here " << codec_context->width << "x" << codec_context->height<< std::endl; - - if( codec_context->width && codec_context->height )// && level != InputFile::eAnalyseLevelFast ) - { - // std::cout << "full analysis" << std::endl; - details::getGopProperties( vp, formatContext, codec_context, codec, videoStreamIndex, progress ); - } - } - - return vp; -} - -} - -#endif diff --git a/src/AvTranscoder/mediaProperty/mediaProperty.cpp b/src/AvTranscoder/mediaProperty/mediaProperty.cpp deleted file mode 100644 index 1b950179..00000000 --- a/src/AvTranscoder/mediaProperty/mediaProperty.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "mediaProperty.hpp" - -extern "C" { -#include -} - -#include -#include - -namespace avtranscoder -{ - -namespace detail -{ - -template -void add( MetadatasMap& dataMap, const std::string& key, const T& value ) -{ - std::stringstream ss; - ss << value; - add( dataMap, key, ss.str() ); -} - -template<> -void add( MetadatasMap& dataMap, const std::string& key, const std::string& value ) -{ - dataMap.push_back( std::pair( key, value ) ); -} - -template<> -void add( MetadatasMap& dataMap, const std::string& key, const bool& value ) -{ - add( dataMap, key, value ? "True" : "False" ); -} - -void fillMetadataDictionnary( AVDictionary* avdictionnary, MetadatasMap& metadata ) -{ - AVDictionaryEntry* tag = NULL; - while( ( tag = av_dict_get( avdictionnary, "", tag, AV_DICT_IGNORE_SUFFIX ) ) ) - { - metadata.push_back( std::pair( tag->key, tag->value ) ); - } -} - -} - -MetadatasMap VideoProperties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "stream id", streamId ); - detail::add( dataMap, "codec id", codecId ); - detail::add( dataMap, "codec name", codecName ); - detail::add( dataMap, "codec long name", codecLongName ); - detail::add( dataMap, "profile", profile ); - detail::add( dataMap, "profile name", profileName ); - detail::add( dataMap, "level", level ); - detail::add( dataMap, "start timecode", startTimecode ); - detail::add( dataMap, "width", width ); - detail::add( dataMap, "height", height ); - detail::add( dataMap, "pixel aspect ratio", sar.num / sar.den ); - detail::add( dataMap, "display aspect ratio", dar.num / dar.den ); - detail::add( dataMap, "dtgActiveFormat", dtgActiveFormat ); - detail::add( dataMap, "components count", componentsCount ); - detail::add( dataMap, "pixel type", pixelName ); - detail::add( dataMap, "bit wise acked", bitWisePacked ); - detail::add( dataMap, "rgb pixel", rgbPixelData ); - detail::add( dataMap, "as alpha", asAlpha ); - detail::add( dataMap, "chroma width", chromaWidth ); - detail::add( dataMap, "chroma height", chromaHeight ); - detail::add( dataMap, "endianess", endianess ); - detail::add( dataMap, "color transfert", colorTransfert ); - detail::add( dataMap, "colorspace", colorspace ); - detail::add( dataMap, "color range", colorRange ); - detail::add( dataMap, "color primaries", colorPrimaries ); - detail::add( dataMap, "indexed colors", indexedColors ); - detail::add( dataMap, "pseudo paletted", pseudoPaletted ); - detail::add( dataMap, "chroma sample location", chromaSampleLocation); - detail::add( dataMap, "interlaced ", isInterlaced ); - detail::add( dataMap, "top field first", topFieldFirst ); - detail::add( dataMap, "field order", fieldOrder); - detail::add( dataMap, "timeBase", timeBase.num / timeBase.den ); - detail::add( dataMap, "fps", fps ); - detail::add( dataMap, "ticksPerFrame", ticksPerFrame ); - detail::add( dataMap, "bit rate", bitRate ); - detail::add( dataMap, "max bit rate", maxBitRate ); - detail::add( dataMap, "min bit rate", minBitRate ); - detail::add( dataMap, "gop size", gopSize ); - - std::string gop; - for( size_t frameIndex = 0; frameIndex < gopStructure.size(); ++frameIndex ) - { - gop += gopStructure.at( frameIndex ).first; - gop += ( gopStructure.at( frameIndex ).second ? "*" : " " ); - } - detail::add( dataMap, "gop", gop ); - - detail::add( dataMap, "has B frames", hasBFrames ); - detail::add( dataMap, "references frames", referencesFrames ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -MetadatasMap AudioProperties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "stream id", streamId ); - detail::add( dataMap, "codec id", codecId ); - detail::add( dataMap, "codec name", codecName ); - detail::add( dataMap, "codec long name", codecLongName ); - detail::add( dataMap, "sample format name", sampleFormatName ); - detail::add( dataMap, "sample format long name", sampleFormatLongName ); - detail::add( dataMap, "sample rate", sampleRate ); - detail::add( dataMap, "bit rate", bit_rate ); - detail::add( dataMap, "channels", channels ); - detail::add( dataMap, "channel layout", channelLayout ); - detail::add( dataMap, "channel name", channelName ); - detail::add( dataMap, "channel description", channelDescription ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -MetadatasMap DataProperties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "streamId", streamId ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -MetadatasMap SubtitleProperties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "streamId", streamId ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -MetadatasMap AttachementProperties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "streamId", streamId ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -MetadatasMap UnknownProperties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "streamId", streamId ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -MetadatasMap Properties::getDataMap() const -{ - MetadatasMap dataMap; - - detail::add( dataMap, "filename", filename ); - detail::add( dataMap, "format name", formatName ); - detail::add( dataMap, "format long name", formatLongName ); - - detail::add( dataMap, "start time", startTime ); - detail::add( dataMap, "duration", duration ); - detail::add( dataMap, "bitrate", bitRate ); - detail::add( dataMap, "number of streams", streamsCount ); - detail::add( dataMap, "number of programs", programsCount ); - detail::add( dataMap, "number of video streams", videoStreams.size() ); - detail::add( dataMap, "number of audio streams", audioStreams.size() ); - detail::add( dataMap, "number of data streams", dataStreams.size() ); - detail::add( dataMap, "number of subtitle streams", subtitleStreams.size() ); - detail::add( dataMap, "number of attachement streams", attachementStreams.size() ); - detail::add( dataMap, "number of unknown streams", unknownStreams.size() ); - - for( size_t metadataIndex = 0; metadataIndex < metadatas.size(); ++metadataIndex ) - { - detail::add( dataMap, metadatas.at( metadataIndex ).first, metadatas.at( metadataIndex ).second ); - } - - return dataMap; -} - -} diff --git a/src/AvTranscoder/mediaProperty/mediaProperty.hpp b/src/AvTranscoder/mediaProperty/mediaProperty.hpp deleted file mode 100644 index 89e89013..00000000 --- a/src/AvTranscoder/mediaProperty/mediaProperty.hpp +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef _AV_TRANSCODER_MEDIA_HPP_ -#define _AV_TRANSCODER_MEDIA_HPP_ - -#include - -#include -#include -#include - -namespace avtranscoder -{ - -/** - * @brief Can get all data of Properties structures by getDataMap(), which return a MetadatasMap. - */ -typedef std::vector< std::pair > MetadatasMap; - -namespace detail -{ - /** - * @brief Fill metadata parameter with the given AVDictionary. - */ - void AvExport fillMetadataDictionnary( AVDictionary* avdictionnary, MetadatasMap& metadata ); -} - -struct AvExport Channel -{ - size_t id; - size_t chromaHeight; - size_t bitStep; -}; - -struct AvExport VideoProperties -{ - VideoProperties() - { - timeBase.num = 0; - timeBase.den = 0; - sar.num = 0; - sar.den = 0; - dar.num = 0; - dar.den = 0; - } - -public: - std::string codecName; - std::string codecLongName; - std::string profileName; - std::string colorTransfert; - std::string colorspace; - std::string colorRange; - std::string colorPrimaries; - std::string chromaSampleLocation; - std::string fieldOrder; - - std::string pixelName; - std::string endianess; - - std::string startTimecode; - - Rational timeBase; - Rational sar; // sample/pixel aspect ratio - Rational dar; // display aspect ratio - - size_t streamId; - size_t codecId; - size_t bitRate; - size_t maxBitRate; - size_t minBitRate; - size_t ticksPerFrame; - size_t width; - size_t height; - size_t gopSize; - size_t dtgActiveFormat; - size_t referencesFrames; - int profile; - int level; - size_t componentsCount; - size_t chromaWidth; - size_t chromaHeight; - - double fps; - - bool hasBFrames; - bool indexedColors; - bool bitWisePacked; - bool hardwareAcceleration; - bool notFirstPlane; - bool rgbPixelData; - bool pseudoPaletted; - bool asAlpha; - bool isInterlaced; - bool topFieldFirst; - - // ( frame type / is key frame ) - std::vector< std::pair< char, bool > > gopStructure; - std::vector channels; - - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -struct AvExport AudioProperties -{ - std::string codecName; - std::string codecLongName; - std::string sampleFormatName; - std::string sampleFormatLongName; - std::string channelLayout; - std::string channelName; - std::string channelDescription; - size_t streamId; - size_t codecId; - size_t sampleRate; - size_t channels; - size_t bit_rate; - - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -struct AvExport DataProperties -{ - size_t streamId; - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -struct AvExport SubtitleProperties -{ - size_t streamId; - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -struct AvExport AttachementProperties -{ - size_t streamId; - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -struct AvExport UnknownProperties -{ - size_t streamId; - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -struct AvExport Properties -{ - std::string filename; - std::string formatName; - std::string formatLongName; - size_t streamsCount; - size_t programsCount; - double startTime; - double duration; - size_t bitRate; - size_t packetSize; - - std::vector< VideoProperties > videoStreams; - std::vector< AudioProperties > audioStreams; - std::vector< DataProperties > dataStreams; - std::vector< SubtitleProperties > subtitleStreams; - std::vector< AttachementProperties > attachementStreams; - std::vector< UnknownProperties > unknownStreams; - - MetadatasMap metadatas; - -public: - MetadatasMap getDataMap() const; -}; - -} - -#endif \ No newline at end of file diff --git a/src/AvTranscoder/mediaProperty/mediaProperty.i b/src/AvTranscoder/mediaProperty/mediaProperty.i new file mode 100644 index 00000000..502c3579 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/mediaProperty.i @@ -0,0 +1,53 @@ +%{ +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace avtranscoder; +%} + +namespace std { +// Allow vector of object with no default constructor +%ignore vector< avtranscoder::VideoProperties >::vector(size_type); +%ignore vector< avtranscoder::VideoProperties >::resize; +%ignore vector< avtranscoder::AudioProperties >::vector(size_type); +%ignore vector< avtranscoder::AudioProperties >::resize; +%ignore vector< avtranscoder::DataProperties >::vector(size_type); +%ignore vector< avtranscoder::DataProperties >::resize; +%ignore vector< avtranscoder::SubtitleProperties >::vector(size_type); +%ignore vector< avtranscoder::SubtitleProperties >::resize; +%ignore vector< avtranscoder::AttachementProperties >::vector(size_type); +%ignore vector< avtranscoder::AttachementProperties >::resize; +%ignore vector< avtranscoder::UnknownProperties >::vector(size_type); +%ignore vector< avtranscoder::UnknownProperties >::resize; + +// Create instantiations of a template classes +%template(VideoVector) vector< avtranscoder::VideoProperties >; +%template(AudioVector) vector< avtranscoder::AudioProperties >; +%template(DataVector) vector< avtranscoder::DataProperties >; +%template(SubtitleVector) vector< avtranscoder::SubtitleProperties >; +%template(AttachementVector) vector< avtranscoder::AttachementProperties >; +%template(UnknownVector) vector< avtranscoder::UnknownProperties >; + +%template(PropertyPair) pair< string, string >; +%template(PropertyVector) vector< pair< string, string > >; + +%template(GopPair) pair< char, bool >; +%template(GopVector) vector< pair< char, bool > >; + +%template(ChannelVector) vector< avtranscoder::Channel >; +} + +%include +%include +%include +%include +%include +%include +%include +%include diff --git a/src/AvTranscoder/mediaProperty/printMediaProperty.hpp b/src/AvTranscoder/mediaProperty/print.hpp similarity index 58% rename from src/AvTranscoder/mediaProperty/printMediaProperty.hpp rename to src/AvTranscoder/mediaProperty/print.hpp index a2a69c80..f9c96324 100644 --- a/src/AvTranscoder/mediaProperty/printMediaProperty.hpp +++ b/src/AvTranscoder/mediaProperty/print.hpp @@ -14,13 +14,13 @@ namespace avtranscoder static const size_t keyWidth = 32; static const std::string separator = "===================="; -std::ostream& operator<<( std::ostream& flux, const Properties& properties ) +std::ostream& operator<<( std::ostream& flux, const FileProperties& fileProperties ) { flux << std::left; flux << separator << " Wrapper " << separator << std::endl; - MetadatasMap dataMap = properties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = fileProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -33,8 +33,8 @@ std::ostream& operator<<( std::ostream& flux, const VideoProperties& videoProper flux << std::left; flux << separator << " Video stream " << separator << std::endl; - MetadatasMap dataMap = videoProperties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = videoProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -47,8 +47,8 @@ std::ostream& operator<<( std::ostream& flux, const AudioProperties& audioProper flux << std::left; flux << separator << " Audio stream " << separator << std::endl; - MetadatasMap dataMap = audioProperties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = audioProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -60,8 +60,8 @@ std::ostream& operator<<( std::ostream& flux, const DataProperties& dataProperti { flux << separator << " Data stream " << separator << std::endl; - MetadatasMap dataMap = dataProperties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = dataProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -73,8 +73,8 @@ std::ostream& operator<<( std::ostream& flux, const SubtitleProperties& subtitle { flux << separator << " Subtitle stream " << separator << std::endl; - MetadatasMap dataMap = subtitleProperties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = subtitleProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -86,8 +86,8 @@ std::ostream& operator<<( std::ostream& flux, const AttachementProperties& attac { flux << separator << " Attachement stream " << separator << std::endl; - MetadatasMap dataMap = attachementProperties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = attachementProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -99,8 +99,8 @@ std::ostream& operator<<( std::ostream& flux, const UnknownProperties& unknownPr { flux << separator << " Unknown stream " << separator << std::endl; - MetadatasMap dataMap = unknownProperties.getDataMap(); - for( MetadatasMap::iterator it = dataMap.begin(); it != dataMap.end(); ++it ) + PropertiesMap properties = unknownProperties.getPropertiesAsMap(); + for( PropertiesMap::iterator it = properties.begin(); it != properties.end(); ++it ) { flux << std::setw( keyWidth ) << it->first << ": " << it->second << std::endl; } @@ -114,39 +114,39 @@ std::ostream& operator<<( std::ostream& flux, const InputFile& input ) flux << input.getProperties(); // video streams - for( size_t videoStreamIndex = 0; videoStreamIndex < input.getProperties().videoStreams.size(); ++videoStreamIndex ) + for( size_t videoStreamIndex = 0; videoStreamIndex < input.getProperties().getNbVideoStreams(); ++videoStreamIndex ) { - flux << input.getProperties().videoStreams.at( videoStreamIndex ); + flux << input.getProperties().getVideoProperties().at( videoStreamIndex ); } // audio streams - for( size_t audioStreamIndex = 0; audioStreamIndex < input.getProperties().audioStreams.size(); ++audioStreamIndex ) + for( size_t audioStreamIndex = 0; audioStreamIndex < input.getProperties().getNbAudioStreams(); ++audioStreamIndex ) { - flux << input.getProperties().audioStreams.at( audioStreamIndex ); + flux << input.getProperties().getAudioProperties().at( audioStreamIndex ); } // data streams - for( size_t dataStreamIndex = 0; dataStreamIndex < input.getProperties().dataStreams.size(); ++dataStreamIndex ) + for( size_t dataStreamIndex = 0; dataStreamIndex < input.getProperties().getNbDataStreams(); ++dataStreamIndex ) { - flux << input.getProperties().dataStreams.at( dataStreamIndex ); + flux << input.getProperties().getDataProperties().at( dataStreamIndex ); } // subtitle streams - for( size_t subtitleStreamIndex = 0; subtitleStreamIndex < input.getProperties().subtitleStreams.size(); ++subtitleStreamIndex ) + for( size_t subtitleStreamIndex = 0; subtitleStreamIndex < input.getProperties().getNbSubtitleStreams(); ++subtitleStreamIndex ) { - flux << input.getProperties().subtitleStreams.at( subtitleStreamIndex ); + flux << input.getProperties().getSubtitleProperties().at( subtitleStreamIndex ); } // attachement streams - for( size_t attachementStreamIndex = 0; attachementStreamIndex < input.getProperties().attachementStreams.size(); ++attachementStreamIndex ) + for( size_t attachementStreamIndex = 0; attachementStreamIndex < input.getProperties().getNbAttachementStreams(); ++attachementStreamIndex ) { - flux << input.getProperties().attachementStreams.at( attachementStreamIndex ); + flux << input.getProperties().getAttachementProperties().at( attachementStreamIndex ); } // unknown streams - for( size_t unknownStreamIndex = 0; unknownStreamIndex < input.getProperties().unknownStreams.size(); ++unknownStreamIndex ) + for( size_t unknownStreamIndex = 0; unknownStreamIndex < input.getProperties().getNbUnknownStreams(); ++unknownStreamIndex ) { - flux << input.getProperties().unknownStreams.at( unknownStreamIndex ); + flux << input.getProperties().getUnknownPropertiesProperties().at( unknownStreamIndex ); } return flux; @@ -154,4 +154,4 @@ std::ostream& operator<<( std::ostream& flux, const InputFile& input ) } -#endif \ No newline at end of file +#endif diff --git a/src/AvTranscoder/mediaProperty/util.cpp b/src/AvTranscoder/mediaProperty/util.cpp new file mode 100644 index 00000000..8aff1a47 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/util.cpp @@ -0,0 +1,36 @@ +#include "util.hpp" + +extern "C" { +#include +} + +namespace avtranscoder +{ + +namespace detail +{ + +template<> +void add( PropertiesMap& propertiesMap, const std::string& key, const std::string& value ) +{ + propertiesMap.push_back( std::make_pair( key, value ) ); +} + +template<> +void add( PropertiesMap& propertiesMap, const std::string& key, const bool& value ) +{ + add( propertiesMap, key, value ? "True" : "False" ); +} + +void fillMetadataDictionnary( AVDictionary* avdictionnary, PropertiesMap& metadata ) +{ + AVDictionaryEntry* tag = NULL; + while( ( tag = av_dict_get( avdictionnary, "", tag, AV_DICT_IGNORE_SUFFIX ) ) ) + { + metadata.push_back( std::make_pair( tag->key, tag->value ) ); + } +} + +} + +} diff --git a/src/AvTranscoder/mediaProperty/util.hpp b/src/AvTranscoder/mediaProperty/util.hpp new file mode 100644 index 00000000..c63618c1 --- /dev/null +++ b/src/AvTranscoder/mediaProperty/util.hpp @@ -0,0 +1,45 @@ +#ifndef _AV_TRANSCODER_MEDIA_PROPERTY_UTIL_HPP_ +#define _AV_TRANSCODER_MEDIA_PROPERTY_UTIL_HPP_ + +#include + +#include +#include +#include +#include + +namespace avtranscoder +{ + +/** + * @brief PropertyMap is a vector of pair, because the order of properties matters to us. + */ +typedef std::vector< std::pair > PropertiesMap; + +namespace detail +{ + +template +void add( PropertiesMap& propertiesMap, const std::string& key, const T& value ) +{ + std::stringstream ss; + ss << value; + add( propertiesMap, key, ss.str() ); +} + +template<> +void add( PropertiesMap& propertiesMap, const std::string& key, const std::string& value ); + +template<> +void add( PropertiesMap& propertiesMap, const std::string& key, const bool& value ); + +/** + * @brief Fill metadata parameter with the given AVDictionary. + */ +void AvExport fillMetadataDictionnary( AVDictionary* avdictionnary, PropertiesMap& metadata ); + +} + +} + +#endif diff --git a/src/AvTranscoder/option/Context.hpp b/src/AvTranscoder/option/Context.hpp index b804943c..b7e43e8d 100644 --- a/src/AvTranscoder/option/Context.hpp +++ b/src/AvTranscoder/option/Context.hpp @@ -11,6 +11,9 @@ namespace avtranscoder { +typedef std::vector