Skip to content

Instantly share code, notes, and snippets.

@Deathproof76
Last active August 25, 2023 12:13
Show Gist options
  • Save Deathproof76/76f5c087a15bcdcaeeeed3c59228766b to your computer and use it in GitHub Desktop.
Save Deathproof76/76f5c087a15bcdcaeeeed3c59228766b to your computer and use it in GitHub Desktop.
Check video files with ffprobe if there is only one i-frame in the first 20 seconds of the file
import os
import subprocess
import time
import sys
import select
def rename_defective_file(filepath):
"""Rename the defective file by appending '_(i_frame_defect)' before the file extension."""
root, ext = os.path.splitext(filepath)
new_name = f"{root}_(i_frame_defect){ext}"
os.rename(filepath, new_name)
return new_name
# Detailed introductory message
print("DESCRIPTION:")
print("------------")
print("This script will recursively search the current directory and its subdirectories for video files.")
print("Each video file will be checked using 'ffprobe' to determine if there's only one I-frame in the first 20 seconds.")
print("Files with only one I-frame in the first 20 seconds will be deemed 'defective'.")
# Provide options to the user
print("\nOPTIONS:")
print("1. Just output the full path of affected files to 'defect_files.txt'.")
print("2. Output the full path of affected files to 'defect_files.txt' and rename the defective files by appending '_(i_frame_defect)' to their filename.")
# Get user's choice
choice = input("\nChoose an option (1/2): ")
# Get a list of all video files in the current directory and subdirectories
video_extensions = ['.mp4', '.mkv', '.avi']
video_files = [os.path.join(root, file)
for root, dirs, files in os.walk('.')
for file in files if os.path.splitext(file)[1] in video_extensions]
defective_files = []
# Check each video file with ffprobe for I-frames in the first 20 seconds
for index, video_file in enumerate(video_files, start=1):
print(f"Checking file {index}/{len(video_files)}: {video_file}")
command = [
'ffprobe',
'-select_streams', 'v',
'-show_frames',
'-read_intervals', '%+#20',
'-of', 'csv=p=0',
'-i', video_file
]
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = result.stdout.decode('utf-8')
i_frames = sum(1 for line in output.splitlines() if line.split(',')[1] == 'I')
if i_frames == 1:
if choice == '2':
video_file = rename_defective_file(video_file)
defective_files.append(os.path.abspath(video_file))
# Write all defective file paths to defect_files.txt, each on a new line
with open('defect_files.txt', 'w') as f:
for file in defective_files:
f.write(file + '\n')
# Write all defective file paths to defect_files_one_line.txt in a single line
with open('defect_files_one_line.txt', 'w') as f:
f.write(' '.join(defective_files))
print(f"\nFinished checking. Found {len(defective_files)} files with only one I-frame in the first 20 seconds.")
print(f"Check 'defect_files.txt' and 'defect_files_one_line.txt' for lists of defective files.")
@Deathproof76
Copy link
Author

Deathproof76 commented Aug 25, 2023

ffmpeg6 with libvpl (onevpl) can produce files with a broken gop, when using qsv to encode to hevc because of bad default settings. Files have only a single i-frame. Even though the files seem intact, the have problems when seeking(long buffering, the bigger the file the worse). This script identifies those files and outputs the full filepath to a txt file for batch ops.

first option: filepaths to txt file
second option: same + rename the affected files by appending _(iframe_defect) between filename and extension

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment