You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
Fixing bitrate calculation (to be in bytes instead of bits), and adding in FPS detection for files which don't have valid FPS. In those cases (streaming files for example), we iterate through all packets, and average the # of frames, duration, bit rate, etc... Not idealy, but a better fallback.
This commit is contained in:
@@ -339,19 +339,21 @@ void FFmpegReader::UpdateAudioInfo()
|
||||
|
||||
void FFmpegReader::UpdateVideoInfo()
|
||||
{
|
||||
if (check_fps)
|
||||
// Already initialized all the video metadata, no reason to do it again
|
||||
return;
|
||||
|
||||
// Set values of FileInfo struct
|
||||
info.has_video = true;
|
||||
info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
|
||||
info.height = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->height;
|
||||
info.width = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->width;
|
||||
info.vcodec = pCodecCtx->codec->name;
|
||||
info.video_bit_rate = pFormatCtx->bit_rate;
|
||||
if (!check_fps)
|
||||
{
|
||||
// set frames per second (fps)
|
||||
info.fps.num = pStream->avg_frame_rate.num;
|
||||
info.fps.den = pStream->avg_frame_rate.den;
|
||||
}
|
||||
info.video_bit_rate = (pFormatCtx->bit_rate / 8);
|
||||
|
||||
// set frames per second (fps)
|
||||
info.fps.num = pStream->avg_frame_rate.num;
|
||||
info.fps.den = pStream->avg_frame_rate.den;
|
||||
|
||||
if (pStream->sample_aspect_ratio.num != 0)
|
||||
{
|
||||
@@ -415,16 +417,22 @@ void FFmpegReader::UpdateVideoInfo()
|
||||
}
|
||||
|
||||
// Override an invalid framerate
|
||||
if (info.fps.ToFloat() > 240.0f || (info.fps.num == 0 || info.fps.den == 0))
|
||||
{
|
||||
// Set a few important default video settings (so audio can be divided into frames)
|
||||
info.fps.num = 24;
|
||||
info.fps.den = 1;
|
||||
info.video_timebase.num = 1;
|
||||
info.video_timebase.den = 24;
|
||||
if (info.fps.ToFloat() > 240.0f || (info.fps.num == 0 || info.fps.den == 0)) {
|
||||
// Calculate FPS, duration, video bit rate, and video length manually
|
||||
// by scanning through all the video stream packets
|
||||
CheckFPS();
|
||||
|
||||
// Calculate number of frames
|
||||
info.video_length = round(info.duration * info.fps.ToDouble());
|
||||
// If still an invalid FPS detected, just default to 24 FPS
|
||||
// Set a few important default video settings (so audio can be divided into frames)
|
||||
if (info.fps.ToFloat() > 240.0f || (info.fps.num == 0 || info.fps.den == 0)) {
|
||||
info.fps.num = 24;
|
||||
info.fps.den = 1;
|
||||
info.video_timebase.num = 1;
|
||||
info.video_timebase.den = 24;
|
||||
|
||||
// Calculate number of frames
|
||||
info.video_length = round(info.duration * info.fps.ToDouble());
|
||||
}
|
||||
}
|
||||
|
||||
// Add video metadata (if any)
|
||||
@@ -1857,16 +1865,12 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram
|
||||
void FFmpegReader::CheckFPS()
|
||||
{
|
||||
check_fps = true;
|
||||
AV_ALLOCATE_IMAGE(pFrame, AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx), info.width, info.height);
|
||||
|
||||
int first_second_counter = 0;
|
||||
int second_second_counter = 0;
|
||||
int third_second_counter = 0;
|
||||
int forth_second_counter = 0;
|
||||
int fifth_second_counter = 0;
|
||||
|
||||
int iterations = 0;
|
||||
int threshold = 500;
|
||||
int frames_detected = 0;
|
||||
|
||||
// Loop through the stream
|
||||
while (true)
|
||||
@@ -1908,63 +1912,29 @@ void FFmpegReader::CheckFPS()
|
||||
forth_second_counter++;
|
||||
else if (video_seconds > 4.0 && video_seconds <= 5.0)
|
||||
fifth_second_counter++;
|
||||
else
|
||||
// Too far
|
||||
break;
|
||||
|
||||
// Increment counters
|
||||
frames_detected++;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment counters
|
||||
iterations++;
|
||||
|
||||
// Give up (if threshold exceeded)
|
||||
if (iterations > threshold)
|
||||
break;
|
||||
}
|
||||
|
||||
// Double check that all counters have greater than zero (or give up)
|
||||
if (second_second_counter == 0 || third_second_counter == 0 || forth_second_counter == 0 || fifth_second_counter == 0)
|
||||
{
|
||||
// Seek to frame 1
|
||||
Seek(1);
|
||||
if (second_second_counter != 0 && third_second_counter != 0 && forth_second_counter != 0 && fifth_second_counter != 0) {
|
||||
// Calculate average FPS
|
||||
int sum_fps = second_second_counter + third_second_counter + forth_second_counter + fifth_second_counter;
|
||||
int avg_fps = round(sum_fps / 4.0f);
|
||||
|
||||
// exit with no changes to FPS (not enough data to calculate)
|
||||
return;
|
||||
// Update FPS
|
||||
info.fps = Fraction(avg_fps, 1);
|
||||
|
||||
// Update Duration and Length
|
||||
info.video_length = frames_detected;
|
||||
info.duration = frames_detected / round(sum_fps / 4.0f);
|
||||
|
||||
// Update video bit rate
|
||||
info.video_bit_rate = info.file_size / info.duration;
|
||||
}
|
||||
|
||||
int sum_fps = second_second_counter + third_second_counter + forth_second_counter + fifth_second_counter;
|
||||
int avg_fps = round(sum_fps / 4.0f);
|
||||
|
||||
// Sometimes the FPS is incorrectly detected by FFmpeg. If the 1st and 2nd seconds counters
|
||||
// agree with each other, we are going to adjust the FPS of this reader instance. Otherwise, print
|
||||
// a warning message.
|
||||
|
||||
// Get diff from actual frame rate
|
||||
double fps = info.fps.ToDouble();
|
||||
double diff = fps - double(avg_fps);
|
||||
|
||||
// Is difference bigger than 1 frame?
|
||||
if (diff <= -1 || diff >= 1)
|
||||
{
|
||||
// Compare to half the frame rate (the most common type of issue)
|
||||
double half_fps = Fraction(info.fps.num / 2, info.fps.den).ToDouble();
|
||||
diff = half_fps - double(avg_fps);
|
||||
|
||||
// Is difference bigger than 1 frame?
|
||||
if (diff <= -1 || diff >= 1)
|
||||
{
|
||||
// Update FPS for this reader instance
|
||||
info.fps = Fraction(avg_fps, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update FPS for this reader instance (to 1/2 the original framerate)
|
||||
info.fps = Fraction(info.fps.num / 2, info.fps.den);
|
||||
}
|
||||
}
|
||||
|
||||
// Seek to frame 1
|
||||
Seek(1);
|
||||
}
|
||||
|
||||
// Remove AVFrame from cache (and deallocate it's memory)
|
||||
|
||||
Reference in New Issue
Block a user