@@ -29,6 +29,7 @@ VideoProperties::VideoProperties(const FileProperties& fileProperties, const siz
29
29
, _isTopFieldFirst(false )
30
30
, _gopSize(0 )
31
31
, _gopStructure()
32
+ , _nbFrames(0 )
32
33
, _firstGopTimeCode(-1 )
33
34
{
34
35
if (_codecContext)
@@ -37,8 +38,23 @@ VideoProperties::VideoProperties(const FileProperties& fileProperties, const siz
37
38
_firstGopTimeCode = _codecContext->timecode_frame_start ;
38
39
}
39
40
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
+ }
42
58
}
43
59
44
60
std::string VideoProperties::getProfileName () const
@@ -329,11 +345,11 @@ size_t VideoProperties::getBitRate() const
329
345
// return bit rate of stream if present or VBR mode
330
346
if (_codecContext->bit_rate || _codecContext->rc_max_rate )
331
347
return _codecContext->bit_rate ;
348
+ LOG_WARN (" The bitrate of the stream '" << _streamIndex << " ' of file '" << _formatContext->filename << " ' is unknown." )
332
349
333
350
if (_levelAnalysis == eAnalyseLevelHeader)
334
351
{
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." )
337
353
return 0 ;
338
354
}
339
355
@@ -364,21 +380,26 @@ size_t VideoProperties::getNbFrames() const
364
380
{
365
381
if (!_formatContext)
366
382
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)
369
391
{
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 ;
380
394
}
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;
382
403
}
383
404
384
405
size_t VideoProperties::getTicksPerFrame () const
@@ -445,18 +466,23 @@ float VideoProperties::getDuration() const
445
466
const float duration = StreamProperties::getDuration ();
446
467
if (duration != 0 )
447
468
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
+ }
448
476
449
- if (_fileProperties-> isRawFormat () )
477
+ if (! _nbFrames )
450
478
{
451
- LOG_INFO (" Get the stream bitrate to compute the duration ." )
479
+ LOG_INFO (" Estimate the duration from the file size and the bitrate ." )
452
480
const size_t bitRate = getBitRate ();
453
481
if (bitRate)
454
- {
455
- LOG_INFO (" Get the file size to compute the duration." )
456
482
return _fileProperties->getFileSize () / bitRate * 8 ;
457
- }
458
483
}
459
- return 0 ;
484
+ LOG_INFO (" Get the exact duration from the number of frames and the fps." )
485
+ return _nbFrames / getFps ();
460
486
}
461
487
462
488
bool VideoProperties::hasBFrames () const
@@ -503,24 +529,24 @@ std::vector<std::pair<char, int> > VideoProperties::getGopStructure() const
503
529
return _gopStructure;
504
530
}
505
531
506
- void VideoProperties::analyseGopStructure (IProgress& progress)
532
+ size_t VideoProperties::analyseGopStructure (IProgress& progress)
507
533
{
508
534
if (! _formatContext || ! _codecContext || ! _codec)
509
- return ;
535
+ return 0 ;
510
536
if (! _codecContext->width || ! _codecContext->height )
511
- return ;
537
+ return 0 ;
512
538
513
539
InputFile& file = const_cast <InputFile&>(_fileProperties->getInputFile ());
514
540
// Get the stream
515
541
IInputStream& stream = file.getStream (_streamIndex);
516
542
stream.activate ();
517
543
// Create a decoder
518
544
VideoDecoder decoder (static_cast <InputStream&>(stream));
545
+ VideoFrame frame (VideoFrameDesc (getWidth (), getHeight (), getPixelFormatName (getPixelProperties ().getAVPixelFormat ())), false );
519
546
520
- size_t count = 0 ;
547
+ size_t nbDecodedFrames = 0 ;
521
548
int positionOfFirstKeyFrame = -1 ;
522
549
int positionOfLastKeyFrame = -1 ;
523
- VideoFrame frame (VideoFrameDesc (getWidth (), getHeight (), getPixelFormatName (getPixelProperties ().getAVPixelFormat ())), false );
524
550
while (decoder.decodeNextFrame (frame))
525
551
{
526
552
AVFrame& avFrame = frame.getAVFrame ();
@@ -532,12 +558,12 @@ void VideoProperties::analyseGopStructure(IProgress& progress)
532
558
if (avFrame.pict_type == AV_PICTURE_TYPE_I)
533
559
{
534
560
if (positionOfFirstKeyFrame == -1 )
535
- positionOfFirstKeyFrame = count ;
561
+ positionOfFirstKeyFrame = nbDecodedFrames ;
536
562
else
537
- positionOfLastKeyFrame = count ;
563
+ positionOfLastKeyFrame = nbDecodedFrames ;
538
564
}
539
565
540
- _gopSize = ++count ;
566
+ _gopSize = ++nbDecodedFrames ;
541
567
542
568
// If the first 2 key frames are found
543
569
if (positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1 )
@@ -551,14 +577,50 @@ void VideoProperties::analyseGopStructure(IProgress& progress)
551
577
}
552
578
}
553
579
554
- // Returns at the beginning of the stream
555
- file.seekAtFrame (0 , AVSEEK_FLAG_BYTE);
556
-
557
580
// Check GOP size
558
581
if (_gopSize <= 0 )
559
582
{
560
583
throw std::runtime_error (" Invalid GOP size when decoding the first data." );
561
584
}
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;
562
624
}
563
625
564
626
PropertyVector& VideoProperties::fillVector (PropertyVector& data) const
0 commit comments