From bd225d1c83c8945871f9e43bb18bad61e5bb7744 Mon Sep 17 00:00:00 2001 From: Jeremy Karst Date: Tue, 4 Jun 2024 17:17:06 -0400 Subject: [PATCH] Changed ffmpeg to encode video while reading images from pipe instead of writing images to temp dir. --- ffmpeg_video.py | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/ffmpeg_video.py b/ffmpeg_video.py index c122be0..cff9720 100644 --- a/ffmpeg_video.py +++ b/ffmpeg_video.py @@ -10,20 +10,22 @@ 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" +path_to_images = r"..\composite\goes16" +output_file = r"..\goes16_2024.mp4" +interp_file = r"..\goes16_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 +max_frame_interp = 120 +# Set up ffmpeg to stream images from an input pipe +command_line = f'{ffmpeg_path} -y -f image2pipe -framerate 60 -i - -c:v libx264 -crf {encoding_crf} -preset veryfast {output_file}' +print(command_line) +p = subprocess.Popen(command_line, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) -os.makedirs(temp_path, exist_ok = True) black_image = Image.fromarray(np.zeros((1080, 1920, 3), dtype='uint8')) files_by_time = SortedDict() @@ -43,32 +45,21 @@ 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)): +for t, f in tqdm.tqdm(files_by_time.items(), desc="FFMPEG encoding images", 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 + black_image.save(p.stdin, 'jpeg', quality = 95) 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) + with open(f, 'rb') as fh: + p.stdin.write(fh.read()) 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) +p.stdin.close() # Close the ffmpeg input pipe +p.wait() # Wait for ffmpeg to finish encoding -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}' +command_line = f'{ffmpeg_path} -y -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