Skip to content

Commit b364f73

Browse files
author
Marc-Antoine Arnaud
committed
Merge remote-tracking branch 'origin' into dev_better_json_format
2 parents 14920f9 + 244f417 commit b364f73

File tree

5 files changed

+145
-42
lines changed

5 files changed

+145
-42
lines changed

app/avMeta/avMeta.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <AvTranscoder/file/InputFile.hpp>
2-
#include <AvTranscoder/progress/NoDisplayProgress.hpp>
2+
#include <AvTranscoder/progress/ConsoleProgress.hpp>
33

44
#include <iostream>
55

@@ -43,8 +43,8 @@ int main(int argc, char** argv)
4343

4444
// analyse inputFile
4545
avtranscoder::InputFile input(argv[1]);
46-
avtranscoder::NoDisplayProgress p;
47-
input.analyse(p, avtranscoder::eAnalyseLevelFirstGop);
46+
avtranscoder::ConsoleProgress p;
47+
input.analyse(p, avtranscoder::eAnalyseLevelFull);
4848

4949
// display file properties
5050
if(toJson)

src/AvTranscoder/file/util.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ enum EAnalyseLevel
1111
{
1212
eAnalyseLevelHeader = 0,
1313
eAnalyseLevelFirstGop = 1,
14-
// eAnalyseLevelFull = 2,
14+
eAnalyseLevelFull = 2
1515
};
1616
}
1717

src/AvTranscoder/properties/VideoProperties.cpp

Lines changed: 96 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ VideoProperties::VideoProperties(const FileProperties& fileProperties, const siz
2929
, _isTopFieldFirst(false)
3030
, _gopSize(0)
3131
, _gopStructure()
32+
, _nbFrames(0)
3233
, _firstGopTimeCode(-1)
3334
{
3435
if(_codecContext)
@@ -37,8 +38,23 @@ VideoProperties::VideoProperties(const FileProperties& fileProperties, const siz
3738
_firstGopTimeCode = _codecContext->timecode_frame_start;
3839
}
3940

40-
if(_levelAnalysis == eAnalyseLevelFirstGop)
41-
analyseGopStructure(progress);
41+
switch(_levelAnalysis)
42+
{
43+
case eAnalyseLevelFirstGop:
44+
analyseGopStructure(progress);
45+
break;
46+
case eAnalyseLevelFull:
47+
analyseFull(progress);
48+
break;
49+
default:
50+
break;
51+
}
52+
53+
if(_levelAnalysis > eAnalyseLevelHeader)
54+
{
55+
// Returns at the beginning of the stream
56+
const_cast<InputFile&>(_fileProperties->getInputFile()).seekAtFrame(0, AVSEEK_FLAG_BYTE);
57+
}
4258
}
4359

4460
std::string VideoProperties::getProfileName() const
@@ -329,11 +345,11 @@ size_t VideoProperties::getBitRate() const
329345
// return bit rate of stream if present or VBR mode
330346
if(_codecContext->bit_rate || _codecContext->rc_max_rate)
331347
return _codecContext->bit_rate;
348+
LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown.")
332349

333350
if(_levelAnalysis == eAnalyseLevelHeader)
334351
{
335-
LOG_WARN("The bitrate of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown. "
336-
"Need a deeper analysis: see eAnalyseLevelFirstGop.")
352+
LOG_INFO("Need a deeper analysis: see eAnalyseLevelFirstGop.")
337353
return 0;
338354
}
339355

@@ -364,21 +380,26 @@ size_t VideoProperties::getNbFrames() const
364380
{
365381
if(!_formatContext)
366382
throw std::runtime_error("unknown format context");
367-
size_t nbFrames = _formatContext->streams[_streamIndex]->nb_frames;
368-
if(nbFrames == 0)
383+
384+
const size_t nbFrames = _formatContext->streams[_streamIndex]->nb_frames;
385+
if(nbFrames)
386+
return nbFrames;
387+
LOG_WARN("The number of frames of the stream '" << _streamIndex << "' of file '" << _formatContext->filename
388+
<< "' is unknown.")
389+
390+
if(_levelAnalysis == eAnalyseLevelHeader)
369391
{
370-
LOG_WARN("The number of frames in the stream '" << _streamIndex << "' of file '" << _formatContext->filename
371-
<< "' is unknown.")
372-
const float duration = getDuration();
373-
if(duration != 0)
374-
{
375-
LOG_INFO("Try to compute the number of frames from the fps and the duration.")
376-
nbFrames = getFps() * duration;
377-
}
378-
else
379-
return 0;
392+
LOG_INFO("Need a deeper analysis: see eAnalyseLevelFirstGop.")
393+
return 0;
380394
}
381-
return nbFrames;
395+
396+
if(! _nbFrames)
397+
{
398+
LOG_INFO("Estimate the number of frames from the fps and the duration.")
399+
return getFps() * getDuration();
400+
}
401+
LOG_INFO("Get the exact number of frames.")
402+
return _nbFrames;
382403
}
383404

384405
size_t VideoProperties::getTicksPerFrame() const
@@ -445,18 +466,23 @@ float VideoProperties::getDuration() const
445466
const float duration = StreamProperties::getDuration();
446467
if(duration != 0)
447468
return duration;
469+
LOG_WARN("The duration of the stream '" << _streamIndex << "' of file '" << _formatContext->filename << "' is unknown.")
470+
471+
if(_levelAnalysis == eAnalyseLevelHeader)
472+
{
473+
LOG_INFO("Need a deeper analysis: see eAnalyseLevelFirstGop.")
474+
return 0;
475+
}
448476

449-
if(_fileProperties->isRawFormat())
477+
if(! _nbFrames)
450478
{
451-
LOG_INFO("Get the stream bitrate to compute the duration.")
479+
LOG_INFO("Estimate the duration from the file size and the bitrate.")
452480
const size_t bitRate = getBitRate();
453481
if(bitRate)
454-
{
455-
LOG_INFO("Get the file size to compute the duration.")
456482
return _fileProperties->getFileSize() / bitRate * 8;
457-
}
458483
}
459-
return 0;
484+
LOG_INFO("Get the exact duration from the number of frames and the fps.")
485+
return _nbFrames / getFps();
460486
}
461487

