noaa-goes-visualization/ffmpeg_video.py

76 lines
No EOL
3.1 KiB
Python

import subprocess
import os
import shutil
import datetime
import time
import calendar
import numpy as np
from sortedcontainers import SortedDict
import tqdm
from PIL import Image
path_to_images = r"..\composite\goes18"
temp_path = r"..\vid"
output_file = r"..\goes18_2024.mp4"
interp_file = r"..\goes18_2024_interp.mp4"
ffmpeg_path = r"..\ffmpeg.exe"
starttime = calendar.timegm(datetime.datetime(2024, 1, 1, tzinfo=datetime.timezone.utc).timetuple())
stoptime = calendar.timegm(datetime.datetime(2025, 1, 1, tzinfo=datetime.timezone.utc).timetuple())
min_file_size = 350000 # Detect and remove corrupted files by filtering by file size
max_file_size = 450000
encoding_crf = 16
max_frame_interp = 1000
os.makedirs(temp_path, exist_ok = True)
black_image = Image.fromarray(np.zeros((1080, 1920, 3), dtype='uint8'))
files_by_time = SortedDict()
for root, dirs, files in tqdm.tqdm(os.walk(path_to_images), desc="Finding and filtering files."):
for f in files:
if f.endswith('.jpg'):
fpath = os.path.join(root, f)
fsize = os.path.getsize(fpath)
time_chunk = f.replace('-', '.').replace('_', '.').split('.')[1]
ftime = int(time_chunk)
if (fsize > min_file_size) and (fsize < max_file_size) and (ftime > starttime) and (ftime < stoptime):
files_by_time[ftime] = fpath
difftimes = np.diff(files_by_time.keys())
unique, counts = np.unique(difftimes, return_counts=True)
interval = unique[0]
assert np.sum((unique % interval) > 0) == 0 # Ensure all our timestamps align perfectly with our interval
prevtime = files_by_time.peekitem(0)[0] - interval
index = 0
newfpath = ""
for t, f in tqdm.tqdm(files_by_time.items(), desc="Copying files to transcode dir", total = len(files_by_time)):
framejump = (t - prevtime) // interval
if framejump < max_frame_interp:
for i in range(framejump - 1): # Fill black frames to fill gaps, these will later be interpolated with ffmpeg
black_image.save(f"{os.path.join(temp_path, f"{index+1:06d}.jpg")}", quality = 95)
index += 1
else: # Skip past intervals that are too large to fill reasonably
# This should never happen now that merger_FITS.py inserts black frames
print(f"Detected a frame gap of: {framejump}!")
newfpath = f"{os.path.join(temp_path, f"{index+1:06d}.jpg")}"
shutil.copy(f, newfpath)
prevtime = t
index += 1
command_line = f'{ffmpeg_path} -framerate 60 -pattern_type sequence -i "{os.path.join(temp_path, r"%06d.jpg")}" -c:v libx264 -crf {encoding_crf} -preset veryfast {output_file}'
print(command_line)
pipe = subprocess.Popen(command_line, shell=True, stdout=subprocess.PIPE).stdout
output = pipe.read().decode()
pipe.close()
shutil.rmtree(temp_path)
command_line = f'{ffmpeg_path} -i {output_file} -vf blackframe=0,metadata=select:key=lavfi.blackframe.pblack:value=95:function=less,minterpolate=mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1:me=fss -c:a copy -c:v libx264 -crf {encoding_crf} -preset veryfast {interp_file}'
print(command_line)
pipe = subprocess.Popen(command_line, shell=True, stdout=subprocess.PIPE).stdout
output = pipe.read().decode()
pipe.close()