From b4ac1916caa0e004187329289ebc48e584cb8334 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 14:08:39 +0200 Subject: [PATCH 01/21] VideoProperties: refactored getProfileName method Use VideoProperties::getProfile() method. --- 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 0dd86102..30a80f86 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -47,7 +47,7 @@ std::string VideoProperties::getProfileName() const throw std::runtime_error("unknown codec profile"); const char* profile = NULL; - if((profile = av_get_profile_name(_codec, _codecContext->profile)) == NULL) + if((profile = av_get_profile_name(_codec, getProfile())) == NULL) throw std::runtime_error("unknown codec profile"); return std::string(profile); From f60840e8926a0620ab5de1f7fefa1b60f013565f Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 9 May 2016 18:28:21 +0200 Subject: [PATCH 02/21] VideoProperties: removed check of profile when getProfileName This check is already done by av_get_profile_name method. --- src/AvTranscoder/properties/VideoProperties.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 30a80f86..3102b33f 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -43,9 +43,6 @@ std::string VideoProperties::getProfileName() const if(_codec->capabilities & CODEC_CAP_TRUNCATED) _codecContext->flags |= CODEC_FLAG_TRUNCATED; - if(_codecContext->profile == -99) - throw std::runtime_error("unknown codec profile"); - const char* profile = NULL; if((profile = av_get_profile_name(_codec, getProfile())) == NULL) throw std::runtime_error("unknown codec profile"); From 07a71ae723232f96a7bcd4f972aeba9db32be9f8 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 14:08:06 +0200 Subject: [PATCH 03/21] VideoProperties: refactored the methods that use AVFrame * Use Frame class instead (allocation/free is managed by the class). --- .../properties/VideoProperties.cpp | 46 ++++--------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 3102b33f..7a1fca79 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -1,5 +1,6 @@ #include "VideoProperties.hpp" +#include #include #include @@ -333,11 +334,7 @@ size_t VideoProperties::getBitRate() const // discard no frame type when decode _codecContext->skip_frame = AVDISCARD_NONE; -#if LIBAVCODEC_VERSION_MAJOR > 54 - AVFrame* frame = av_frame_alloc(); -#else - AVFrame* frame = avcodec_alloc_frame(); -#endif + Frame frame; AVPacket pkt; av_init_packet(&pkt); avcodec_open2(_codecContext, _codec, NULL); @@ -350,11 +347,11 @@ size_t VideoProperties::getBitRate() const { if(pkt.stream_index == (int)_streamIndex) { - avcodec_decode_video2(_codecContext, frame, &gotFrame, &pkt); + avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt); if(gotFrame) { #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 7, 100) - gopFramesSize += av_frame_get_pkt_size(frame); + gopFramesSize += av_frame_get_pkt_size(&frame.getAVFrame()); #else gopFramesSize += pkt.size; #endif @@ -365,13 +362,6 @@ size_t VideoProperties::getBitRate() const if(_codecContext->gop_size == count) break; } -#if LIBAVCODEC_VERSION_MAJOR > 54 - av_frame_free(&frame); -#elif LIBAVCODEC_VERSION_MAJOR > 53 - avcodec_free_frame(&frame); -#else - av_free(frame); -#endif int bitsPerByte = 8; return (gopFramesSize / _codecContext->gop_size) * bitsPerByte * getFps(); @@ -490,16 +480,10 @@ void VideoProperties::analyseGopStructure(IProgress& progress) AVPacket pkt; av_init_packet(&pkt); -// Allocate frame -#if LIBAVCODEC_VERSION_MAJOR > 54 - AVFrame* frame = av_frame_alloc(); -#else - AVFrame* frame = avcodec_alloc_frame(); -#endif - // Initialize the AVCodecContext to use the given AVCodec avcodec_open2(_codecContext, _codec, NULL); + Frame frame; int count = 0; int gotFrame = 0; bool stopAnalyse = false; @@ -508,13 +492,14 @@ void VideoProperties::analyseGopStructure(IProgress& progress) { if(pkt.stream_index == (int)_streamIndex) { - avcodec_decode_video2(_codecContext, frame, &gotFrame, &pkt); + 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(frame->pict_type), frame->key_frame)); - _isInterlaced = frame->interlaced_frame; - _isTopFieldFirst = frame->top_field_first; + std::make_pair(av_get_picture_type_char(avFrame.pict_type), avFrame.key_frame)); + _isInterlaced = avFrame.interlaced_frame; + _isTopFieldFirst = avFrame.top_field_first; ++count; if(progress.progress(count, _codecContext->gop_size) == eJobStatusCancel) stopAnalyse = true; @@ -534,17 +519,6 @@ 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); - -// Free frame -#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 } } } From 16b2e56cf4f9d2f8875df8d83b614c4cfea63960 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 14:04:44 +0200 Subject: [PATCH 04/21] Frame: added getEncodedSize method --- src/AvTranscoder/data/decoded/Frame.cpp | 5 +++++ src/AvTranscoder/data/decoded/Frame.hpp | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/AvTranscoder/data/decoded/Frame.cpp b/src/AvTranscoder/data/decoded/Frame.cpp index 68491b24..655776c9 100644 --- a/src/AvTranscoder/data/decoded/Frame.cpp +++ b/src/AvTranscoder/data/decoded/Frame.cpp @@ -40,6 +40,11 @@ Frame::~Frame() } } +int Frame::getEncodedSize() const +{ + return av_frame_get_pkt_size(_frame); +} + void Frame::copyData(const Frame& frameToRef) { const int ret = av_frame_copy(_frame, &frameToRef.getAVFrame()); diff --git a/src/AvTranscoder/data/decoded/Frame.hpp b/src/AvTranscoder/data/decoded/Frame.hpp index aa3e45b1..482c92ff 100644 --- a/src/AvTranscoder/data/decoded/Frame.hpp +++ b/src/AvTranscoder/data/decoded/Frame.hpp @@ -43,6 +43,12 @@ class AvExport Frame */ int* getLineSize() const { return _frame->linesize; } + /** + * @return Size of the corresponding packet containing the compressed frame (in bytes) + * @warning returns a negative value if the size is unknown + */ + int getEncodedSize() const; + /** * @brief Copy the data of the given Frame. * @note This function does not allocate anything: the current frame must be already initialized and From 718b855cb56694c8fba842b1ce556932cef6fe01 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 14:09:28 +0200 Subject: [PATCH 05/21] VideoProperties: refactored getBitRate method Use Frame::getEncodedSize() method. --- 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 7a1fca79..1f801ac1 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -351,7 +351,7 @@ size_t VideoProperties::getBitRate() const if(gotFrame) { #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 7, 100) - gopFramesSize += av_frame_get_pkt_size(&frame.getAVFrame()); + gopFramesSize += frame.getEncodedSize(); #else gopFramesSize += pkt.size; #endif From a3c82098171d5e9cefaf4156f2b7733b5213328c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 14:45:24 +0200 Subject: [PATCH 06/21] VideoProperties: refactored the methods that use gop_size * Use VideoProperties::getGopSize() instead. * Add doc to this method. --- src/AvTranscoder/properties/VideoProperties.cpp | 12 ++++++------ src/AvTranscoder/properties/VideoProperties.hpp | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 1f801ac1..e2d119d1 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -340,7 +340,7 @@ size_t VideoProperties::getBitRate() const avcodec_open2(_codecContext, _codec, NULL); int gotFrame = 0; - int count = 0; + size_t count = 0; int gopFramesSize = 0; while(!av_read_frame(const_cast(_formatContext), &pkt)) @@ -359,12 +359,12 @@ size_t VideoProperties::getBitRate() const } } av_free_packet(&pkt); - if(_codecContext->gop_size == count) + if(getGopSize() == count) break; } int bitsPerByte = 8; - return (gopFramesSize / _codecContext->gop_size) * bitsPerByte * getFps(); + return (gopFramesSize / getGopSize()) * bitsPerByte * getFps(); } size_t VideoProperties::getMaxBitRate() const @@ -484,7 +484,7 @@ void VideoProperties::analyseGopStructure(IProgress& progress) avcodec_open2(_codecContext, _codec, NULL); Frame frame; - int count = 0; + size_t count = 0; int gotFrame = 0; bool stopAnalyse = false; @@ -501,14 +501,14 @@ void VideoProperties::analyseGopStructure(IProgress& progress) _isInterlaced = avFrame.interlaced_frame; _isTopFieldFirst = avFrame.top_field_first; ++count; - if(progress.progress(count, _codecContext->gop_size) == eJobStatusCancel) + if(progress.progress(count, getGopSize()) == eJobStatusCancel) stopAnalyse = true; } } av_free_packet(&pkt); - if(_codecContext->gop_size == count) + if(getGopSize() == count) { stopAnalyse = true; } diff --git a/src/AvTranscoder/properties/VideoProperties.hpp b/src/AvTranscoder/properties/VideoProperties.hpp index bd1cc301..163eea76 100644 --- a/src/AvTranscoder/properties/VideoProperties.hpp +++ b/src/AvTranscoder/properties/VideoProperties.hpp @@ -47,7 +47,13 @@ class AvExport VideoProperties : public StreamProperties size_t getTicksPerFrame() const; size_t getWidth() const; size_t getHeight() const; + + /** + * @return the distance between two nearest I frame + * @note it returns 0 for intra_only + */ size_t getGopSize() const; + size_t getDtgActiveFormat() const; size_t getReferencesFrames() const; int getProfile() const; From 65712aaa6b1e25e84bc41e128d18d328c5cf1e9c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 15:35:07 +0200 Subject: [PATCH 07/21] VideoProperties: added _levelAnalysis private attribute * To get the level of analysis asked inside member methods. * Will be used in the next commit. --- src/AvTranscoder/properties/VideoProperties.cpp | 1 + src/AvTranscoder/properties/VideoProperties.hpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index e2d119d1..4aca154a 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -20,6 +20,7 @@ namespace avtranscoder VideoProperties::VideoProperties(const FormatContext& formatContext, const size_t index, IProgress& progress, const EAnalyseLevel level) : StreamProperties(formatContext, index) + , _levelAnalysis(level) , _pixelProperties() , _isInterlaced(false) , _isTopFieldFirst(false) diff --git a/src/AvTranscoder/properties/VideoProperties.hpp b/src/AvTranscoder/properties/VideoProperties.hpp index 163eea76..919f275b 100644 --- a/src/AvTranscoder/properties/VideoProperties.hpp +++ b/src/AvTranscoder/properties/VideoProperties.hpp @@ -110,6 +110,11 @@ class AvExport VideoProperties : public StreamProperties #endif private: + /** + * @brief Level of analysis asked. + */ + EAnalyseLevel _levelAnalysis; + PixelProperties _pixelProperties; //@{ // Can acces these data when analyse first gop From a86ec98f2bb2429bfbaabbe8e98f8164caca756d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 15:42:51 +0200 Subject: [PATCH 08/21] VideoProperties: fixed getGopSize method * AVCodecContext->gop_size is unused when decode according to the ffmpeg documentation: https://ffmpeg.org/doxygen/2.8/structAVCodecContext.html#a9b6b3f1fcbdcc2ad9f4dbb4370496e38 * So compute this info when analyseGopStructure, and store it inside the VideoProperties class. * Because the gop size could be used inside getBitRate() method, throw a runtime exception before using it. --- .../properties/VideoProperties.cpp | 40 +++++++++++-------- .../properties/VideoProperties.hpp | 12 +++--- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 4aca154a..67156882 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -24,6 +24,7 @@ VideoProperties::VideoProperties(const FormatContext& formatContext, const size_ , _pixelProperties() , _isInterlaced(false) , _isTopFieldFirst(false) + , _gopSize(0) , _gopStructure() , _firstGopTimeCode(-1) { @@ -332,6 +333,10 @@ size_t VideoProperties::getBitRate() const if(!_codecContext->width || !_codecContext->height) throw std::runtime_error("cannot compute bit rate: invalid frame size"); + // Needed to get the gop size + if(_levelAnalysis < eAnalyseLevelFirstGop) + throw std::runtime_error("cannot compute bit rate: need to get info from the first gop (see eAnalyseLevelFirstGop)"); + // discard no frame type when decode _codecContext->skip_frame = AVDISCARD_NONE; @@ -413,13 +418,6 @@ size_t VideoProperties::getHeight() const 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) @@ -487,7 +485,8 @@ void VideoProperties::analyseGopStructure(IProgress& progress) Frame frame; size_t count = 0; int gotFrame = 0; - bool stopAnalyse = false; + int positionOfFirstKeyFrame = -1; + int positionOfLastKeyFrame = -1; while(!av_read_frame(const_cast(_formatContext), &pkt)) { @@ -497,25 +496,34 @@ void VideoProperties::analyseGopStructure(IProgress& progress) if(gotFrame) { AVFrame& avFrame = frame.getAVFrame(); + _gopStructure.push_back( std::make_pair(av_get_picture_type_char(avFrame.pict_type), avFrame.key_frame)); _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; + } + ++count; - if(progress.progress(count, getGopSize()) == eJobStatusCancel) - stopAnalyse = true; } } - av_free_packet(&pkt); - if(getGopSize() == count) + // If the first 2 key frames are found + if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1) { - stopAnalyse = true; - } - - if(stopAnalyse) + // 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; + } } // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself) diff --git a/src/AvTranscoder/properties/VideoProperties.hpp b/src/AvTranscoder/properties/VideoProperties.hpp index 919f275b..c89ee2ca 100644 --- a/src/AvTranscoder/properties/VideoProperties.hpp +++ b/src/AvTranscoder/properties/VideoProperties.hpp @@ -47,13 +47,6 @@ class AvExport VideoProperties : public StreamProperties size_t getTicksPerFrame() const; size_t getWidth() const; size_t getHeight() const; - - /** - * @return the distance between two nearest I frame - * @note it returns 0 for intra_only - */ - size_t getGopSize() const; - size_t getDtgActiveFormat() const; size_t getReferencesFrames() const; int getProfile() const; @@ -77,6 +70,10 @@ class AvExport VideoProperties : public StreamProperties // @see analyseGopStructure bool isInterlaced() const { return _isInterlaced; } bool isTopFieldFirst() const { return _isTopFieldFirst; } + /** + * @return the distance between two nearest I frame + */ + size_t getGopSize() const { return _gopSize; } std::vector > getGopStructure() const { return _gopStructure; } //@} @@ -120,6 +117,7 @@ class AvExport VideoProperties : public StreamProperties // Can acces these data when analyse first gop bool _isInterlaced; bool _isTopFieldFirst; + size_t _gopSize; std::vector > _gopStructure; //@} From 0ba9d01acdfa1779d99a99d5da5bac1d2abc930e Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 15:44:17 +0200 Subject: [PATCH 09/21] VideoProperties: added doc to _pixelProperties attribute --- src/AvTranscoder/properties/VideoProperties.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AvTranscoder/properties/VideoProperties.hpp b/src/AvTranscoder/properties/VideoProperties.hpp index c89ee2ca..d995a565 100644 --- a/src/AvTranscoder/properties/VideoProperties.hpp +++ b/src/AvTranscoder/properties/VideoProperties.hpp @@ -112,7 +112,11 @@ class AvExport VideoProperties : public StreamProperties */ EAnalyseLevel _levelAnalysis; + /** + * @brief All the pixel properties contained in this stream. + */ PixelProperties _pixelProperties; + //@{ // Can acces these data when analyse first gop bool _isInterlaced; From 8ae3d4dbcff38d0e203519f19ee70e346a603af0 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 15:57:51 +0200 Subject: [PATCH 10/21] FormatContext: added const to local variables of methods --- src/AvTranscoder/file/FormatContext.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/AvTranscoder/file/FormatContext.cpp b/src/AvTranscoder/file/FormatContext.cpp index f15fa69d..cab0b3d7 100644 --- a/src/AvTranscoder/file/FormatContext.cpp +++ b/src/AvTranscoder/file/FormatContext.cpp @@ -53,7 +53,7 @@ FormatContext::~FormatContext() void FormatContext::findStreamInfo(AVDictionary** options) { - int err = avformat_find_stream_info(_avFormatContext, options); + const int err = avformat_find_stream_info(_avFormatContext, options); if(err < 0) { throw std::ios_base::failure("Unable to find stream informations: " + getDescriptionFromErrorCode(err)); @@ -65,7 +65,7 @@ void FormatContext::openRessource(const std::string& url, int flags) if((_avFormatContext->flags & AVFMT_NOFILE) == AVFMT_NOFILE) return; - int err = avio_open2(&_avFormatContext->pb, url.c_str(), flags, NULL, NULL); + const int err = avio_open2(&_avFormatContext->pb, url.c_str(), flags, NULL, NULL); if(err < 0) { throw std::ios_base::failure("Error when opening output format: " + getDescriptionFromErrorCode(err)); @@ -77,7 +77,7 @@ void FormatContext::closeRessource() if((_avFormatContext->flags & AVFMT_NOFILE) == AVFMT_NOFILE) return; - int err = avio_close(_avFormatContext->pb); + const int err = avio_close(_avFormatContext->pb); if(err < 0) { throw std::ios_base::failure("Error when close output format: " + getDescriptionFromErrorCode(err)); @@ -86,7 +86,7 @@ void FormatContext::closeRessource() void FormatContext::writeHeader(AVDictionary** options) { - int ret = avformat_write_header(_avFormatContext, options); + const int ret = avformat_write_header(_avFormatContext, options); if(ret != 0) { throw std::runtime_error("Could not write header: " + getDescriptionFromErrorCode(ret)); @@ -115,7 +115,7 @@ void FormatContext::writeFrame(AVPacket& packet, bool interleaved) void FormatContext::writeTrailer() { - int ret = av_write_trailer(_avFormatContext); + const int ret = av_write_trailer(_avFormatContext); if(ret != 0) { throw std::runtime_error("Could not write trailer: " + getDescriptionFromErrorCode(ret)); @@ -124,7 +124,7 @@ void FormatContext::writeTrailer() void FormatContext::addMetaData(const std::string& key, const std::string& value) { - int ret = av_dict_set(&_avFormatContext->metadata, key.c_str(), value.c_str(), 0); + const int ret = av_dict_set(&_avFormatContext->metadata, key.c_str(), value.c_str(), 0); if(ret < 0) { LOG_ERROR(getDescriptionFromErrorCode(ret)) @@ -144,8 +144,8 @@ AVStream& FormatContext::addAVStream(const AVCodec& avCodec) bool FormatContext::seek(const uint64_t position, const int flag) { - LOG_INFO("Seek in '" << _avFormatContext->filename << "' at " << position << " (in AV_TIME_BASE units)") - int err = av_seek_frame(_avFormatContext, -1, position, flag); + LOG_INFO("Seek in '" << _avFormatContext->filename << "' at " << position << " with flag '"<< flag << "'") + const int err = av_seek_frame(_avFormatContext, -1, position, flag); if(err < 0) { LOG_ERROR("Error when seek at " << position << " (in AV_TIME_BASE units) in file") From 25500d23509f5036e61644130a83a7018e0ff470 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 16:25:26 +0200 Subject: [PATCH 11/21] pyTest: updated testInputFileAnalyseFirstGop --- test/pyTest/testInputFile.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/pyTest/testInputFile.py b/test/pyTest/testInputFile.py index d9b4f247..237ce06d 100644 --- a/test/pyTest/testInputFile.py +++ b/test/pyTest/testInputFile.py @@ -31,6 +31,7 @@ def testInputFileAnalyseFirstGop(): videoProperties = inputFile.getProperties().getVideoProperties()[0] assert_equals(videoProperties.isInterlaced(), False) assert_equals(videoProperties.isTopFieldFirst(), False) + assert_equals(videoProperties.getGopSize(), 0) assert_equals(videoProperties.getGopStructure(), ()) # Analyse first GOP @@ -39,4 +40,5 @@ def testInputFileAnalyseFirstGop(): # Check properties after GOP analysis videoProperties = inputFile.getProperties().getVideoProperties()[0] + assert_greater(videoProperties.getGopSize(), 0) assert_not_equals(videoProperties.getGopStructure(), ()) From 46f983a6d8e49f86baf99c75e87a4025d6cf413d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 16:46:13 +0200 Subject: [PATCH 12/21] VideoProperties: updated value returned by getGopStructure * Before: picture type, is key frame * After: picture type, encoded frame size in bytes * Note: "is key frame" info can be found using the picture type (I frame). * Updated SWIG interface. --- src/AvTranscoder/properties/VideoProperties.cpp | 2 +- src/AvTranscoder/properties/VideoProperties.hpp | 4 ++-- src/AvTranscoder/properties/properties.i | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 67156882..633e0aad 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -498,7 +498,7 @@ void VideoProperties::analyseGopStructure(IProgress& progress) AVFrame& avFrame = frame.getAVFrame(); _gopStructure.push_back( - std::make_pair(av_get_picture_type_char(avFrame.pict_type), avFrame.key_frame)); + 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) diff --git a/src/AvTranscoder/properties/VideoProperties.hpp b/src/AvTranscoder/properties/VideoProperties.hpp index d995a565..66ef46e7 100644 --- a/src/AvTranscoder/properties/VideoProperties.hpp +++ b/src/AvTranscoder/properties/VideoProperties.hpp @@ -74,7 +74,7 @@ class AvExport VideoProperties : public StreamProperties * @return the distance between two nearest I frame */ size_t getGopSize() const { return _gopSize; } - std::vector > getGopStructure() const { return _gopStructure; } + std::vector > getGopStructure() const { return _gopStructure; } //@} #ifndef SWIG @@ -122,7 +122,7 @@ class AvExport VideoProperties : public StreamProperties bool _isInterlaced; bool _isTopFieldFirst; size_t _gopSize; - std::vector > _gopStructure; + std::vector > _gopStructure; ///< picture type, encoded frame size in bytes //@} /** diff --git a/src/AvTranscoder/properties/properties.i b/src/AvTranscoder/properties/properties.i index 00cbaeaa..0bbb720f 100644 --- a/src/AvTranscoder/properties/properties.i +++ b/src/AvTranscoder/properties/properties.i @@ -40,8 +40,8 @@ namespace std { %template(PropertyPair) pair< string, string >; %template(PropertyVector) vector< pair< string, string > >; -%template(GopPair) pair< char, bool >; -%template(GopVector) vector< pair< char, bool > >; +%template(GopPair) pair< char, int >; +%template(GopVector) vector< pair< char, int > >; %template(ChannelVector) vector< avtranscoder::Channel >; } From c0948f13f71c34663c3f428a5238f4d545d07600 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 16:48:35 +0200 Subject: [PATCH 13/21] VideoProperties: get encoded frame size of GOP when fillVector of properties --- src/AvTranscoder/properties/VideoProperties.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index 633e0aad..1f1df415 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -564,13 +564,16 @@ PropertyVector& VideoProperties::fillVector(PropertyVector& data) const addProperty(data, "minBitRate", &VideoProperties::getMinBitRate); addProperty(data, "gopSize", &VideoProperties::getGopSize); - std::string gop; + std::stringstream gop; for(size_t frameIndex = 0; frameIndex < _gopStructure.size(); ++frameIndex) { - gop += _gopStructure.at(frameIndex).first; - gop += " "; + gop << _gopStructure.at(frameIndex).first; + gop << "("; + gop << _gopStructure.at(frameIndex).second;; + gop << ")"; + gop << " "; } - detail::add(data, "gop", gop); + detail::add(data, "gop", gop.str()); // detail::add( data, "isClosedGop", isClosedGop() ); addProperty(data, "hasBFrames", &VideoProperties::hasBFrames); From 37c238551a5e6aea081409c91c1e11fbbf95ff46 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 3 May 2016 17:00:03 +0200 Subject: [PATCH 14/21] pyTest: updated testInputFileAnalyseFirstGop --- test/pyTest/testInputFile.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/pyTest/testInputFile.py b/test/pyTest/testInputFile.py index 237ce06d..3fdadc60 100644 --- a/test/pyTest/testInputFile.py +++ b/test/pyTest/testInputFile.py @@ -42,3 +42,8 @@ def testInputFileAnalyseFirstGop(): videoProperties = inputFile.getProperties().getVideoProperties()[0] assert_greater(videoProperties.getGopSize(), 0) assert_not_equals(videoProperties.getGopStructure(), ()) + for image in videoProperties.getGopStructure(): + pictureType = image[0] + encodedPictureSize = image[1] + assert_in(pictureType, ['I', 'P', 'B']) + assert_greater(encodedPictureSize, 0) From 7a42b23690494239e0df04cdba5810a063ac13bb Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 9 May 2016 18:29:39 +0200 Subject: [PATCH 15/21] VideoProperties: used attribute instead of parameter in constructor To improve readability. --- 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 1f1df415..dbf8c99b 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -34,7 +34,7 @@ VideoProperties::VideoProperties(const FormatContext& formatContext, const size_ _firstGopTimeCode = _codecContext->timecode_frame_start; } - if(level == eAnalyseLevelFirstGop) + if(_levelAnalysis == eAnalyseLevelFirstGop) analyseGopStructure(progress); } From 94ad0ae15b06c29dc3873459905a8d9c5e924dc0 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 11 May 2016 10:27:48 +0200 Subject: [PATCH 16/21] PixelProperties: fixed colorComponents value if not found All properties have the same value if not found. --- src/AvTranscoder/properties/PixelProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/properties/PixelProperties.cpp b/src/AvTranscoder/properties/PixelProperties.cpp index 2f104421..bef52cd4 100644 --- a/src/AvTranscoder/properties/PixelProperties.cpp +++ b/src/AvTranscoder/properties/PixelProperties.cpp @@ -274,7 +274,7 @@ PropertyVector& PixelProperties::fillVector(PropertyVector& data) const } catch(const std::exception& e) { - detail::add(data, "colorComponents", e.what()); + detail::add(data, "colorComponents", detail::propertyValueIfError); } try From 85290f2bbdcec87ce56126d7c3168aff75ad2a46 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 12 May 2016 14:32:01 +0200 Subject: [PATCH 17/21] VideoProperties: fixed value of properties available when decode first gop All properties have the same value if not found. --- .../properties/VideoProperties.cpp | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/AvTranscoder/properties/VideoProperties.cpp b/src/AvTranscoder/properties/VideoProperties.cpp index dbf8c99b..e2e56c1e 100644 --- a/src/AvTranscoder/properties/VideoProperties.cpp +++ b/src/AvTranscoder/properties/VideoProperties.cpp @@ -553,8 +553,6 @@ PropertyVector& VideoProperties::fillVector(PropertyVector& data) const addProperty(data, "colorRange", &VideoProperties::getColorRange); addProperty(data, "colorPrimaries", &VideoProperties::getColorPrimaries); addProperty(data, "chromaSampleLocation", &VideoProperties::getChromaSampleLocation); - addProperty(data, "interlaced ", &VideoProperties::isInterlaced); - addProperty(data, "topFieldFirst", &VideoProperties::isTopFieldFirst); addProperty(data, "fieldOrder", &VideoProperties::getFieldOrder); addProperty(data, "fps", &VideoProperties::getFps); addProperty(data, "nbFrame", &VideoProperties::getNbFrames); @@ -562,22 +560,36 @@ PropertyVector& VideoProperties::fillVector(PropertyVector& data) const addProperty(data, "bitRate", &VideoProperties::getBitRate); addProperty(data, "maxBitRate", &VideoProperties::getMaxBitRate); addProperty(data, "minBitRate", &VideoProperties::getMinBitRate); - addProperty(data, "gopSize", &VideoProperties::getGopSize); + addProperty(data, "hasBFrames", &VideoProperties::hasBFrames); + addProperty(data, "referencesFrames", &VideoProperties::getReferencesFrames); - std::stringstream gop; - for(size_t frameIndex = 0; frameIndex < _gopStructure.size(); ++frameIndex) + // Add properties available when decode first gop + if(_levelAnalysis < eAnalyseLevelFirstGop) { - gop << _gopStructure.at(frameIndex).first; - gop << "("; - gop << _gopStructure.at(frameIndex).second;; - gop << ")"; - gop << " "; + detail::add(data, "gopSize", detail::propertyValueIfError); + detail::add(data, "gop", detail::propertyValueIfError); + detail::add(data, "interlaced", detail::propertyValueIfError); + detail::add(data, "topFieldFirst", detail::propertyValueIfError); } - detail::add(data, "gop", gop.str()); - // detail::add( data, "isClosedGop", isClosedGop() ); + else + { + addProperty(data, "gopSize", &VideoProperties::getGopSize); - addProperty(data, "hasBFrames", &VideoProperties::hasBFrames); - addProperty(data, "referencesFrames", &VideoProperties::getReferencesFrames); + std::stringstream gop; + for(size_t frameIndex = 0; frameIndex < _gopStructure.size(); ++frameIndex) + { + gop << _gopStructure.at(frameIndex).first; + gop << "("; + gop << _gopStructure.at(frameIndex).second;; + gop << ")"; + gop << " "; + } + detail::add(data, "gop", gop.str()); + // detail::add( data, "isClosedGop", isClosedGop() ); + + addProperty(data, "interlaced ", &VideoProperties::isInterlaced); + addProperty(data, "topFieldFirst", &VideoProperties::isTopFieldFirst); + } // Add properties of the pixel PropertyVector pixelProperties; From f6e2fec9a221159b9c597fbcc5cab173acf98c5c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 12 May 2016 16:21:56 +0200 Subject: [PATCH 18/21] FileProperties: added mimeType to the list of properties when fillVector --- src/AvTranscoder/properties/FileProperties.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AvTranscoder/properties/FileProperties.cpp b/src/AvTranscoder/properties/FileProperties.cpp index c18083fe..32aba7a5 100644 --- a/src/AvTranscoder/properties/FileProperties.cpp +++ b/src/AvTranscoder/properties/FileProperties.cpp @@ -235,6 +235,7 @@ PropertyVector& FileProperties::fillVector(PropertyVector& data) const addProperty(data, "filename", &FileProperties::getFilename); addProperty(data, "formatName", &FileProperties::getFormatName); addProperty(data, "formatLongName", &FileProperties::getFormatLongName); + addProperty(data, "mimeType", &FileProperties::getFormatMimeType); addProperty(data, "startTime", &FileProperties::getStartTime); addProperty(data, "duration", &FileProperties::getDuration); From 02c617056eb3d5cf5fa95c40cde4cab0c89bcbac Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 12 May 2016 16:25:26 +0200 Subject: [PATCH 19/21] FileProperties: throw runtime error if mime type is not found Like other getter to properties. --- src/AvTranscoder/properties/FileProperties.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/AvTranscoder/properties/FileProperties.cpp b/src/AvTranscoder/properties/FileProperties.cpp index 32aba7a5..e7ab4fd8 100644 --- a/src/AvTranscoder/properties/FileProperties.cpp +++ b/src/AvTranscoder/properties/FileProperties.cpp @@ -148,15 +148,10 @@ std::string FileProperties::getFormatLongName() const std::string FileProperties::getFormatMimeType() const { #if LIBAVFORMAT_VERSION_MAJOR <= 55 - LOG_WARN("Cannot get mime type format of '" << getFilename() - << "' because your libavformat library has a major version <= 55.") - return "not available"; + throw std::runtime_error("cannot get mime type format: libavformat library has a major version <= 55."); #else if(_avFormatContext->iformat->mime_type == NULL) - { - LOG_WARN("Unknown demuxer format mime type of '" << getFilename() << "'.") - return ""; - } + throw std::runtime_error("Unknown demuxer format mime type"); return std::string(_avFormatContext->iformat->mime_type); #endif } From 1dea4504710d9b2a86b5fe2a53ce61ce0d92130c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Fri, 13 May 2016 10:22:20 +0200 Subject: [PATCH 20/21] pyTest: fixed dnx transcode tests Need to analyse first GOP to compute bitrate and get gop size of output. --- test/pyTest/testTranscoderTranscodeVideo.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/pyTest/testTranscoderTranscodeVideo.py b/test/pyTest/testTranscoderTranscodeVideo.py index 9bdcfb63..5a6b166f 100644 --- a/test/pyTest/testTranscoderTranscodeVideo.py +++ b/test/pyTest/testTranscoderTranscodeVideo.py @@ -35,6 +35,7 @@ def testTranscodeDnxhd120(): # get dst file of transcode dst_inputFile = av.InputFile( outputFileName ) + dst_inputFile.analyse(progress, av.eAnalyseLevelFirstGop) dst_properties = dst_inputFile.getProperties() dst_videoStream = dst_properties.getVideoProperties()[0] @@ -43,7 +44,7 @@ def testTranscodeDnxhd120(): deltaBitRate = expectedBitRate * 0.05 assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p", dst_videoStream.getPixelProperties().getPixelName() ) - # assert_equals( 1, dst_videoStream.getGopSize() ) # 1 != 12L + assert_equals( 1, dst_videoStream.getGopSize() ) def testTranscodeDnxhd185(): """ @@ -70,6 +71,7 @@ def testTranscodeDnxhd185(): # get dst file of transcode dst_inputFile = av.InputFile( outputFileName ) + dst_inputFile.analyse(progress, av.eAnalyseLevelFirstGop) dst_properties = dst_inputFile.getProperties() dst_videoStream = dst_properties.getVideoProperties()[0] @@ -78,7 +80,7 @@ def testTranscodeDnxhd185(): deltaBitRate = expectedBitRate * 0.05 assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p", dst_videoStream.getPixelProperties().getPixelName() ) - # assert_equals( 1, dst_videoStream.getGopSize() ) # 1 != 12L + assert_equals( 1, dst_videoStream.getGopSize() ) def testTranscodeDnxhd185x(): """ @@ -105,6 +107,7 @@ def testTranscodeDnxhd185x(): # get dst file of transcode dst_inputFile = av.InputFile( outputFileName ) + dst_inputFile.analyse(progress, av.eAnalyseLevelFirstGop) dst_properties = dst_inputFile.getProperties() dst_videoStream = dst_properties.getVideoProperties()[0] @@ -113,7 +116,7 @@ def testTranscodeDnxhd185x(): deltaBitRate = expectedBitRate * 0.05 assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p10le", dst_videoStream.getPixelProperties().getPixelName() ) - # assert_equals( 1, dst_videoStream.getGopSize() ) # 1 != 12L + assert_equals( 1, dst_videoStream.getGopSize() ) def testTranscodeYUV420(): """ From 4d04f1002c49c2a7a310d1e4fca96f6949a34071 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Fri, 13 May 2016 10:25:36 +0200 Subject: [PATCH 21/21] pyTest: check width/height when transcode to dnxhd --- test/pyTest/testTranscoderTranscodeVideo.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/pyTest/testTranscoderTranscodeVideo.py b/test/pyTest/testTranscoderTranscodeVideo.py index 5a6b166f..8f486f94 100644 --- a/test/pyTest/testTranscoderTranscodeVideo.py +++ b/test/pyTest/testTranscoderTranscodeVideo.py @@ -44,6 +44,8 @@ def testTranscodeDnxhd120(): deltaBitRate = expectedBitRate * 0.05 assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p", dst_videoStream.getPixelProperties().getPixelName() ) + assert_equals( 1920, dst_videoStream.getWidth() ) + assert_equals( 1080, dst_videoStream.getHeight() ) assert_equals( 1, dst_videoStream.getGopSize() ) def testTranscodeDnxhd185(): @@ -80,7 +82,9 @@ def testTranscodeDnxhd185(): deltaBitRate = expectedBitRate * 0.05 assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p", dst_videoStream.getPixelProperties().getPixelName() ) - assert_equals( 1, dst_videoStream.getGopSize() ) + assert_equals( 1920, dst_videoStream.getWidth() ) + assert_equals( 1080, dst_videoStream.getHeight() ) + assert_equals( 1, dst_videoStream.getGopSize() ) def testTranscodeDnxhd185x(): """ @@ -116,6 +120,8 @@ def testTranscodeDnxhd185x(): deltaBitRate = expectedBitRate * 0.05 assert_almost_equals( expectedBitRate, dst_videoStream.getBitRate(), delta=deltaBitRate ) assert_equals( "yuv422p10le", dst_videoStream.getPixelProperties().getPixelName() ) + assert_equals( 1920, dst_videoStream.getWidth() ) + assert_equals( 1080, dst_videoStream.getHeight() ) assert_equals( 1, dst_videoStream.getGopSize() ) def testTranscodeYUV420():