From efcccedfd9e3bc98087efecabfe14e2fd15b3d5c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 17:29:11 +0100 Subject: [PATCH 01/10] VideoProperties: skip GOP decoding to estimate the bitrate when analysing only the header --- src/AvTranscoder/properties/VideoProperties.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 99b3bde2..0f933f7d 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -328,7 +328,12 @@ size_t VideoProperties::getBitRate() const if(_codecContext->bit_rate || _codecContext->rc_max_rate) return _codecContext->bit_rate; - LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown.") + if(_levelAnalysis == eAnalyseLevelHeader) + { + LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown.") + return 0; + } + LOG_INFO("Compute the video bitrate by decoding the first GOP.") if(!_codecContext->width || !_codecContext->height) From 05881777ef779ce27af489f92db52a29e94f0b67 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 17:35:32 +0100 Subject: [PATCH 02/10] VideoProperties: refactor how to estimate the video bitrate * The first GOP is already decoded once, in analyseGopStructure private method. * Use the results already computed to estimate the bitrate. --- .../properties/VideoProperties.cpp | 73 ++----------------- 1 file changed, 7 insertions(+), 66 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 0f933f7d..e55b5d27 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -334,75 +334,16 @@ size_t VideoProperties::getBitRate() const return 0; } - LOG_INFO("Compute the video bitrate by decoding the first GOP.") - - if(!_codecContext->width || !_codecContext->height) - throw std::runtime_error("cannot compute bit rate: invalid frame size"); - - if(!_formatContext || !_codec) - throw std::runtime_error("cannot compute bit rate: unknown format or codec"); - if(!_codecContext->width || !_codecContext->height) - throw std::runtime_error("cannot compute bit rate: invalid frame size"); - - // discard no frame type when decode - _codecContext->skip_frame = AVDISCARD_NONE; - - Frame frame; - AVPacket pkt; - av_init_packet(&pkt); - avcodec_open2(_codecContext, _codec, NULL); - - int gotFrame = 0; - size_t nbDecodedFrames = 0; - int gopFramesSize = 0; - int positionOfFirstKeyFrame = -1; - int positionOfLastKeyFrame = -1; - - while(!av_read_frame(const_cast(_formatContext), &pkt)) - { - if(pkt.stream_index == (int)_streamIndex) - { - avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt); - if(gotFrame) - { - // check distance between key frames - AVFrame& avFrame = frame.getAVFrame(); - if(avFrame.pict_type == AV_PICTURE_TYPE_I) - { - if(positionOfFirstKeyFrame == -1) - positionOfFirstKeyFrame = nbDecodedFrames; - else - positionOfLastKeyFrame = nbDecodedFrames; - } - ++nbDecodedFrames; - - // added size of all frames of the same gop - if(positionOfLastKeyFrame == -1) - { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 7, 100) - gopFramesSize += frame.getEncodedSize(); -#else - gopFramesSize += pkt.size; -#endif - } - } - } - av_free_packet(&pkt); - if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) - break; - } - // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) - avcodec_close(_codecContext); - // Returns at the beginning of the stream - const_cast(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); + if(getGopSize() <= 0) + return 0; - const size_t gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame; - if(gopSize > 0) + LOG_INFO("Estimate the video bitrate from the first GOP.") + size_t gopFramesSize = 0; + for(size_t picture = 0; picture < _gopStructure.size(); ++picture) { - const float fps = av_q2d(_formatContext->streams[_streamIndex]->avg_frame_rate); - return (gopFramesSize / gopSize) * 8 * fps; + gopFramesSize += _gopStructure.at(picture).second; } - return 0; + return (gopFramesSize / getGopSize()) * 8 * getFps(); } size_t VideoProperties::getMaxBitRate() const From 8e63e7fe348f99fb26d7e1734a8ab7edc945bddc Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 17:37:40 +0100 Subject: [PATCH 03/10] VideoProperties: throw a runtime if the GOP size is invalid when decoding So no need to check this attribute in other method. --- src/AvTranscoder/properties/VideoProperties.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index e55b5d27..5a1cd518 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -334,9 +334,6 @@ size_t VideoProperties::getBitRate() const return 0; } - if(getGopSize() <= 0) - return 0; - LOG_INFO("Estimate the video bitrate from the first GOP.") size_t gopFramesSize = 0; for(size_t picture = 0; picture < _gopStructure.size(); ++picture) @@ -562,6 +559,12 @@ void VideoProperties::analyseGopStructure(IProgress& progress) // Returns at the beginning of the stream const_cast(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); + + // Check GOP size + if(_gopSize <= 0) + { + throw std::runtime_error("Invalid GOP size when decoding the first data."); + } } } } From 163a02a60d899b1cbbeca68d635f6f3198e3defd Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 17:44:18 +0100 Subject: [PATCH 04/10] VideoProperties: refactor analyseGOPStructure method Return immediatly at the beginning of the function if some attributes are not correctly set. --- .../properties/VideoProperties.cpp | 113 +++++++++--------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 5a1cd518..ce9910eb 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -497,75 +497,74 @@ std::vector > VideoProperties::getGopStructure() const void VideoProperties::analyseGopStructure(IProgress& progress) { - if(_formatContext && _codecContext && _codec) - { - if(_codecContext->width && _codecContext->height) - { - // Discard no frame type when decode - _codecContext->skip_frame = AVDISCARD_NONE; + if(! _formatContext || ! _codecContext || ! _codec) + return; + if(! _codecContext->width || ! _codecContext->height) + return; + + // Discard no frame type when decode + _codecContext->skip_frame = AVDISCARD_NONE; - AVPacket pkt; - av_init_packet(&pkt); + AVPacket pkt; + av_init_packet(&pkt); - // Initialize the AVCodecContext to use the given AVCodec - avcodec_open2(_codecContext, _codec, NULL); + // Initialize the AVCodecContext to use the given AVCodec + avcodec_open2(_codecContext, _codec, NULL); - Frame frame; - size_t count = 0; - int gotFrame = 0; - int positionOfFirstKeyFrame = -1; - int positionOfLastKeyFrame = -1; + Frame frame; + size_t count = 0; + int gotFrame = 0; + int positionOfFirstKeyFrame = -1; + int positionOfLastKeyFrame = -1; - while(!av_read_frame(const_cast(_formatContext), &pkt)) + while(!av_read_frame(const_cast(_formatContext), &pkt)) + { + if(pkt.stream_index == (int)_streamIndex) + { + avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt); + if(gotFrame) { - if(pkt.stream_index == (int)_streamIndex) - { - avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt); - if(gotFrame) - { - AVFrame& avFrame = frame.getAVFrame(); - - _gopStructure.push_back( - std::make_pair(av_get_picture_type_char(avFrame.pict_type), frame.getEncodedSize())); - _isInterlaced = avFrame.interlaced_frame; - _isTopFieldFirst = avFrame.top_field_first; - if(avFrame.pict_type == AV_PICTURE_TYPE_I) - { - if(positionOfFirstKeyFrame == -1) - positionOfFirstKeyFrame = count; - else - positionOfLastKeyFrame = count; - } - - _gopSize = ++count; - } - } - av_free_packet(&pkt); + AVFrame& avFrame = frame.getAVFrame(); - // If the first 2 key frames are found - if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) + _gopStructure.push_back( + std::make_pair(av_get_picture_type_char(avFrame.pict_type), frame.getEncodedSize())); + _isInterlaced = avFrame.interlaced_frame; + _isTopFieldFirst = avFrame.top_field_first; + if(avFrame.pict_type == AV_PICTURE_TYPE_I) { - // Set gop size as distance between these 2 key frames - _gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame; - // Update gop structure to keep only one gop - while(_gopStructure.size() > _gopSize) - _gopStructure.pop_back(); - break; + if(positionOfFirstKeyFrame == -1) + positionOfFirstKeyFrame = count; + else + positionOfLastKeyFrame = count; } + + _gopSize = ++count; } + } + av_free_packet(&pkt); - // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) - avcodec_close(_codecContext); + // If the first 2 key frames are found + if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) + { + // Set gop size as distance between these 2 key frames + _gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame; + // Update gop structure to keep only one gop + while(_gopStructure.size() > _gopSize) + _gopStructure.pop_back(); + break; + } + } - // Returns at the beginning of the stream - const_cast(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); + // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) + avcodec_close(_codecContext); - // Check GOP size - if(_gopSize <= 0) - { - throw std::runtime_error("Invalid GOP size when decoding the first data."); - } - } + // Returns at the beginning of the stream + const_cast(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); + + // Check GOP size + if(_gopSize <= 0) + { + throw std::runtime_error("Invalid GOP size when decoding the first data."); } } From 42f78c9d6cd7edeecc6392a3b353305e5ce1b965 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 17:58:08 +0100 Subject: [PATCH 05/10] FileProperties: update how to construct the properties * Keep a reference to the InputFile. * This new reference will be used to refactor the decoding in case of deep analysis. --- src/AvTranscoder/file/InputFile.cpp | 2 +- src/AvTranscoder/file/InputFile.hpp | 2 +- src/AvTranscoder/properties/FileProperties.cpp | 15 ++++++++------- src/AvTranscoder/properties/FileProperties.hpp | 7 ++++--- src/AvTranscoder/properties/VideoProperties.cpp | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/AvTranscoder/file/InputFile.cpp b/src/AvTranscoder/file/InputFile.cpp index 30e9efd5..41eb8ddb 100644 --- a/src/AvTranscoder/file/InputFile.cpp +++ b/src/AvTranscoder/file/InputFile.cpp @@ -30,7 +30,7 @@ InputFile::InputFile(const std::string& filename) _formatContext.findStreamInfo(); // Get the stream information as properties - _properties = new FileProperties(_formatContext); + _properties = new FileProperties(*this); // Create streams for(size_t streamIndex = 0; streamIndex < _formatContext.getNbStreams(); ++streamIndex) diff --git a/src/AvTranscoder/file/InputFile.hpp b/src/AvTranscoder/file/InputFile.hpp index 2440edbc..60423485 100644 --- a/src/AvTranscoder/file/InputFile.hpp +++ b/src/AvTranscoder/file/InputFile.hpp @@ -79,7 +79,7 @@ class AvExport InputFile std::string getFilename() const { return _filename; } - FormatContext& getFormatContext() { return _formatContext; } + const FormatContext& getFormatContext() const { return _formatContext; } /** * @brief Set the format of the input file diff --git a/src/AvTranscoder/properties/FileProperties.cpp b/src/AvTranscoder/properties/FileProperties.cpp index 8d78d23c..15b03d61 100644 --- a/src/AvTranscoder/properties/FileProperties.cpp +++ b/src/AvTranscoder/properties/FileProperties.cpp @@ -11,9 +11,10 @@ namespace avtranscoder { -FileProperties::FileProperties(const FormatContext& formatContext) - : _formatContext(&formatContext) - , _avFormatContext(&formatContext.getAVFormatContext()) +FileProperties::FileProperties(const InputFile& file) + : _file(file) + , _formatContext(&file.getFormatContext()) + , _avFormatContext(&file.getFormatContext().getAVFormatContext()) , _videoStreams() , _audioStreams() , _dataStreams() @@ -31,8 +32,8 @@ FileProperties::FileProperties(const FormatContext& formatContext) void FileProperties::extractStreamProperties(IProgress& progress, const EAnalyseLevel level) { // Returns at the beginning of the stream before any deep analysis - if(level > eAnalyseLevelHeader && !isRawFormat()) - const_cast(_formatContext)->seek(0, AVSEEK_FLAG_BACKWARD); + if(level > eAnalyseLevelHeader && ! isRawFormat()) + const_cast(_file).seekAtFrame(0, AVSEEK_FLAG_BACKWARD); // clear properties clearStreamProperties(); @@ -123,8 +124,8 @@ void FileProperties::extractStreamProperties(IProgress& progress, const EAnalyse } // Returns at the beginning of the stream after any deep analysis - if(level > eAnalyseLevelHeader && !isRawFormat()) - const_cast(_formatContext)->seek(0, AVSEEK_FLAG_BACKWARD); + if(level > eAnalyseLevelHeader && ! isRawFormat()) + const_cast(_file).seekAtFrame(0, AVSEEK_FLAG_BACKWARD); } std::string FileProperties::getFilename() const diff --git a/src/AvTranscoder/properties/FileProperties.hpp b/src/AvTranscoder/properties/FileProperties.hpp index f873e3f8..d926339f 100644 --- a/src/AvTranscoder/properties/FileProperties.hpp +++ b/src/AvTranscoder/properties/FileProperties.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ class AvExport FileProperties * @note The default streams analyse level is eAnalyseLevelHeader * @see FormatContext */ - FileProperties(const FormatContext& formatContext); + FileProperties(const InputFile& file); /** * @brief Relaunch streams analysis with a specific level. @@ -62,7 +62,7 @@ class AvExport FileProperties size_t getNbAttachementStreams() const { return _attachementStreams.size(); } size_t getNbUnknownStreams() const { return _unknownStreams.size(); } - const FormatContext& getFormatContext() const { return *_formatContext; } + const InputFile& getInputFile() const { return _file; } //@{ // @brief Get the properties at the indicated stream index @@ -110,6 +110,7 @@ class AvExport FileProperties void clearStreamProperties(); ///< Clear all array of stream properties private: + const InputFile& _file; ///< Has link (no ownership) const FormatContext* _formatContext; ///< Has link (no ownership) const AVFormatContext* _avFormatContext; ///< Has link (no ownership) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index ce9910eb..9b847102 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -559,7 +559,7 @@ void VideoProperties::analyseGopStructure(IProgress& progress) avcodec_close(_codecContext); // Returns at the beginning of the stream - const_cast(&_fileProperties->getFormatContext())->seek(0, AVSEEK_FLAG_BYTE); + const_cast(_fileProperties->getInputFile()).seekAtFrame(0, AVSEEK_FLAG_BYTE); // Check GOP size if(_gopSize <= 0) From acd25dc47b4cd06eab23808bb8e1a69c2b5e339c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 18:16:58 +0100 Subject: [PATCH 06/10] VideoProperties: refactor how to analyse the GOP structure Use the avtranscoder objects: easier to maintain. --- .../properties/VideoProperties.cpp | 60 ++++++++----------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 9b847102..28972429 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -1,6 +1,7 @@ #include "VideoProperties.hpp" -#include +#include +#include #include #include #include @@ -502,46 +503,36 @@ void VideoProperties::analyseGopStructure(IProgress& progress) if(! _codecContext->width || ! _codecContext->height) return; + InputFile& file = const_cast(_fileProperties->getInputFile()); + // Get the stream + IInputStream& stream = file.getStream(_streamIndex); + stream.activate(); + // Setup a decoder + VideoDecoder decoder(static_cast(stream)); // Discard no frame type when decode _codecContext->skip_frame = AVDISCARD_NONE; - AVPacket pkt; - av_init_packet(&pkt); - - // Initialize the AVCodecContext to use the given AVCodec - avcodec_open2(_codecContext, _codec, NULL); - - Frame frame; size_t count = 0; - int gotFrame = 0; int positionOfFirstKeyFrame = -1; int positionOfLastKeyFrame = -1; - - while(!av_read_frame(const_cast(_formatContext), &pkt)) + VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelProperties().getAVPixelFormat())); + while(decoder.decodeNextFrame(frame)) { - if(pkt.stream_index == (int)_streamIndex) + AVFrame& avFrame = frame.getAVFrame(); + + _gopStructure.push_back( + std::make_pair(av_get_picture_type_char(avFrame.pict_type), frame.getEncodedSize())); + _isInterlaced = avFrame.interlaced_frame; + _isTopFieldFirst = avFrame.top_field_first; + if(avFrame.pict_type == AV_PICTURE_TYPE_I) { - avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt); - if(gotFrame) - { - AVFrame& avFrame = frame.getAVFrame(); - - _gopStructure.push_back( - std::make_pair(av_get_picture_type_char(avFrame.pict_type), frame.getEncodedSize())); - _isInterlaced = avFrame.interlaced_frame; - _isTopFieldFirst = avFrame.top_field_first; - if(avFrame.pict_type == AV_PICTURE_TYPE_I) - { - if(positionOfFirstKeyFrame == -1) - positionOfFirstKeyFrame = count; - else - positionOfLastKeyFrame = count; - } - - _gopSize = ++count; - } + if(positionOfFirstKeyFrame == -1) + positionOfFirstKeyFrame = count; + else + positionOfLastKeyFrame = count; } - av_free_packet(&pkt); + + _gopSize = ++count; // If the first 2 key frames are found if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) @@ -555,11 +546,8 @@ void VideoProperties::analyseGopStructure(IProgress& progress) } } - // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) - avcodec_close(_codecContext); - // Returns at the beginning of the stream - const_cast(_fileProperties->getInputFile()).seekAtFrame(0, AVSEEK_FLAG_BYTE); + file.seekAtFrame(0, AVSEEK_FLAG_BYTE); // Check GOP size if(_gopSize <= 0) From ba6b39196c9dbec8c65bfecf929d32151185ecd9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 2 Nov 2016 18:20:28 +0100 Subject: [PATCH 07/10] VideoProperties: remove setting of skip_frame when analysing the first GOP --- src/AvTranscoder/properties/VideoProperties.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 28972429..32c5177c 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -507,10 +507,8 @@ void VideoProperties::analyseGopStructure(IProgress& progress) // Get the stream IInputStream& stream = file.getStream(_streamIndex); stream.activate(); - // Setup a decoder + // Create a decoder VideoDecoder decoder(static_cast(stream)); - // Discard no frame type when decode - _codecContext->skip_frame = AVDISCARD_NONE; size_t count = 0; int positionOfFirstKeyFrame = -1; From dfc2c98c11ccdd0dde928deb1a33d9996b87026e Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 3 Nov 2016 11:30:42 +0100 Subject: [PATCH 08/10] pyTest: fix file analysis of raw format (eAnalyseLevelFirstGop) --- test/pyTest/testProperties.py | 25 +++++++++++++------------ test/pyTest/testTranscoderRewrap.py | 2 ++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/test/pyTest/testProperties.py b/test/pyTest/testProperties.py index 3e29c8b5..91c77584 100644 --- a/test/pyTest/testProperties.py +++ b/test/pyTest/testProperties.py @@ -114,25 +114,26 @@ def testCheckRawVideoProperties(): inputFile = av.InputFile(inputFileName) properties = inputFile.getProperties() + # Check format assert_true(properties.isRawFormat()) assert_equals(properties.getNbStreams(), 1) assert_equals(properties.getNbVideoStreams(), 1) assert_equals(properties.getDuration(), 0) # file duration is unknown assert_equals(properties.getBitRate(), 0) # file bitrate is unknown + assert_equals(properties.getFileSize(), 256293L) - expectedFileSize = 256293L - assert_equals(properties.getFileSize(), expectedFileSize) - - expectedBitRate = 177200L - expectedNbFrames = 200 - expectedDuration = 8 - expectedFps = 25 - + # Check video stream when analyse the header + videoStream = properties.getVideoProperties()[0] + assert_equals(videoStream.getFps(), 25) + assert_equals(videoStream.getNbFrames(), 0) # stream nbFrames is unknown + assert_equals(videoStream.getDuration(), 0) # stream duration is unknown + assert_equals(videoStream.getBitRate(), 0) # stream bitrate is unknown + # Check video stream when analyse the first GOP + inputFile.analyse(av.NoDisplayProgress(), av.eAnalyseLevelFirstGop) videoStream = properties.getVideoProperties()[0] - assert_equals(videoStream.getNbFrames(), expectedNbFrames) - assert_equals(videoStream.getDuration(), expectedDuration) - assert_equals(videoStream.getBitRate(), expectedBitRate) - assert_equals(videoStream.getFps(), expectedFps) + assert_equals(videoStream.getNbFrames(), 200) + assert_equals(videoStream.getDuration(), 8) + assert_equals(videoStream.getBitRate(), 177200L) def testCheckAudioProperties(): diff --git a/test/pyTest/testTranscoderRewrap.py b/test/pyTest/testTranscoderRewrap.py index cd4ae14a..aee5c50e 100644 --- a/test/pyTest/testTranscoderRewrap.py +++ b/test/pyTest/testTranscoderRewrap.py @@ -164,6 +164,7 @@ def testRewrapRawVideoStream(): # get src file of wrap inputFileName = os.environ['AVTRANSCODER_TEST_VIDEO_RAW_FILE'] src_inputFile = av.InputFile(inputFileName) + src_inputFile.analyse(av.NoDisplayProgress(), av.eAnalyseLevelFirstGop) src_properties = src_inputFile.getProperties() src_videoStream = src_properties.getVideoProperties()[0] @@ -180,6 +181,7 @@ def testRewrapRawVideoStream(): # get dst file of wrap dst_inputFile = av.InputFile(outputFileName) + dst_inputFile.analyse(av.NoDisplayProgress(), av.eAnalyseLevelFirstGop) dst_properties = dst_inputFile.getProperties() dst_videoStream = dst_properties.getVideoProperties()[0] From 462b50df099b703483ac4e12def2ee264cad8d9a Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 3 Nov 2016 14:04:30 +0100 Subject: [PATCH 09/10] VideoProperties: update log when bitRate is not available in the container --- src/AvTranscoder/properties/VideoProperties.cpp | 3 ++- src/AvTranscoder/properties/VideoProperties.hpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 32c5177c..6897765d 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -331,7 +331,8 @@ size_t VideoProperties::getBitRate() const if(_levelAnalysis == eAnalyseLevelHeader) { - LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown.") + LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown. " + "Need a deeper analysis: see eAnalyseLevelFirstGop.") return 0; } diff --git a/src/AvTranscoder/properties/VideoProperties.hpp b/src/AvTranscoder/properties/VideoProperties.hpp index ed9d59ec..a5a2c9a6 100644 --- a/src/AvTranscoder/properties/VideoProperties.hpp +++ b/src/AvTranscoder/properties/VideoProperties.hpp @@ -42,7 +42,9 @@ class AvExport VideoProperties : public StreamProperties /** * @return The video bitrate in bits/s. - * @warning If there is no such info available in the container, this data is estimated by decoding the first GOP. + * @note 0 if unknown. + * @warning If there is no such info available in the container, this data is estimated using the information of the first GOP. + * @see eAnalyseLevelFirstGop */ size_t getBitRate() const; size_t getMaxBitRate() const; From 2ccf4b6985493432520da22a4c8e8758a5c3d6d9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 3 Nov 2016 16:24:59 +0100 Subject: [PATCH 10/10] VideoProperties: fix memory leak when analyseGopStructure The data buffer of the VideoFrame will be allocated by the decoder. --- src/AvTranscoder/properties/VideoProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index cf28f7f0..9d8e2378 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -515,7 +515,7 @@ void VideoProperties::analyseGopStructure(IProgress& progress) size_t count = 0; int positionOfFirstKeyFrame = -1; int positionOfLastKeyFrame = -1; - VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelFormatName(getPixelProperties().getAVPixelFormat()))); + VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelFormatName(getPixelProperties().getAVPixelFormat())), false); while(decoder.decodeNextFrame(frame)) { AVFrame& avFrame = frame.getAVFrame();