From 71f896539322b92ad37400d520864a6ff81eb3ce Mon Sep 17 00:00:00 2001 From: Brannon King Date: Thu, 26 Mar 2020 07:53:13 -0600 Subject: [PATCH] re-use ffprobe info in stream_type avoid duplicate args handle review comment --- lbry/extras/daemon/daemon.py | 7 +++-- lbry/file_analysis.py | 35 +++++++++++++++++---- lbry/schema/claim.py | 2 +- scripts/check_video.py | 2 +- tests/integration/other/test_transcoding.py | 17 +++++----- 5 files changed, 46 insertions(+), 17 deletions(-) diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index 4196f9491..0411e99a5 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -3168,9 +3168,11 @@ class Daemon(metaclass=JSONRPCServerType): f"Use --allow-duplicate-name flag to override." ) - file_path = await self._video_file_analyzer.verify_or_repair( + file_path, spec = await self._video_file_analyzer.verify_or_repair( validate_file, optimize_file, file_path, ignore_non_video=True ) + kwargs.update(spec) + claim = Claim() claim.stream.update(file_path=file_path, sd_hash='0' * 96, **kwargs) tx = await Transaction.claim_create( @@ -3364,9 +3366,10 @@ class Daemon(metaclass=JSONRPCServerType): if fee_address: kwargs['fee_address'] = fee_address - file_path = await self._video_file_analyzer.verify_or_repair( + file_path, spec = await self._video_file_analyzer.verify_or_repair( validate_file, optimize_file, file_path, ignore_non_video=True ) + kwargs.update(spec) if replace: claim = Claim() diff --git a/lbry/file_analysis.py b/lbry/file_analysis.py index 4645e797e..982a75e35 100644 --- a/lbry/file_analysis.py +++ b/lbry/file_analysis.py @@ -341,23 +341,46 @@ class VideoFileAnalyzer: return scan_data + @staticmethod + def _build_spec(scan_data): + assert scan_data + + duration = float(scan_data["format"]["duration"]) # existence verified when scan_data made + width = -1 + height = -1 + for stream in scan_data["streams"]: + if stream["codec_type"] != "video": + continue + width = max(width, int(stream["width"])) + height = max(height, int(stream["height"])) + + log.debug(" Detected duration: %f sec. with resolution: %d x %d", duration, width, height) + + spec = {"duration": duration} + if height >= 0: + spec["height"] = height + if width >= 0: + spec["width"] = width + return spec + async def verify_or_repair(self, validate, repair, file_path, ignore_non_video=False): if not validate and not repair: - return file_path + return file_path, {} if ignore_non_video and not file_path: - return file_path + return file_path, {} await self._verify_ffmpeg_installed() try: scan_data = await self._get_scan_data(validate, file_path) except ValueError: if ignore_non_video: - return file_path + return file_path, {} raise fast_start_msg = await self._verify_fast_start(scan_data, file_path) log.debug("Analyzing %s:", file_path) + spec = self._build_spec(scan_data) log.debug(" Detected faststart is %s", "false" if fast_start_msg else "true") container_msg = self._verify_container(scan_data) bitrate_msg = self._verify_bitrate(scan_data, file_path) @@ -367,7 +390,7 @@ class VideoFileAnalyzer: messages = [container_msg, bitrate_msg, fast_start_msg, video_msg, audio_msg, volume_msg] if not any(messages): - return file_path + return file_path, spec if not repair: errors = ["Streamability verification failed:"] @@ -418,6 +441,6 @@ class VideoFileAnalyzer: raise log.info("Unable to transcode %s . Message: %s", file_path, str(e)) # TODO: delete partial output file here if it exists? - return file_path + return file_path, spec - return str(output) + return str(output), spec diff --git a/lbry/schema/claim.py b/lbry/schema/claim.py index 560b52f64..6a81ff133 100644 --- a/lbry/schema/claim.py +++ b/lbry/schema/claim.py @@ -253,7 +253,7 @@ class Stream(BaseClaim): if stream_type in ('image', 'video', 'audio'): media = getattr(self, stream_type) media_args = {'file_metadata': None} - if file_path is not None: + if file_path is not None and not all((duration, width, height)): try: media_args['file_metadata'] = binary_file_metadata(binary_file_parser(file_path)) except: diff --git a/scripts/check_video.py b/scripts/check_video.py index c95fbf776..23e7f29e5 100755 --- a/scripts/check_video.py +++ b/scripts/check_video.py @@ -33,7 +33,7 @@ async def process_video(analyzer, video_file): transcode = input("Would you like to make a repaired clone now? [y/N] ") if transcode == "y": try: - new_video_file = await analyzer.verify_or_repair(True, True, video_file) + new_video_file, _ = await analyzer.verify_or_repair(True, True, video_file) print("Successfully created ", new_video_file) except Exception as e: print("Unable to complete the transcode. Message: ", str(e)) diff --git a/tests/integration/other/test_transcoding.py b/tests/integration/other/test_transcoding.py index 9a80fc8da..d671ace4d 100644 --- a/tests/integration/other/test_transcoding.py +++ b/tests/integration/other/test_transcoding.py @@ -52,12 +52,15 @@ class TranscodeValidation(ClaimTestCase): self.assertEqual(code, 0, output) async def test_should_work(self): - new_file_name = await self.analyzer.verify_or_repair(True, False, self.video_file_name) + new_file_name, _ = await self.analyzer.verify_or_repair(True, False, self.video_file_name) self.assertEqual(self.video_file_name, new_file_name) - new_file_name = await self.analyzer.verify_or_repair(True, False, self.video_file_ogg) + new_file_name, _ = await self.analyzer.verify_or_repair(True, False, self.video_file_ogg) self.assertEqual(self.video_file_ogg, new_file_name) - new_file_name = await self.analyzer.verify_or_repair(True, False, self.video_file_webm) + new_file_name, spec = await self.analyzer.verify_or_repair(True, False, self.video_file_webm) self.assertEqual(self.video_file_webm, new_file_name) + self.assertEqual(spec["width"], 1280) + self.assertEqual(spec["height"], 720) + self.assertEqual(spec["duration"], 15.054) async def test_volume(self): self.conf.volume_analysis_time = 200 @@ -75,7 +78,7 @@ class TranscodeValidation(ClaimTestCase): with self.assertRaisesRegex(Exception, "Container format is not in the approved list"): await self.analyzer.verify_or_repair(True, False, file_name) - fixed_file = await self.analyzer.verify_or_repair(True, True, file_name) + fixed_file, _ = await self.analyzer.verify_or_repair(True, True, file_name) pathlib.Path(fixed_file).unlink() async def test_video_codec(self): @@ -91,7 +94,7 @@ class TranscodeValidation(ClaimTestCase): with self.assertRaisesRegex(Exception, "faststart flag was not used"): await self.analyzer.verify_or_repair(True, False, file_name) - fixed_file = await self.analyzer.verify_or_repair(True, True, file_name) + fixed_file, _ = await self.analyzer.verify_or_repair(True, True, file_name) pathlib.Path(fixed_file).unlink() async def test_max_bit_rate(self): @@ -111,7 +114,7 @@ class TranscodeValidation(ClaimTestCase): with self.assertRaisesRegex(Exception, "pixel format does not match the approved"): await self.analyzer.verify_or_repair(True, False, file_name) - fixed_file = await self.analyzer.verify_or_repair(True, True, file_name) + fixed_file, _ = await self.analyzer.verify_or_repair(True, True, file_name) pathlib.Path(fixed_file).unlink() async def test_audio_codec(self): @@ -125,7 +128,7 @@ class TranscodeValidation(ClaimTestCase): with self.assertRaisesRegex(Exception, "Audio codec is not in the approved list"): await self.analyzer.verify_or_repair(True, False, file_name) - fixed_file = await self.analyzer.verify_or_repair(True, True, file_name) + fixed_file, _ = await self.analyzer.verify_or_repair(True, True, file_name) pathlib.Path(fixed_file).unlink() async def test_extension_choice(self):