Framerate fix (#246)

* Framerate fix

Keep original framerate up to 60fps, halve any framerate above 60fps. Because of "video_frame_rate": Fraction(video_info["r_frame_rate"]), it does not work, when float used, the video is encoded but framerate suffers from rounding error.

* Framerate fix

Keep original framerate up to 60fps, halve any framerate above 60fps. Because of "video_frame_rate": Fraction(video_info["r_frame_rate"]), it does not work, when float used, the video is encoded but framerate suffers from rounding error.

* Introduction of minimum bitrate modifier

A minimum bitrate modifier introduced as per https://developers.google.com/media/vp9/settings/vod

* Introduction of minimum bitrate modifier

A minimum bitrate modifier introduced as per https://developers.google.com/media/vp9/settings/vod
This commit is contained in:
multiflexi 2021-08-20 13:04:50 +02:00 committed by GitHub
parent 062e4be6c2
commit 48838ac406
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -23,6 +23,8 @@ CRF_ENCODING_NUM_SECONDS = 2 # 0 * 60 # videos with greater duration will get
# you should use CRF encoding.
MAX_RATE_MULTIPLIER = 1.5
MIN_RATE_MULTIPLIER = 0.5
BUF_SIZE_MULTIPLIER = 1.5
# in seconds, anything between 2 and 6 makes sense
@ -238,7 +240,8 @@ def media_file_info(input_file):
- `filename`: Filename
- `file_size`: Size of the file in bytes
- `video_duration`: Duration of the video in `s.msec`
- `video_frame_rate`: Framerate in Hz
- `video_frame_rate_d`: Framerate franction denominator
- `video_frame_rate_n`: Framerate fraction nominator
- `video_bitrate`: Bitrate of the video stream in kBit/s
- `video_width`: Width in pixels
- `video_height`: Height in pixels
@ -366,18 +369,31 @@ def media_file_info(input_file):
stdout = run_command(cmd).get("out")
stream_size = sum([int(line) for line in stdout.split("\n") if line != ""])
video_bitrate = round((stream_size * 8 / 1024.0) / video_duration, 2)
if "r_frame_rate" in video_info.keys():
video_frame_rate = video_info["r_frame_rate"].partition("/")
video_frame_rate_n = video_frame_rate[0]
video_frame_rate_d = video_frame_rate[2]
ret = {
"filename": input_file,
"file_size": file_size,
"video_duration": video_duration,
"video_frame_rate": float(Fraction(video_info["r_frame_rate"])),
"video_duration": video_duration,
"video_frame_rate_n": video_frame_rate_n,
"video_frame_rate_d": video_frame_rate_d,
"video_bitrate": video_bitrate,
"video_width": video_info["width"],
"video_height": video_info["height"],
"video_codec": video_info["codec_name"],
"has_video": has_video,
"has_audio": has_audio,
"color_range": video_info.get("color_range"),
"color_space": video_info.get("color_space"),
"color_transfer": video_info.get("color_space"),
"color_primaries": video_info.get("color_primaries"),
"field_order": video_info.get("field_order"),
"display_aspect_ratio": video_info.get("display_aspect_ratio"),
"sample_aspect_ratio": video_info.get("sample_aspect_ratio"),
}
if has_audio:
@ -492,7 +508,7 @@ def get_base_ffmpeg_command(
codec {str} -- video codec
encoder {str} -- video encoder
audio_encoder {str} -- audio encoder
target_fps {int} -- target FPS
target_fps {fractions.Fraction} -- target FPS
target_height {int} -- height
target_rate {int} -- target bitrate in kbps
target_rate_audio {int} -- audio target bitrate
@ -501,10 +517,12 @@ def get_base_ffmpeg_command(
enc_type {str} -- encoding type (twopass or crf)
"""
target_fps = int(target_fps)
# avoid Frame rate very high for a muxer not efficiently supporting it.
if target_fps > 90:
target_fps = 90
# avoid very high frame rates
while target_fps > 60:
target_fps = target_fps/2
if target_fps < 1:
target_fps = 1
base_cmd = [
settings.FFMPEG_COMMAND,
@ -622,6 +640,8 @@ def get_base_ffmpeg_command(
str(keyframe_distance),
"-maxrate",
str(int(int(target_rate) * MAX_RATE_MULTIPLIER)) + "k",
"-minrate",
str(int(int(target_rate) * MIN_RATE_MULTIPLIER)) + "k",
"-bufsize",
str(int(int(target_rate) * BUF_SIZE_MULTIPLIER)) + "k",
"-speed",
@ -669,8 +689,8 @@ def produce_ffmpeg_commands(media_file, media_info, resolution, codec, output_fi
else:
return False
src_framerate = media_info.get("video_frame_rate", 30)
if src_framerate <= 30:
target_fps = Fraction(int(media_info.get("video_frame_rate_n", 30)), int(media_info.get("video_frame_rate_d", 1)))
if target_fps <= 30:
target_rate = VIDEO_BITRATES[codec][25].get(resolution)
else:
target_rate = VIDEO_BITRATES[codec][60].get(resolution)
@ -687,8 +707,6 @@ def produce_ffmpeg_commands(media_file, media_info, resolution, codec, output_fi
# target_fps = 25
# else:
# adjust the target frame rate if the input is fractional
target_fps = src_framerate if isinstance(src_framerate, int) else math.ceil(src_framerate)
if media_info.get("video_duration") > CRF_ENCODING_NUM_SECONDS:
enc_type = "crf"
@ -700,6 +718,7 @@ def produce_ffmpeg_commands(media_file, media_info, resolution, codec, output_fi
elif enc_type == "crf":
passes = [2]
cmds = []
for pass_number in passes:
cmds.append(
@ -738,4 +757,4 @@ def clean_query(query):
for char in chars:
query = query.replace(char, "")
return query.lower()
return query.lower()