462488
bool VideoProperties::hasBFrames() const
@@ -503,24 +529,24 @@ std::vector<std::pair<char, int> > VideoProperties::getGopStructure() const
503529
return _gopStructure;
504530
}
505531

506-
void VideoProperties::analyseGopStructure(IProgress& progress)
532+
size_t VideoProperties::analyseGopStructure(IProgress& progress)
507533
{
508534
if(! _formatContext || ! _codecContext || ! _codec)
509-
return;
535+
return 0;
510536
if(! _codecContext->width || ! _codecContext->height)
511-
return;
537+
return 0;
512538

513539
InputFile& file = const_cast<InputFile&>(_fileProperties->getInputFile());
514540
// Get the stream
515541
IInputStream& stream = file.getStream(_streamIndex);
516542
stream.activate();
517543
// Create a decoder
518544
VideoDecoder decoder(static_cast<InputStream&>(stream));
545+
VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelFormatName(getPixelProperties().getAVPixelFormat())), false);
519546

520-
size_t count = 0;
547+
size_t nbDecodedFrames = 0;
521548
int positionOfFirstKeyFrame = -1;
522549
int positionOfLastKeyFrame = -1;
523-
VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelFormatName(getPixelProperties().getAVPixelFormat())), false);
524550
while(decoder.decodeNextFrame(frame))
525551
{
526552
AVFrame& avFrame = frame.getAVFrame();
@@ -532,12 +558,12 @@ void VideoProperties::analyseGopStructure(IProgress& progress)
532558
if(avFrame.pict_type == AV_PICTURE_TYPE_I)
533559
{
534560
if(positionOfFirstKeyFrame == -1)
535-
positionOfFirstKeyFrame = count;
561+
positionOfFirstKeyFrame = nbDecodedFrames;
536562
else
537-
positionOfLastKeyFrame = count;
563+
positionOfLastKeyFrame = nbDecodedFrames;
538564
}
539565

540-
_gopSize = ++count;
566+
_gopSize = ++nbDecodedFrames;
541567

542568
// If the first 2 key frames are found
543569
if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1)
@@ -551,14 +577,50 @@ void VideoProperties::analyseGopStructure(IProgress& progress)
551577
}
552578
}
553579

554-
// Returns at the beginning of the stream
555-
file.seekAtFrame(0, AVSEEK_FLAG_BYTE);
556-
557580
// Check GOP size
558581
if(_gopSize <= 0)
559582
{
560583
throw std::runtime_error("Invalid GOP size when decoding the first data.");
561584
}
585+
return nbDecodedFrames;
586+
}
587+
588+
size_t VideoProperties::analyseFull(IProgress& progress)
589+
{
590+
const size_t nbDecodedFrames = analyseGopStructure(progress);
591+
592+
if(! _fileProperties->isRawFormat())
593+
{
594+
LOG_INFO("No need to decode all the stream to get more information.")
595+
return nbDecodedFrames;
596+
}
597+
598+
if(! _formatContext || ! _codecContext || ! _codec)
599+
return 0;
600+
if(! _codecContext->width || ! _codecContext->height)
601+
return 0;
602+
603+
InputFile& file = const_cast<InputFile&>(_fileProperties->getInputFile());
604+
// Get the stream
605+
IInputStream& stream = file.getStream(_streamIndex);
606+
stream.activate();
607+
// Create a decoder
608+
VideoDecoder decoder(static_cast<InputStream&>(stream));
609+
VideoFrame frame(VideoFrameDesc(getWidth(), getHeight(), getPixelFormatName(getPixelProperties().getAVPixelFormat())), false);
610+
611+
const size_t estimateNbFrames = getNbFrames();
612+
_nbFrames = nbDecodedFrames;
613+
while(decoder.decodeNextFrame(frame))
614+
{
615+
progress.progress(++_nbFrames, estimateNbFrames);
616+
}
617+
618+
// Check GOP size
619+
if(_nbFrames <= 0)
620+
{
621+
throw std::runtime_error("Invalid number of frames when decoding the video stream.");
622+
}
623+
return _nbFrames;
562624
}
563625

564626
PropertyVector& VideoProperties::fillVector(PropertyVector& data) const

src/AvTranscoder/properties/VideoProperties.hpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,16 @@ class AvExport VideoProperties : public StreamProperties
104104

105105
private:
106106
/**
107-
* @brief frame type / is key frame
108-
* @param progress: callback to get analysis progression
107+
* @param progress: callback to get analysis progression
108+
* @return the number of decoded frames to compute the GOP structure.
109109
*/
110-
void analyseGopStructure(IProgress& progress);
110+
size_t analyseGopStructure(IProgress& progress);
111+
112+
/**
113+
* @param progress: callback to get analysis progression
114+
* @return the number of decoded frames to parse all the file.
115+
*/
116+
size_t analyseFull(IProgress& progress);
111117

112118
private:
113119
/**
@@ -121,13 +127,20 @@ class AvExport VideoProperties : public StreamProperties
121127
PixelProperties _pixelProperties;
122128

123129
//@{
124-
// Can acces these data when analyse first gop
130+
// @brief Can access these data when analysing the first GOP.
131+
// @see eAnalyseLevelFirstGOP
125132
bool _isInterlaced;
126133
bool _isTopFieldFirst;
127134
size_t _gopSize;
128135
std::vector<std::pair<char, int> > _gopStructure; ///< picture type, encoded frame size in bytes
129136
//@}
130137

138+
//@{
139+
// @brief Can access these data when analysing all the stream.
140+
// @see eAnalyseLevelFull
141+
size_t _nbFrames;
142+
//}
143+
131144
/**
132145
* @brief GOP timecode of the first frame
133146
* @note AVCodecContext stores the GOP timecode of the last decoded frame

test/pyTest/testInputFile.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,31 @@ def testInputFileAnalyseFirstGop():
9292
encodedPictureSize = image[1]
9393
assert_in(pictureType, ['I', 'P', 'B'])
9494
assert_greater(encodedPictureSize, 0)
95+
assert_not_equals(videoProperties.getDuration(), 0)
96+
assert_not_equals(videoProperties.getBitRate(), 0)
97+
assert_not_equals(videoProperties.getNbFrames(), 0)
98+
99+
100+
def testInputFileAnalyseFull():
101+
"""
102+
Analyse the full video stream of an InputFile, and check if the correct attributes are filled.
103+
"""
104+
inputFileName = os.environ['AVTRANSCODER_TEST_VIDEO_RAW_FILE']
105+
inputFile = av.InputFile( inputFileName )
106+
107+
# Analyse full stream
108+
progress = av.ConsoleProgress()
109+
inputFile.analyse(progress, av.eAnalyseLevelFull)
110+
111+
# Check properties after full analysis
112+
videoProperties = inputFile.getProperties().getVideoProperties()[0]
113+
assert_greater(videoProperties.getGopSize(), 0)
114+
assert_not_equals(videoProperties.getGopStructure(), ())
115+
for image in videoProperties.getGopStructure():
116+
pictureType = image[0]
117+
encodedPictureSize = image[1]
118+
assert_in(pictureType, ['I', 'P', 'B'])
119+
assert_greater(encodedPictureSize, 0)
120+
assert_not_equals(videoProperties.getDuration(), 0)
121+
assert_not_equals(videoProperties.getBitRate(), 0)
122+
assert_not_equals(videoProperties.getNbFrames(), 0)

0 commit comments

Comments
 (0)