Skip to content

Instantly share code, notes, and snippets.

@MrYakobo
Created March 25, 2025 21:02
Show Gist options
  • Save MrYakobo/67a59a5d8d08a6b2f9f88296d7bf3807 to your computer and use it in GitHub Desktop.
Save MrYakobo/67a59a5d8d08a6b2f9f88296d7bf3807 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import subprocess
import json
import os
import math
import sys
def human_readable_size(size_bytes):
"""Convert bytes to human-readable file size."""
if size_bytes == 0:
return "0B"
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
i = int(math.floor(math.log(size_bytes, 1024)))
p = math.pow(1024, i)
s = round(size_bytes / p, 2)
return f"{s} {size_name[i]}"
def human_readable_duration(seconds):
"""Convert seconds to hours:minutes:seconds format."""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
def get_media_info(file_path):
"""
Extract detailed media file information using ffprobe.
Args:
file_path (str): Path to the media file
Returns:
dict: Parsed media file information
"""
try:
# Command to get JSON output from ffprobe
command = [
'ffprobe',
'-v', 'quiet',
'-print_format', 'json',
'-show_format',
'-show_streams',
file_path
]
# Run the command and capture output
result = subprocess.run(command, capture_output=True, text=True, check=True)
# Parse JSON output
media_info = json.loads(result.stdout)
# Prepare a more readable output
readable_info = {
'File Details': {
'Filename': os.path.basename(file_path),
'Full Path': file_path,
'File Size': human_readable_size(int(media_info['format'].get('size', 0))),
},
'Format': media_info['format'].get('format_name', 'Unknown'),
'Duration': human_readable_duration(float(media_info['format'].get('duration', 0))),
'Streams': []
}
# Process stream information
for stream in media_info.get('streams', []):
stream_info = {
'Type': stream.get('codec_type', 'Unknown'),
'Codec': stream.get('codec_name', 'Unknown'),
}
# Add specific details based on stream type
if stream.get('codec_type') == 'video':
stream_info.update({
'Resolution': f"{stream.get('width', 'N/A')}x{stream.get('height', 'N/A')}",
'Framerate': stream.get('avg_frame_rate', 'N/A'),
'Pixel Format': stream.get('pix_fmt', 'Unknown')
})
elif stream.get('codec_type') == 'audio':
stream_info.update({
'Sample Rate': stream.get('sample_rate', 'N/A'),
'Channels': stream.get('channels', 'N/A'),
'Channel Layout': stream.get('channel_layout', 'Unknown')
})
readable_info['Streams'].append(stream_info)
return readable_info
except subprocess.CalledProcessError as e:
print(f"Error running ffprobe: {e}")
return None
except json.JSONDecodeError:
print("Error parsing ffprobe output")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
def main():
"""
Main function to process media file information.
Accepts file path as a command-line argument.
"""
import math # Imported here to avoid global import
if len(sys.argv) < 2:
print("Usage: python script.py <media_file_path>")
sys.exit(1)
file_path = sys.argv[1]
if not os.path.exists(file_path):
print(f"File not found: {file_path}")
sys.exit(1)
# Get and print media information
media_info = get_media_info(file_path)
if media_info:
# Pretty print the media information
print("Media File Information:")
print("=" * 40)
# File Details
print("\nFile Details:")
for key, value in media_info['File Details'].items():
print(f"{key}: {value}")
# Format and Duration
print(f"\nFormat: {media_info['Format']}")
print(f"Duration: {media_info['Duration']}")
# Streams
print("\nStreams:")
for i, stream in enumerate(media_info['Streams'], 1):
print(f"\nStream {i}:")
for key, value in stream.items():
print(f"{key}: {value}")
if __name__ == "__main__":
main()
@MrYakobo
Copy link
Author

Media File Information:
========================================

File Details:
Filename: pokemon_s12_h-264_se_18.mp4
Full Path: pokemon_s12_h-264_se_18.mp4
File Size: 76.14 MB

Format: mov,mp4,m4a,3gp,3g2,mj2
Duration: 00:23:24

Streams:

Stream 1:
Type: video
Codec: h264
Resolution: 480x360
Framerate: 25/1
Pixel Format: yuv420p

Stream 2:
Type: audio
Codec: aac
Sample Rate: 48000
Channels: 2
Channel Layout: stereo

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