3
3
#include < AvTranscoder/properties/util.hpp>
4
4
#include < AvTranscoder/properties/JsonWriter.hpp>
5
5
#include < AvTranscoder/properties/FileProperties.hpp>
6
+ #include < AvTranscoder/data/decoded/Frame.hpp>
6
7
7
8
#include < stdexcept>
8
9
@@ -58,6 +59,99 @@ size_t StreamProperties::getStreamId() const
58
59
return _formatContext->streams [_streamIndex]->id ;
59
60
}
60
61
62
+ size_t StreamProperties::getBitRate () const
63
+ {
64
+ if (!_codecContext)
65
+ throw std::runtime_error (" unknown codec context" );
66
+
67
+ // return bit rate of stream if present or VBR mode
68
+ if (_codecContext->bit_rate || _codecContext->rc_max_rate )
69
+ return _codecContext->bit_rate ;
70
+
71
+ LOG_WARN (" The bitrate of the stream '" << _streamIndex << " ' of file '" << _formatContext->filename << " ' is unknown." )
72
+
73
+ const AVMediaType streamType = getStreamType ();
74
+
75
+ // compute audio bitrate
76
+ if (streamType == AVMEDIA_TYPE_AUDIO)
77
+ {
78
+ LOG_INFO (" Compute the audio bitrate (suppose PCM audio data)." )
79
+
80
+ // warning: this is the way to compute bit rate of PCM audio data
81
+ const int bitsPerSample = av_get_bits_per_sample (_codecContext->codec_id ); // 0 if unknown for the given codec
82
+ return _codecContext->sample_rate * _codecContext->channels * bitsPerSample;
83
+ }
84
+
85
+ // compute video bitrate
86
+ if (streamType == AVMEDIA_TYPE_VIDEO)
87
+ {
88
+ LOG_INFO (" Compute the video bitrate by decoding the first GOP." )
89
+
90
+ if (!_formatContext || !_codec)
91
+ throw std::runtime_error (" cannot compute bit rate: unknown format or codec context" );
92
+ if (!_codecContext->width || !_codecContext->height )
93
+ throw std::runtime_error (" cannot compute bit rate: invalid frame size" );
94
+
95
+ // discard no frame type when decode
96
+ _codecContext->skip_frame = AVDISCARD_NONE;
97
+
98
+ Frame frame;
99
+ AVPacket pkt;
100
+ av_init_packet (&pkt);
101
+ avcodec_open2 (_codecContext, _codec, NULL );
102
+
103
+ int gotFrame = 0 ;
104
+ size_t nbDecodedFrames = 0 ;
105
+ int gopFramesSize = 0 ;
106
+ int positionOfFirstKeyFrame = -1 ;
107
+ int positionOfLastKeyFrame = -1 ;
108
+
109
+ while (!av_read_frame (const_cast <AVFormatContext*>(_formatContext), &pkt))
110
+ {
111
+ if (pkt.stream_index == (int )_streamIndex)
112
+ {
113
+ avcodec_decode_video2 (_codecContext, &frame.getAVFrame (), &gotFrame, &pkt);
114
+ if (gotFrame)
115
+ {
116
+ // check distance between key frames
117
+ AVFrame& avFrame = frame.getAVFrame ();
118
+ if (avFrame.pict_type == AV_PICTURE_TYPE_I)
119
+ {
120
+ if (positionOfFirstKeyFrame == -1 )
121
+ positionOfFirstKeyFrame = nbDecodedFrames;
122
+ else
123
+ positionOfLastKeyFrame = nbDecodedFrames;
124
+ }
125
+ ++nbDecodedFrames;
126
+
127
+ // added size of all frames of the same gop
128
+ if (positionOfLastKeyFrame == -1 )
129
+ {
130
+ #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 7, 100)
131
+ gopFramesSize += frame.getEncodedSize ();
132
+ #else
133
+ gopFramesSize += pkt.size ;
134
+ #endif
135
+ }
136
+ }
137
+ }
138
+ av_free_packet (&pkt);
139
+ if (positionOfFirstKeyFrame != -1 && positionOfLastKeyFrame != -1 )
140
+ break ;
141
+ }
142
+ avcodec_close (_codecContext);
143
+
144
+ const size_t gopSize = positionOfLastKeyFrame - positionOfFirstKeyFrame;
145
+ if (gopSize > 0 )
146
+ {
147
+ const float fps = av_q2d (_formatContext->streams [_streamIndex]->avg_frame_rate );
148
+ return (gopFramesSize / gopSize) * 8 * fps;
149
+ }
150
+ }
151
+
152
+ return 0 ;
153
+ }
154
+
61
155
Rational StreamProperties::getTimeBase () const
62
156
{
63
157
if (!_formatContext)
@@ -70,7 +164,20 @@ float StreamProperties::getDuration() const
70
164
const Rational timeBase = getTimeBase ();
71
165
const size_t duration = _formatContext->streams [_streamIndex]->duration ;
72
166
if (duration == (size_t )AV_NOPTS_VALUE)
167
+ {
168
+ LOG_WARN (" The duration of the stream '" << _streamIndex << " ' of file '" << _formatContext->filename << " ' is unknown." )
169
+ if (_fileProperties->isRawFormat ())
170
+ {
171
+ LOG_INFO (" Get the stream bitrate to compute the duration." )
172
+ const size_t bitRate = getBitRate ();
173
+ if (bitRate)
174
+ {
175
+ LOG_INFO (" Get the file size to compute the duration." )
176
+ return _fileProperties->getFileSize () / bitRate * 8 ;
177
+ }
178
+ }
73
179
return 0 ;
180
+ }
74
181
return av_q2d (timeBase) * duration;
75
182
}
76
183
@@ -136,6 +243,7 @@ PropertyVector& StreamProperties::fillVector(PropertyVector& data) const
136
243
{
137
244
addProperty (data, " streamId" , &StreamProperties::getStreamId);
138
245
addProperty (data, " streamIndex" , &StreamProperties::getStreamIndex);
246
+ addProperty (data, " bitRate" , &StreamProperties::getBitRate);
139
247
addProperty (data, " timeBase" , &StreamProperties::getTimeBase);
140
248
addProperty (data, " duration" , &StreamProperties::getDuration);
141
249
addProperty (data, " codecId" , &StreamProperties::getCodecId);
0 commit comments