Skip to content

Fix gop properties #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
May 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b4ac191
VideoProperties: refactored getProfileName method
May 3, 2016
f60840e
VideoProperties: removed check of profile when getProfileName
May 9, 2016
07a71ae
VideoProperties: refactored the methods that use AVFrame
May 3, 2016
16b2e56
Frame: added getEncodedSize method
May 3, 2016
718b855
VideoProperties: refactored getBitRate method
May 3, 2016
a3c8209
VideoProperties: refactored the methods that use gop_size
May 3, 2016
65712aa
VideoProperties: added _levelAnalysis private attribute
May 3, 2016
a86ec98
VideoProperties: fixed getGopSize method
May 3, 2016
0ba9d01
VideoProperties: added doc to _pixelProperties attribute
May 3, 2016
8ae3d4d
FormatContext: added const to local variables of methods
May 3, 2016
25500d2
pyTest: updated testInputFileAnalyseFirstGop
May 3, 2016
46f983a
VideoProperties: updated value returned by getGopStructure
May 3, 2016
c0948f1
VideoProperties: get encoded frame size of GOP when fillVector of pro…
May 3, 2016
37c2385
pyTest: updated testInputFileAnalyseFirstGop
May 3, 2016
7a42b23
VideoProperties: used attribute instead of parameter in constructor
May 9, 2016
94ad0ae
PixelProperties: fixed colorComponents value if not found
May 11, 2016
85290f2
VideoProperties: fixed value of properties available when decode firs…
May 12, 2016
f6e2fec
FileProperties: added mimeType to the list of properties when fillVector
May 12, 2016
02c6170
FileProperties: throw runtime error if mime type is not found
May 12, 2016
1dea450
pyTest: fixed dnx transcode tests
May 13, 2016
4d04f10
pyTest: check width/height when transcode to dnxhd
May 13, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/AvTranscoder/data/decoded/Frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
6 changes: 6 additions & 0 deletions src/AvTranscoder/data/decoded/Frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions src/AvTranscoder/file/FormatContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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));
Expand All @@ -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))
Expand All @@ -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")
Expand Down
10 changes: 3 additions & 7 deletions src/AvTranscoder/properties/FileProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -235,6 +230,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);
Expand Down
2 changes: 1 addition & 1 deletion src/AvTranscoder/properties/PixelProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
139 changes: 67 additions & 72 deletions src/AvTranscoder/properties/VideoProperties.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "VideoProperties.hpp"

#include <AvTranscoder/data/decoded/Frame.hpp>
#include <AvTranscoder/properties/util.hpp>
#include <AvTranscoder/progress/NoDisplayProgress.hpp>

Expand All @@ -19,9 +20,11 @@ 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)
, _gopSize(0)
, _gopStructure()
, _firstGopTimeCode(-1)
{
Expand All @@ -31,7 +34,7 @@ VideoProperties::VideoProperties(const FormatContext& formatContext, const size_
_firstGopTimeCode = _codecContext->timecode_frame_start;
}

if(level == eAnalyseLevelFirstGop)
if(_levelAnalysis == eAnalyseLevelFirstGop)
analyseGopStructure(progress);
}

Expand All @@ -43,11 +46,8 @@ 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, _codecContext->profile)) == NULL)
if((profile = av_get_profile_name(_codec, getProfile())) == NULL)
throw std::runtime_error("unknown codec profile");

return std::string(profile);
Expand Down Expand Up @@ -333,51 +333,44 @@ 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;

#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);

int gotFrame = 0;
int count = 0;
size_t count = 0;
int gopFramesSize = 0;

while(!av_read_frame(const_cast<AVFormatContext*>(_formatContext), &pkt))
{
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 += frame.getEncodedSize();
#else
gopFramesSize += pkt.size;
#endif
++count;
}
}
av_free_packet(&pkt);
if(_codecContext->gop_size == count)
if(getGopSize() == 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();
return (gopFramesSize / getGopSize()) * bitsPerByte * getFps();
}

size_t VideoProperties::getMaxBitRate() const
Expand Down Expand Up @@ -425,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)
Expand Down Expand Up @@ -493,61 +479,55 @@ 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);

int count = 0;
Frame frame;
size_t count = 0;
int gotFrame = 0;
bool stopAnalyse = false;
int positionOfFirstKeyFrame = -1;
int positionOfLastKeyFrame = -1;

while(!av_read_frame(const_cast<AVFormatContext*>(_formatContext), &pkt))
{
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), 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;
}

++count;
if(progress.progress(count, _codecContext->gop_size) == eJobStatusCancel)
stopAnalyse = true;
}
}

av_free_packet(&pkt);

if(_codecContext->gop_size == 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)
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
}
}
}
Expand All @@ -573,28 +553,43 @@ 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);
addProperty(data, "ticksPerFrame", &VideoProperties::getTicksPerFrame);
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::string 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 += " ";
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);
// 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;
Expand Down
Loading