Skip to content

Instantly share code, notes, and snippets.

@grinsted
Created March 28, 2025 09:16
Show Gist options
  • Select an option

  • Save grinsted/3dbc99b727fc15f5275024fa8ee06513 to your computer and use it in GitHub Desktop.

Select an option

Save grinsted/3dbc99b727fc15f5275024fa8ee06513 to your computer and use it in GitHub Desktop.
compress phone videos to make space
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import subprocess\n",
"import glob\n",
"import os\n",
"from tqdm.notebook import trange, tqdm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"def has_been_compressed(file):\n",
" command = ['ffprobe','-v','0','-show_entries','format_tags','-i',file]\n",
" q = subprocess.run(command,capture_output=True,text=True)\n",
" return (q.stdout.find(\"ffmpeg_ag\")>=0)\n",
"\n",
"def check_integrity(file):\n",
" command = ['ffmpeg','-v','error','-i',file,'-f','null','-']\n",
" q = subprocess.run(command,capture_output=True,text=True)\n",
" if not (q.returncode==0):\n",
" print(file, q.stderr)\n",
" return (q.returncode==0)\n",
"\n",
"def compress_a_video(infile, outfile):\n",
" command = ['ffmpeg', '-y', '-i', infile, #y to overwrite\n",
" \"-hide_banner\",\"-loglevel\",\"error\",\n",
" \"-c:v\", \"libx265\", \"-vtag\", \"hvc1\", \"-vf\", \"scale='min(max(iw/2,1280),iw)':-1\",\n",
" \"-map_metadata\", \"0\", \"-movflags\", \"use_metadata_tags\",\n",
" \"-copytb\", \"1\", \"-c:a\", \"copy\", \n",
" \"-movflags\",\"+faststart\",\n",
" \"-metadata:g\",\"encoding_tool=ffmpeg_ag\",\n",
" outfile]\n",
" #compress\n",
" print(\" \".join(command))\n",
" subprocess.run(command,stdin=subprocess.DEVNULL)\n",
" #copy filecreate/modify timestamps:\n",
" os.utime(outfile, (os.path.getctime(infile), os.path.getmtime(infile)))\n",
" newsize =os.path.getsize(outfile)\n",
" oldsize =os.path.getsize(infile)\n",
" print(f'{infile}: {newsize*100/oldsize:.0f}%')\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"rootfolder = r'Y:\\device\\DCIM\\2024'\n",
"outputfolder = 'localoutput'\n",
"write_it_back = False #not implemented yet. Go for manual move back\n",
"for infile in tqdm(glob.glob(\"**/*.mp4\", root_dir=rootfolder, recursive=True)):\n",
" outfile = os.path.join(outputfolder, infile)\n",
" infile = os.path.join(rootfolder, infile)\n",
" basename = os.path.basename(infile)\n",
" if has_been_compressed(infile):\n",
" print(f'{basename} skipped as it is compressed')\n",
" continue\n",
" if os.path.exists(outfile):\n",
" if has_been_compressed(outfile):\n",
" if check_integrity(outfile): \n",
" print(f'{basename} skipped - outfile already exists and is compressed!! {basename}')\n",
" continue\n",
" os.remove(outfile)\n",
" os.makedirs(os.path.dirname(outfile), exist_ok=True)\n",
" compress_a_video(infile, outfile)\n",
" if write_it_back:\n",
" if check_integrity(outfile):\n",
" 1/0\n",
" #todo: copy and replace\n",
" #check integrity/filesize or hash.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment