forked from LBRYCommunity/lbry-sdk
make bit_rate check support maximum
This commit is contained in:
parent
19ce0ab246
commit
a3294d4a0d
4 changed files with 28 additions and 20 deletions
10
lbry/conf.py
10
lbry/conf.py
|
@ -467,12 +467,16 @@ class TranscodeConfig(BaseConfig):
|
||||||
ffmpeg_folder = String('The path to ffmpeg and ffprobe', '')
|
ffmpeg_folder = String('The path to ffmpeg and ffprobe', '')
|
||||||
video_encoder = String('FFmpeg codec and parameters for the video encoding. '
|
video_encoder = String('FFmpeg codec and parameters for the video encoding. '
|
||||||
'Example: libaom-av1 -crf 25 -b:v 0 -strict experimental',
|
'Example: libaom-av1 -crf 25 -b:v 0 -strict experimental',
|
||||||
'libx264 -crf 18 -vf "format=yuv420p"')
|
'libx264 -crf 21 -preset faster -pix_fmt yuv420p')
|
||||||
|
video_bitrate_maximum = Integer('Maximum bits per second allowed for video streams (0 to disable).', 8400000)
|
||||||
|
video_scaler = String('FFmpeg scaling parameters for reducing bitrate. '
|
||||||
|
'Example: -vf "scale=-2:720,fps=24" -maxrate 5M -bufsize 3M',
|
||||||
|
'-vf "scale=if(gte(iw\,ih)\,min(2560\,iw)\,-2):if(lt(iw\,ih)\,min(2560\,ih)\,-2)" -maxrate 8400K -bufsize 5000K')
|
||||||
audio_encoder = String('FFmpeg codec and parameters for the audio encoding. '
|
audio_encoder = String('FFmpeg codec and parameters for the audio encoding. '
|
||||||
'Example: libopus -b:a 128k',
|
'Example: libopus -b:a 128k',
|
||||||
'aac -b:a 192k')
|
'aac -b:a 160k')
|
||||||
volume_filter = String('FFmpeg filter for audio normalization.', '-af loudnorm')
|
volume_filter = String('FFmpeg filter for audio normalization.', '-af loudnorm')
|
||||||
volume_analysis_time = Integer('Maximum seconds into the file that we examine audio volume (0 to disable).', '240')
|
volume_analysis_time = Integer('Maximum seconds into the file that we examine audio volume (0 to disable).', 240)
|
||||||
|
|
||||||
|
|
||||||
class CLIConfig(TranscodeConfig):
|
class CLIConfig(TranscodeConfig):
|
||||||
|
|
|
@ -97,24 +97,21 @@ class VideoFileAnalyzer:
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
def _verify_bitrate(self, scan_data: json, file_path):
|
||||||
def _verify_bitrate(scan_data: json):
|
bit_rate_max = float(self._conf.video_bitrate_maximum)
|
||||||
if "bit_rate" not in scan_data["format"]:
|
if bit_rate_max <= 0:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
bit_rate = float(scan_data["format"]["bit_rate"])
|
if "bit_rate" in scan_data["format"]:
|
||||||
log.debug(" Detected bitrate is %s Mbps", str(bit_rate / 1000000.0))
|
bit_rate = float(scan_data["format"]["bit_rate"])
|
||||||
pixels = -1.0
|
else:
|
||||||
for stream in scan_data["streams"]:
|
bit_rate = os.stat(file_path).st_size / float(scan_data["format"]["duration"])
|
||||||
if stream["codec_type"] == "video":
|
log.debug(" Detected bitrate is %s Mbps. Allowed is %s Mbps",
|
||||||
pieces = stream["r_frame_rate"].split('/', 1)
|
str(bit_rate / 1000000.0), str(bit_rate_max / 1000000.0))
|
||||||
frame_rate = float(pieces[0]) if len(pieces) == 1 \
|
|
||||||
else float(pieces[0]) / float(pieces[1])
|
|
||||||
pixels = max(pixels, float(stream["height"]) * float(stream["width"]) * frame_rate)
|
|
||||||
|
|
||||||
if pixels > 0.0 and pixels / bit_rate < 3.0:
|
if bit_rate > bit_rate_max:
|
||||||
return "Bits per second is excessive for this data; this may impact web streaming performance. " \
|
return "The bit rate is above the configured maximum. Actual: " \
|
||||||
f"Actual: {str(bit_rate / 1000000.0)} Mbps"
|
f"{bit_rate / 1000000.0} Mbps; Allowed: {bit_rate_max / 1000000.0} Mbps"
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -178,6 +175,9 @@ class VideoFileAnalyzer:
|
||||||
# https://developers.google.com/media/vp9/settings/vod/
|
# https://developers.google.com/media/vp9/settings/vod/
|
||||||
return int(-0.011 * height + 40)
|
return int(-0.011 * height + 40)
|
||||||
|
|
||||||
|
def _get_video_scaler(self):
|
||||||
|
return self._conf.video_scaler
|
||||||
|
|
||||||
async def _get_video_encoder(self, scan_data):
|
async def _get_video_encoder(self, scan_data):
|
||||||
# use what the user said if it's there:
|
# use what the user said if it's there:
|
||||||
# if it's not there, use h264 if we can because it's way faster than the others
|
# if it's not there, use h264 if we can because it's way faster than the others
|
||||||
|
@ -297,7 +297,7 @@ class VideoFileAnalyzer:
|
||||||
log.debug("Analyzing %s:", file_path)
|
log.debug("Analyzing %s:", file_path)
|
||||||
log.debug(" Detected faststart is %s", "false" if fast_start_msg else "true")
|
log.debug(" Detected faststart is %s", "false" if fast_start_msg else "true")
|
||||||
container_msg = self._verify_container(scan_data)
|
container_msg = self._verify_container(scan_data)
|
||||||
bitrate_msg = self._verify_bitrate(scan_data)
|
bitrate_msg = self._verify_bitrate(scan_data, file_path)
|
||||||
video_msg = self._verify_video_encoding(scan_data)
|
video_msg = self._verify_video_encoding(scan_data)
|
||||||
audio_msg = self._verify_audio_encoding(scan_data)
|
audio_msg = self._verify_audio_encoding(scan_data)
|
||||||
volume_msg = await self._verify_audio_volume(self._conf.volume_analysis_time, file_path)
|
volume_msg = await self._verify_audio_volume(self._conf.volume_analysis_time, file_path)
|
||||||
|
@ -323,6 +323,8 @@ class VideoFileAnalyzer:
|
||||||
if video_msg or bitrate_msg:
|
if video_msg or bitrate_msg:
|
||||||
video_encoder = await self._get_video_encoder(scan_data)
|
video_encoder = await self._get_video_encoder(scan_data)
|
||||||
transcode_command.append(video_encoder)
|
transcode_command.append(video_encoder)
|
||||||
|
# could do the scaling only if bitrate_msg, but if we're going to the effort to re-encode anyway...
|
||||||
|
transcode_command.append(self._get_video_scaler())
|
||||||
else:
|
else:
|
||||||
transcode_command.append("copy")
|
transcode_command.append("copy")
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,6 @@ types_map = {
|
||||||
|
|
||||||
|
|
||||||
def guess_media_type(path):
|
def guess_media_type(path):
|
||||||
# should we be using "file --mime-type -b $filename" on linux?
|
|
||||||
_, ext = os.path.splitext(path)
|
_, ext = os.path.splitext(path)
|
||||||
extension = ext.strip().lower()
|
extension = ext.strip().lower()
|
||||||
if extension[1:]:
|
if extension[1:]:
|
||||||
|
|
|
@ -220,6 +220,9 @@ class IntegrationTestCase(AsyncioTestCase):
|
||||||
self.account: Optional[Account] = None
|
self.account: Optional[Account] = None
|
||||||
|
|
||||||
async def asyncSetUp(self):
|
async def asyncSetUp(self):
|
||||||
|
if sys.version_info < (3, 8):
|
||||||
|
# hide warning about TaskWakeupMethWrapper, see bugs.python.org/issue38608
|
||||||
|
asyncio.get_running_loop().set_debug(False)
|
||||||
self.conductor = Conductor(seed=self.SEED)
|
self.conductor = Conductor(seed=self.SEED)
|
||||||
await self.conductor.start_blockchain()
|
await self.conductor.start_blockchain()
|
||||||
self.addCleanup(self.conductor.stop_blockchain)
|
self.addCleanup(self.conductor.stop_blockchain)
|
||||||
|
|
Loading…
Add table
Reference in a new issue