AvTranscoder  0.9.4
C++APIforLibav/FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VideoProperties.cpp
Go to the documentation of this file.
1 #include "VideoProperties.hpp"
2 
6 
7 extern "C" {
8 #include <libavutil/avutil.h>
9 }
10 
11 #include <stdexcept>
12 #include <iomanip>
13 #include <sstream>
14 #include <limits>
15 #include <cmath>
16 
17 namespace avtranscoder
18 {
19 
20 VideoProperties::VideoProperties(const FormatContext& formatContext, const size_t index, IProgress& progress,
21  const EAnalyseLevel level)
22  : StreamProperties(formatContext, index)
23  , _levelAnalysis(level)
24  , _pixelProperties()
25  , _isInterlaced(false)
26  , _isTopFieldFirst(false)
27  , _gopSize(0)
28  , _gopStructure()
29  , _firstGopTimeCode(-1)
30 {
31  if(_codecContext)
32  {
34  _firstGopTimeCode = _codecContext->timecode_frame_start;
35  }
36 
38  analyseGopStructure(progress);
39 }
40 
42 {
43  if(!_codecContext || !_codec)
44  throw std::runtime_error("unknown codec");
45 
46  if(_codec->capabilities & CODEC_CAP_TRUNCATED)
47  _codecContext->flags |= CODEC_FLAG_TRUNCATED;
48 
49  const char* profile = NULL;
50  if((profile = av_get_profile_name(_codec, getProfile())) == NULL)
51  throw std::runtime_error("unknown codec profile");
52 
53  return std::string(profile);
54 }
55 
57 {
58  if(!_codecContext)
59  throw std::runtime_error("unknown codec context");
60 
61  switch(_codecContext->color_trc)
62  {
63  case AVCOL_TRC_BT709:
64  return "Rec 709 / ITU-R BT1361";
65  case AVCOL_TRC_UNSPECIFIED:
66  return "unspecified";
67  case AVCOL_TRC_GAMMA22:
68  return "Gamma 2.2";
69  case AVCOL_TRC_GAMMA28:
70  return "Gamma 2.8";
71 #if LIBAVCODEC_VERSION_MAJOR > 53
72  case AVCOL_TRC_SMPTE240M:
73  return "Smpte 240M";
74 #endif
75 #if LIBAVCODEC_VERSION_MAJOR > 54
76 #ifdef AVCOL_TRC_SMPTE170M
77  case AVCOL_TRC_SMPTE170M:
78  return "Rec 601 / ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC";
79 #endif
80 #ifdef AVCOL_TRC_LINEAR
81  case AVCOL_TRC_LINEAR:
82  return "Linear transfer characteristics";
83 #endif
84 #ifdef AVCOL_TRC_LOG
85  case AVCOL_TRC_LOG:
86  return "Logarithmic transfer characteristic (100:1 range)";
87 #endif
88 #ifdef AVCOL_TRC_LOG_SQRT
89  case AVCOL_TRC_LOG_SQRT:
90  return "Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range)";
91 #endif
92 #ifdef AVCOL_TRC_IEC61966_2_4
93  case AVCOL_TRC_IEC61966_2_4:
94  return "IEC 61966-2-4";
95 #endif
96 #ifdef AVCOL_TRC_BT1361_ECG
97  case AVCOL_TRC_BT1361_ECG:
98  return "ITU-R BT1361 Extended Colour Gamut";
99 #endif
100 #ifdef AVCOL_TRC_IEC61966_2_1
101  case AVCOL_TRC_IEC61966_2_1:
102  return "IEC 61966-2-1 (sRGB or sYCC)";
103 #endif
104 #ifdef AVCOL_TRC_BT2020_10
105  case AVCOL_TRC_BT2020_10:
106  return "ITU-R BT2020 for 10 bit system";
107 #endif
108 #ifdef AVCOL_TRC_BT2020_12
109  case AVCOL_TRC_BT2020_12:
110  return "ITU-R BT2020 for 12 bit system";
111 #endif
112 #endif
113  case AVCOL_TRC_NB:
114  return "Not ABI";
115  default:
116  return "";
117  }
118 }
119 
121 {
122  if(!_codecContext)
123  throw std::runtime_error("unknown codec context");
124 
125  switch(_codecContext->colorspace)
126  {
127  case AVCOL_SPC_RGB:
128  return "RGB";
129  case AVCOL_SPC_BT709:
130  return "Rec 709";
131  case AVCOL_SPC_UNSPECIFIED:
132  return "unspecified";
133  case AVCOL_SPC_FCC:
134  return "Four CC";
135  case AVCOL_SPC_BT470BG:
136  return "BT470 (PAL - 625)";
137  case AVCOL_SPC_SMPTE170M:
138  return "Smpte 170M (NTSC)";
139  case AVCOL_SPC_SMPTE240M:
140  return "Smpte 240M";
141 #if LIBAVCODEC_VERSION_MAJOR > 53
142  case AVCOL_SPC_YCOCG:
143  return "Y Co Cg";
144 //#else
145 // case AVCOL_SPC_YCGCO:
146 // return "Y Cg Co";
147 #endif
148 #if LIBAVCODEC_VERSION_MAJOR > 54
149 #ifdef AVCOL_TRC_BT2020_12
150  case AVCOL_SPC_BT2020_NCL:
151  return "ITU-R BT2020 non-constant luminance system";
152 #endif
153 #ifdef AVCOL_TRC_BT2020_CL
154  case AVCOL_SPC_BT2020_CL:
155  return "ITU-R BT2020 constant luminance system";
156 #endif
157 #endif
158  case AVCOL_SPC_NB:
159  return "Not ABI";
160  default:
161  return "";
162  }
163 }
164 
166 {
167  if(!_codecContext)
168  throw std::runtime_error("unknown codec context");
169 
170  switch(_codecContext->color_range)
171  {
172  case AVCOL_RANGE_UNSPECIFIED:
173  return "unspecified";
174  case AVCOL_RANGE_MPEG:
175  return "Head";
176  case AVCOL_RANGE_JPEG:
177  return "Full";
178  case AVCOL_RANGE_NB:
179  return "Not ABI";
180  default:
181  return "";
182  }
183 }
184 
186 {
187  if(!_codecContext)
188  throw std::runtime_error("unknown codec context");
189 
190  switch(_codecContext->color_primaries)
191  {
192  case AVCOL_PRI_BT709:
193  return "Rec 709";
194  case AVCOL_PRI_UNSPECIFIED:
195  return "unspecified";
196  case AVCOL_PRI_BT470M:
197  return "BT 470M";
198  case AVCOL_PRI_BT470BG:
199  return "Rec 601 (PAL & SECAM)";
200  case AVCOL_PRI_SMPTE170M:
201  return "Rec 601 (NTSC)";
202  case AVCOL_PRI_SMPTE240M:
203  return "Smpte 240 (NTSC)";
204  case AVCOL_PRI_FILM:
205  return "Film";
206 #if LIBAVCODEC_VERSION_MAJOR > 54
207 #ifdef AVCOL_TRC_BT2020_CL
208  case AVCOL_PRI_BT2020:
209  return "ITU-R BT2020";
210 #endif
211 #endif
212  case AVCOL_PRI_NB:
213  return "Not ABI";
214  default:
215  return "";
216  }
217 }
218 
220 {
221  if(!_codecContext)
222  throw std::runtime_error("unknown codec context");
223 
224  switch(_codecContext->chroma_sample_location)
225  {
226  case AVCHROMA_LOC_UNSPECIFIED:
227  return "unspecified";
228  case AVCHROMA_LOC_LEFT:
229  return "left (mpeg2/4, h264 default)";
230  case AVCHROMA_LOC_CENTER:
231  return "center (mpeg1, jpeg, h263)";
232  case AVCHROMA_LOC_TOPLEFT:
233  return "top left";
234  case AVCHROMA_LOC_TOP:
235  return "top";
236  case AVCHROMA_LOC_BOTTOMLEFT:
237  return "bottom left";
238  case AVCHROMA_LOC_BOTTOM:
239  return "bottom";
240  case AVCHROMA_LOC_NB:
241  return "Not ABI";
242  default:
243  return "";
244  }
245 }
246 
248 {
249  if(!_codecContext)
250  throw std::runtime_error("unknown codec context");
251 
252  switch(_codecContext->field_order)
253  {
254  case AV_FIELD_UNKNOWN:
255  return "unknown";
256  case AV_FIELD_PROGRESSIVE:
257  return "progressive";
258  case AV_FIELD_TT:
259  return "top top";
260  case AV_FIELD_BB:
261  return "bottom bottom";
262  case AV_FIELD_TB:
263  return "top bottom";
264  case AV_FIELD_BT:
265  return "bottom top";
266  default:
267  return "";
268  }
269 }
270 
272 {
273  if(!_codecContext)
274  throw std::runtime_error("unknown codec context");
275  return _firstGopTimeCode;
276 }
277 
279 {
280  int64_t startTimeCode = getStartTimecode();
281  std::ostringstream os;
282  if(startTimeCode == -1)
283  os << "unset";
284  else
285  {
286  os << std::setfill('0');
287  os << std::setw(2) << (startTimeCode >> 19 & 0x1f) << ":"; // 5-bit hours
288  os << std::setw(2) << (startTimeCode >> 13 & 0x3f) << ":"; // 6-bit minutes
289  os << std::setw(2) << (startTimeCode >> 6 & 0x3f); // 6-bit seconds
290  os << (startTimeCode & 1 << 24 ? ';' : ':'); // 1-bit drop flag
291  os << std::setw(2) << (startTimeCode & 0x3f); // 6-bit frames
292  }
293  return os.str();
294 }
295 
297 {
298  if(!_codecContext)
299  throw std::runtime_error("unknown codec context");
300 
301  Rational sar = {
302  _codecContext->sample_aspect_ratio.num, _codecContext->sample_aspect_ratio.den,
303  };
304  return sar;
305 }
306 
308 {
309  if(!_codecContext)
310  throw std::runtime_error("unknown codec context");
311 
312  int darNum, darDen;
313  av_reduce(&darNum, &darDen, _codecContext->width * getSar().num, _codecContext->height * getSar().den, 1024 * 1024);
314 
315  Rational dar = {
316  darNum, darDen,
317  };
318  return dar;
319 }
320 
322 {
323  if(!_codecContext)
324  throw std::runtime_error("unknown codec context");
325  // return bit rate of stream if present or VBR mode
326  if(_codecContext->bit_rate || _codecContext->rc_max_rate)
327  return _codecContext->bit_rate;
328 
329  // else compute bit rate from the first GOP
330  if(!_formatContext || !_codec)
331  throw std::runtime_error("cannot compute bit rate: unknown format or codec context");
332 
333  if(!_codecContext->width || !_codecContext->height)
334  throw std::runtime_error("cannot compute bit rate: invalid frame size");
335 
336  // Needed to get the gop size
338  throw std::runtime_error("cannot compute bit rate: need to get info from the first gop (see eAnalyseLevelFirstGop)");
339 
340  // discard no frame type when decode
341  _codecContext->skip_frame = AVDISCARD_NONE;
342 
343  Frame frame;
344  AVPacket pkt;
345  av_init_packet(&pkt);
346  avcodec_open2(_codecContext, _codec, NULL);
347 
348  int gotFrame = 0;
349  size_t count = 0;
350  int gopFramesSize = 0;
351 
352  while(!av_read_frame(const_cast<AVFormatContext*>(_formatContext), &pkt))
353  {
354  if(pkt.stream_index == (int)_streamIndex)
355  {
356  avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt);
357  if(gotFrame)
358  {
359 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 7, 100)
360  gopFramesSize += frame.getEncodedSize();
361 #else
362  gopFramesSize += pkt.size;
363 #endif
364  ++count;
365  }
366  }
367  av_free_packet(&pkt);
368  if(getGopSize() == count)
369  break;
370  }
371 
372  int bitsPerByte = 8;
373  return (gopFramesSize / getGopSize()) * bitsPerByte * getFps();
374 }
375 
377 {
378  if(!_codecContext)
379  throw std::runtime_error("unknown codec context");
380  return _codecContext->rc_max_rate;
381 }
382 
384 {
385  if(!_codecContext)
386  throw std::runtime_error("unknown codec context");
387  return _codecContext->rc_min_rate;
388 }
389 
391 {
392  if(!_formatContext)
393  throw std::runtime_error("unknown format context");
394  size_t nbFrames = _formatContext->streams[_streamIndex]->nb_frames;
395  if(nbFrames == 0)
396  nbFrames = getFps() * getDuration();
397  return nbFrames;
398 }
399 
401 {
402  if(!_codecContext)
403  throw std::runtime_error("unknown codec context");
404  return _codecContext->ticks_per_frame;
405 }
406 
408 {
409  if(!_codecContext)
410  throw std::runtime_error("unknown codec context");
411  return _codecContext->width;
412 }
413 
415 {
416  if(!_codecContext)
417  throw std::runtime_error("unknown codec context");
418  return _codecContext->height;
419 }
420 
422 {
423  if(!_codecContext)
424  throw std::runtime_error("unknown codec context");
425  return _codecContext->dtg_active_format;
426 }
427 
429 {
430  if(!_codecContext)
431  throw std::runtime_error("unknown codec context");
432  return _codecContext->refs;
433 }
434 
436 {
437  if(!_codecContext)
438  throw std::runtime_error("unknown codec context");
439  return _codecContext->profile;
440 }
441 
443 {
444  if(!_codecContext)
445  throw std::runtime_error("unknown codec context");
446  return _codecContext->level;
447 }
448 
450 {
451  return av_q2d(_formatContext->streams[_streamIndex]->avg_frame_rate);
452 }
453 
455 {
456  if(!_codecContext)
457  throw std::runtime_error("unknown codec context");
458  return (bool)_codecContext->has_b_frames;
459 }
460 
461 // CODEC_FLAG_CLOSED_GOP is superior of INT_MAX, and _codecContext->flags is an int
462 // => Need a patch from FFmpeg
463 // bool VideoProperties::isClosedGop() const
464 //{
465 // if( ! _codecContext )
466 // throw std::runtime_error( "unknown codec context" );
467 // return ( _codecContext->flags & CODEC_FLAG_CLOSED_GOP ) == CODEC_FLAG_CLOSED_GOP;
468 //}
469 
471 {
473  {
474  if(_codecContext->width && _codecContext->height)
475  {
476  // Discard no frame type when decode
477  _codecContext->skip_frame = AVDISCARD_NONE;
478 
479  AVPacket pkt;
480  av_init_packet(&pkt);
481 
482  // Initialize the AVCodecContext to use the given AVCodec
483  avcodec_open2(_codecContext, _codec, NULL);
484 
485  Frame frame;
486  size_t count = 0;
487  int gotFrame = 0;
488  int positionOfFirstKeyFrame = -1;
489  int positionOfLastKeyFrame = -1;
490 
491  while(!av_read_frame(const_cast<AVFormatContext*>(_formatContext), &pkt))
492  {
493  if(pkt.stream_index == (int)_streamIndex)
494  {
495  avcodec_decode_video2(_codecContext, &frame.getAVFrame(), &gotFrame, &pkt);
496  if(gotFrame)
497  {
498  AVFrame& avFrame = frame.getAVFrame();
499 
500  _gopStructure.push_back(
501  std::make_pair(av_get_picture_type_char(avFrame.pict_type), frame.getEncodedSize()));
502  _isInterlaced = avFrame.interlaced_frame;
503  _isTopFieldFirst = avFrame.top_field_first;
504  if(avFrame.pict_type == AV_PICTURE_TYPE_I)
505  {
506  if(positionOfFirstKeyFrame == -1)
507  positionOfFirstKeyFrame = count;
508  else
509  positionOfLastKeyFrame = count;
510  }
511 
512  ++count;
513  }
514  }
515  av_free_packet(&pkt);
516 
517  // If the first 2 key frames are found
518  if(positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1)
519  {
520  // Set gop size as distance between these 2 key frames
521  _gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame;
522  // Update gop structure to keep only one gop
523  while(_gopStructure.size() > _gopSize)
524  _gopStructure.pop_back();
525  break;
526  }
527  }
528 
529  // Close a given AVCodecContext and free all the data associated with it (but not the AVCodecContext itself)
530  avcodec_close(_codecContext);
531  }
532  }
533 }
534 
536 {
537  // Add properties of base class
538  PropertyVector basedProperty;
539  StreamProperties::fillVector(basedProperty);
540  data.insert(data.begin(), basedProperty.begin(), basedProperty.end());
541 
542  addProperty(data, "profile", &VideoProperties::getProfile);
543  addProperty(data, "profileName", &VideoProperties::getProfileName);
544  addProperty(data, "level", &VideoProperties::getLevel);
545  addProperty(data, "startTimecode", &VideoProperties::getStartTimecodeString);
546  addProperty(data, "width", &VideoProperties::getWidth);
547  addProperty(data, "height", &VideoProperties::getHeight);
548  addProperty(data, "pixelAspectRatio", &VideoProperties::getSar);
549  addProperty(data, "displayAspectRatio", &VideoProperties::getDar);
550  addProperty(data, "dtgActiveFormat", &VideoProperties::getDtgActiveFormat);
551  addProperty(data, "colorTransfert", &VideoProperties::getColorTransfert);
552  addProperty(data, "colorspace", &VideoProperties::getColorspace);
553  addProperty(data, "colorRange", &VideoProperties::getColorRange);
554  addProperty(data, "colorPrimaries", &VideoProperties::getColorPrimaries);
555  addProperty(data, "chromaSampleLocation", &VideoProperties::getChromaSampleLocation);
556  addProperty(data, "fieldOrder", &VideoProperties::getFieldOrder);
557  addProperty(data, "fps", &VideoProperties::getFps);
558  addProperty(data, "nbFrame", &VideoProperties::getNbFrames);
559  addProperty(data, "ticksPerFrame", &VideoProperties::getTicksPerFrame);
560  addProperty(data, "bitRate", &VideoProperties::getBitRate);
561  addProperty(data, "maxBitRate", &VideoProperties::getMaxBitRate);
562  addProperty(data, "minBitRate", &VideoProperties::getMinBitRate);
563  addProperty(data, "hasBFrames", &VideoProperties::hasBFrames);
564  addProperty(data, "referencesFrames", &VideoProperties::getReferencesFrames);
565 
566  // Add properties available when decode first gop
568  {
569  detail::add(data, "gopSize", detail::propertyValueIfError);
571  detail::add(data, "interlaced", detail::propertyValueIfError);
572  detail::add(data, "topFieldFirst", detail::propertyValueIfError);
573  }
574  else
575  {
576  addProperty(data, "gopSize", &VideoProperties::getGopSize);
577 
578  std::stringstream gop;
579  for(size_t frameIndex = 0; frameIndex < _gopStructure.size(); ++frameIndex)
580  {
581  gop << _gopStructure.at(frameIndex).first;
582  gop << "(";
583  gop << _gopStructure.at(frameIndex).second;;
584  gop << ")";
585  gop << " ";
586  }
587  detail::add(data, "gop", gop.str());
588  // detail::add( data, "isClosedGop", isClosedGop() );
589 
590  addProperty(data, "interlaced ", &VideoProperties::isInterlaced);
591  addProperty(data, "topFieldFirst", &VideoProperties::isTopFieldFirst);
592  }
593 
594  // Add properties of the pixel
595  PropertyVector pixelProperties;
596  _pixelProperties.fillVector(pixelProperties);
597  data.insert(data.end(), pixelProperties.begin(), pixelProperties.end());
598 
599  return data;
600 }
601 
602 std::ostream& operator<<(std::ostream& flux, const VideoProperties& videoProperties)
603 {
604  flux << std::left;
605  flux << detail::separator << " Video stream " << detail::separator << std::endl;
606 
607  PropertyVector properties = videoProperties.asVector();
608  for(PropertyVector::iterator it = properties.begin(); it != properties.end(); ++it)
609  {
610  flux << std::setw(detail::keyWidth) << it->first << ": " << it->second << std::endl;
611  }
612 
613  return flux;
614 }
615 }
Base class of Progress. Inherit this class to have your own way to manage a progress bar...
Definition: IProgress.hpp:23
std::vector< std::pair< std::string, std::string > > PropertyVector
PropertyVector is a vector of pair, because the order of properties matters to us.
Definition: util.hpp:23
const AVFormatContext * _formatContext
Has link (no ownership)
EAnalyseLevel
Level of file analysis.
Definition: util.hpp:10
std::string getChromaSampleLocation() const
std::vector< std::pair< char, int > > _gopStructure
picture type, encoded frame size in bytes
const size_t keyWidth
Definition: util.hpp:32
const std::string separator
Definition: util.hpp:33
std::string getStartTimecodeString() const
void add(PropertyVector &propertyVector, const std::string &key, const size_t &value)
Definition: util.cpp:16
AVCodec * _codec
Has link (no ownership)
void analyseGopStructure(IProgress &progress)
frame type / is key frame
PropertyVector & fillVector(PropertyVector &data) const
To avoid copy of the vector.
float getDuration() const
in seconds
size_t getBitRate() const
in bits/s
void addProperty(PropertyVector &dataVector, const std::string &key, T(VideoProperties::*getter)(void) const) const
int getEncodedSize() const
Definition: Frame.cpp:43
std::string getProfileName() const
Wrapper of an AVFormatContext.
EAnalyseLevel _levelAnalysis
Level of analysis asked.
std::string getColorPrimaries() const
std::string getColorRange() const
float getFps() const
Corresponds to the 'fps' returned by ffprobe. fps = the average framerate that has come from the AVSt...
virtual PropertyVector & fillVector(PropertyVector &data) const
To avoid copy of the vector.
std::string getFieldOrder() const
int64_t _firstGopTimeCode
GOP timecode of the first frame.
AVCodecContext * _codecContext
Has link (no ownership)
This class describes decoded (raw) audio or video data.
Definition: Frame.hpp:16
PropertyVector & fillVector(PropertyVector &data) const
To avoid copy of the vector.
std::string getColorTransfert() const
Virtual based class of properties for all types of stream.
std::string getColorspace() const
AVRational Rational
Definition: common.hpp:55
VideoProperties(const FormatContext &formatContext, const size_t index, IProgress &progress, const EAnalyseLevel level=eAnalyseLevelFirstGop)
std::ostream & operator<<(std::ostream &flux, const InputFile &input)
Definition: InputFile.cpp:171
AVFrame & getAVFrame()
Definition: Frame.hpp:88
const std::string propertyValueIfError
Definition: util.hpp:38
PropertyVector asVector() const
Same data with a specific order.
PixelProperties _pixelProperties
All the pixel properties contained in this stream.
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