def render_video(recording, output, dry, quality, audio_bitrate): start = time.time() logging.debug("Rendering video from frame %s to %s", str(recording.start_frame), str(recording.end_frame)) if dry: recording.sorted_location = "** DRY RUN **" return recording.sorted_location = get_next_filename( os.path.join(output, recording.matched_model)) ffmpeg = FFmpeg().input(recording.original_location).output( recording.sorted_location, { 'codec:v': 'libx265', 'codec:a': 'eac3', 'tag:v': 'hvc1', 'preset': 'fast', 'crf': quality, 'b:a': audio_bitrate, 'vf': f'scale={recording.dimension}:flags=lanczos', 'ss': calculate_timestamp_fps(recording.start_frame, recording.fps), 'to': calculate_timestamp_fps(recording.end_frame, recording.fps) }) @ffmpeg.on('progress') def on_progress(progress): progressbar.update_to(progress.frame) if recording.average_bitrate == 0: recording.average_bitrate = progress.bitrate else: recording.average_bitrate = round( (recording.average_bitrate + progress.bitrate) / 2) @ffmpeg.on('terminated') def on_terminated(): raise Exception('ffmpeg was externally terminated') @ffmpeg.on('error') def on_error(code): raise Exception('ffmpeg exited with ' + code) loop = asyncio.get_event_loop() tqdm_out = TqdmToLogger(logging.getLogger(), level=logging.INFO) progressbar = TqdmUpTo(total=recording.end_frame - recording.start_frame + 1, desc="Rendering video", unit="frame", file=tqdm_out, bar_format='{l_bar}{bar:50}{r_bar}{bar:-50b}', ascii=False) loop.run_until_complete(ffmpeg.execute()) progressbar.close() logging.debug("Finished rendering in in %ss", str(round(time.time() - start, 2)))
def compare(path=u'../02-cut-00.mp4', width=1280, height=720, vcodec='libx264', preset='faster', crf=23): ffmpeg = FFmpeg(path=path) output = '%s/%s.%s' % (ffmpeg.root, preset, ffmpeg.attr) cmd = 'ffmpeg.exe -i "%s" -s %dx%d -vcodec %s -preset %s -crf %d "%s"' % ( ffmpeg.path, width, height, vcodec, preset, crf, output) cost = ffmpeg.execute(cmd) return cost
from ffmpeg import FFmpeg import asyncio import sys ffscale = FFmpeg() @ffscale.on('completed') def on_complete(): print("completed") # @ffscale.on('progress') # def on_ffprobe_progress(progress): # print(progress.resolution) new_file = sys.argv[1] + "_scale" filter_scale = "scale=" + sys.argv[2] ffscale.input(sys.argv[1]) ffscale.output(new_file, {'filter_complex': filter_scale}, f='mp4') loop = asyncio.get_event_loop() loop.run_until_complete(ffscale.execute()) loop.close()
def download(self): metadata = None track_image_path = None asyncio.set_event_loop(asyncio.new_event_loop()) loop = asyncio.get_event_loop() if self.metadata_filepath is not None: if self.is_album: tg = TitleGenerator(self.metadata_filepath, self.artist) else: tg = TitleGenerator(self.metadata_filepath, self.artist, no_album=True) tg.make_titles() metadata = tg.get_titles() for num, url in self.urls: yt = None image_dl_failed = False failed_image_url = "" self.cur_song = num + self.start + 1 try: if self.proxies is not None: yt = YouTube(url, proxies=self.proxies) else: yt = YouTube(url) except Exception as e: self.retry_urls.append((num, url)) print( f"Downloading song {font.apply('gb', str(self.cur_song))} - {font.apply('bf', '[Failed - ')} {font.apply('bf', str(e) + ']')}\n" ) continue path = None try: yt.register_on_progress_callback(self.progress_function) self.cur_video = (yt.streams.filter( type="audio", subtype="mp4").order_by("abr").desc().first()) safe_name = extract_title( make_safe_filename(self.cur_video.title)) path = self.cur_video.download( output_path=self.outdir, filename=safe_name, ) self.successful_filepaths.append(path) self.successful += 1 except (Exception, KeyboardInterrupt) as e: self.retry_urls.append((num, url)) print( f"Downloading song {font.apply('gb',str(self.cur_song))+' - '+font.apply('gb', self.cur_video.title)} - {font.apply('bf', '[Failed - ')} {font.apply('bf', str(e) + ']')}\n" ) continue # if self.is_album: # if self.image_filepath is None: # if not self.album_image_set: # image_path = Downloader.download_image( # yt.thumbnail_url, num, self.outdir # ) # self.images.append(image_path) # self.image_filepath = image_path # self.album_image_set = True # else: # image_path = Downloader.download_image(yt.thumbnail_url, num, self.outdir) # self.images.append(image_path) # self.image_filepath = image_path track_title = None track_artist = None if metadata is not None: t = metadata[num] track_title = t.title if not t.unused else self.cur_video.title track_artist = t.artist if not t.unused else self.artist track_album = self.album track_image_path = self.image_filepath if t.image_path is not None: if not is_url(t.image_path): track_image_path = t.image_path else: try: track_image_path = Downloader.download_image( t.image_path, num, self.outdir) self.to_delete.append(track_image_path) num = 0 # track num should always be 1 if downloading a single except error.ImageDownloadError as e: image_dl_failed = True failed_image_url = t.image_path else: if self.image_filepath is not None: try: track_image_path = Downloader.download_image( self.image_filepath, num, self.outdir) self.to_delete.append(track_image_path) num = 0 # track num should always be 1 if downloading a single except error.ImageDownloadError as e: image_dl_failed = True failed_image_url = self.image_filepath if not self.is_album: track_album = t.album else: track_title = self.cur_video.title track_artist = self.artist track_album = self.album if self.image_filepath is not None: if not is_url(self.image_filepath): track_image_path = self.image_filepath else: try: track_image_path = Downloader.download_image( self.image_filepath, num, self.outdir) self.to_delete.append(track_image_path) except error.ImageDownloadError as e: image_dl_failed = True failed_image_url = self.image_filepath metadata_branch = "├──" if self.mp3 else "└──" try: if image_dl_failed: raise error.ImageDownloadError(failed_image_url) self.apply_metadata( num + 1, self.total_songs, path, track_album, track_title, track_artist, track_image_path, ) print( f"{metadata_branch} Applying metadata - {font.apply('bl', '[Done]')}" ) except (Exception, KeyboardInterrupt) as e: print( f"{metadata_branch} Applying metadata - {font.apply('bf', '[Failed - ')} {font.apply('bf', str(e) + ']')}" ) if self.mp3: ffmpeg = FFmpeg().input(path).output( f"{extract_title(path)}.mp3") @ffmpeg.on("progress") def mp3_conv_progress(event): p = (to_sec(event.time) / int(yt.length)) * 100 progress = ( f"└── Converting to mp3 - [{p:.2f}%]" if p < 100 else f"└── Converting to mp3 - {font.apply('bl', '[Done] ')}" ) end = "\n" if p >= 100 else "\r" print(progress, end=end, flush=True) try: loop.run_until_complete(ffmpeg.execute()) os.remove(f"{extract_title(path)}.mp4") path = f"{extract_title(path)}.mp3" except (Exception, KeyboardInterrupt) as e: print( f"└── Converting to mp3 - {font.apply('bf', '[Failed - ')} {font.apply('bf', str(e) + ']')}" ) print(" ") loop.close() for image in self.to_delete: os.remove(image)
from ffmpeg import FFmpeg import asyncio import sys resolution = "" ffmpeg = FFmpeg() @ffmpeg.on('progress') def on_ffmpeg_progress(progress): if 'VMAF' in progress._fields: print(progress.VMAF) ffmpeg.input(sys.argv[1]) ffmpeg.input(sys.argv[2]) ffmpeg.output("-", {'filter_complex': 'libvmaf'}, f="null") loop = asyncio.get_event_loop() loop.run_until_complete(ffmpeg.execute()) loop.close()
from ffmpeg import FFmpeg import asyncio import sys resolution = "" ffprobe = FFmpeg(executable='ffprobe') @ffprobe.on('progress') def on_ffprobe_progress(progress): if 'resolution' in progress._fields: resolution = progress.resolution.replace("\n", "").replace("\r", "") print(resolution) ffprobe.input(sys.argv[1]) loop = asyncio.get_event_loop() loop.run_until_complete(ffprobe.execute()) loop.close()