Last active
September 14, 2023 22:10
-
-
Save asdfgeoff/62b155ee4ea6b81c9175c39ec2d22e9a to your computer and use it in GitHub Desktop.
Bulk compress phone videos using H.265 HEVC encoding 🔥 More info: https://geoffruddock.com/bulk-compress-videos-x265-with-ffmpeg/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import click | |
from pathlib import Path | |
from subprocess import call, check_output | |
from tqdm import tqdm | |
@click.command() | |
@click.argument('directory', type=click.Path(exists=True)) | |
@click.option('--recursive', is_flag=True, help='Recursive') | |
@click.option('--file-ext', help='File format to process') | |
def main(directory, file_ext='mp4', recursive=False): | |
""" Compress h264 video files in a directory using libx265 codec with crf=28 | |
Args: | |
directory: the directory to scan for video files | |
file_ext: the file extension to consider for conversion | |
recursive: whether to search directory or all its contents | |
""" | |
if recursive: | |
video_files = [fp.absolute() for fp in Path(directory).rglob(f'*.{file_ext}')] | |
else: | |
video_files = [fp.absolute() for fp in Path(directory).glob(f'*.{file_ext}')] | |
check_codec_cmd = 'ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "{fp}"' | |
codecs = [] | |
for fp in tqdm(video_files, desc='Checking metadata', unit='videos'): | |
codecs.append(check_output(check_codec_cmd.format(fp=fp), shell=True).strip().decode('UTF-8')) | |
files_to_process = [fp for fp, codec in zip(video_files, codecs) if codec != 'hevc'] | |
print(f'\nTOTAL FILES FOUND ({len(video_files)})') | |
print(f'FILES TO PROCESS ({len(files_to_process)}):', [fp.name for fp in files_to_process], '\n') | |
if len(files_to_process) == 0: | |
raise click.Abort | |
else: | |
click.confirm('Do you want to continue?', abort=True) | |
for fp in tqdm(files_to_process, desc='Converting files', unit='videos'): | |
new_fp = fp.parent / f'temp_ffmpeg.mp4' | |
convert_cmd = f'ffmpeg -i "{fp}" -map_metadata 0 -vcodec libx265 -crf 28 "{new_fp}"' | |
conversion_return_code = call(convert_cmd, shell=True) | |
if conversion_return_code == 0: | |
call(f'touch -r "{fp}" "{new_fp}"', shell=True) | |
call(f'mv "{new_fp}" "{fp}"', shell=True) | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment