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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy