220 lines · 7.4 KB
Raw Download
1
import subprocess
2
import json
3
import os
4
from collections import defaultdict
5
from pathlib import Path
6
7
# Common video file extensions
8
VIDEO_EXTENSIONS = {'.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.m4v', '.mpg', '.mpeg'}
9
10
def get_video_info(file_path):
11
    """
12
    Extract video bitrate and resolution using ffprobe with modified bitrate calculation
13
    """
14
    try:
15
        # First command to get stream information
16
        result = subprocess.run([
17
            'ffprobe', 
18
            '-v', 'quiet', 
19
            '-print_format', 'json', 
20
            '-show_streams', 
21
            '-select_streams', 'v:0', 
22
            file_path
23
        ], capture_output=True, text=True)
24
        
25
        # Second command specifically for bitrate using -count_packets
26
        bitrate_result = subprocess.run([
27
            'ffprobe',
28
            '-v', 'quiet',
29
            '-select_streams', 'v:0',
30
            '-show_entries', 'format=duration,size',
31
            '-print_format', 'json',
32
            file_path
33
        ], capture_output=True, text=True)
34
        
35
        probe_data = json.loads(result.stdout)
36
        bitrate_data = json.loads(bitrate_result.stdout)
37
        
38
        video_stream = probe_data['streams'][0]
39
        width = int(video_stream.get('width', 0))
40
        height = int(video_stream.get('height', 0))
41
        
42
        # Calculate bitrate from file size and duration
43
        try:
44
            duration = float(bitrate_data['format']['duration'])
45
            size_bits = float(bitrate_data['format']['size']) * 8
46
            bitrate = (size_bits / duration) / 1000  # Convert to kbps
47
        except (KeyError, ZeroDivisionError):
48
            # Fallback method using direct bit_rate if available
49
            bitrate = float(video_stream.get('bit_rate', 0)) / 1000
50
            if bitrate == 0:
51
                # Second fallback: try format bitrate
52
                format_result = subprocess.run([
53
                    'ffprobe',
54
                    '-v', 'quiet',
55
                    '-print_format', 'json',
56
                    '-show_format',
57
                    file_path
58
                ], capture_output=True, text=True)
59
                format_data = json.loads(format_result.stdout)
60
                bitrate = float(format_data['format'].get('bit_rate', 0)) / 1000
61
        
62
        return {
63
            'bitrate': bitrate,
64
            'width': width,
65
            'height': height,
66
            'path': file_path,
67
            'filename': os.path.basename(file_path),
68
            'size_mb': os.path.getsize(file_path) / (1024 * 1024)  # Convert to MB
69
        }
70
    
71
    except Exception as e:
72
        print(f"\nError analyzing video {file_path}: {e}")
73
        return None
74
75
def categorize_bitrate(video_info):
76
    """
77
    Categorize bitrate based on resolution and bitrate
78
    """
79
    width = video_info['width']
80
    height = video_info['height']
81
    bitrate = video_info['bitrate']
82
    pixels = width * height
83
    
84
    # Resolution categories and their bitrate thresholds
85
    categories = {
86
        '4K': {
87
            'pixels': (3840 * 2160, float('inf')),
88
            'thresholds': {
89
                'Low': (0, 10000),
90
                'Medium': (10000, 20000),
91
                'High': (20000, float('inf'))
92
            }
93
        },
94
        '1080p': {
95
            'pixels': (1920 * 1080, 3840 * 2160),
96
            'thresholds': {
97
                'Low': (0, 5000),
98
                'Medium': (5000, 10000),
99
                'High': (10000, float('inf'))
100
            }
101
        },
102
        '720p': {
103
            'pixels': (1280 * 720, 1920 * 1080),
104
            'thresholds': {
105
                'Low': (0, 2500),
106
                'Medium': (2500, 5000),
107
                'High': (5000, float('inf'))
108
            }
109
        },
110
        'SD': {
111
            'pixels': (0, 1280 * 720),
112
            'thresholds': {
113
                'Low': (0, 1000),
114
                'Medium': (1000, 2500),
115
                'High': (2500, float('inf'))
116
            }
117
        }
118
    }
119
    
120
    # Find resolution category
121
    resolution_category = None
122
    for res_name, res_info in categories.items():
123
        min_pixels, max_pixels = res_info['pixels']
124
        if min_pixels < pixels <= max_pixels:
125
            resolution_category = res_name
126
            break
127
    
128
    if not resolution_category:
129
        return None
130
    
131
    # Find bitrate category
132
    for bitrate_category, (min_rate, max_rate) in categories[resolution_category]['thresholds'].items():
133
        if min_rate <= bitrate < max_rate:
134
            return f"{resolution_category} - {bitrate_category}"
135
    
136
    return None
137
138
def find_video_files(folder_path):
139
    """
140
    Recursively find all video files in the given folder
141
    """
142
    video_files = []
143
    for path in Path(folder_path).rglob('*'):
144
        if path.suffix.lower() in VIDEO_EXTENSIONS:
145
            video_files.append(str(path))
146
    return video_files
147
148
def analyze_folder(folder_path):
149
    """
150
    Analyze all videos in a folder and return categorized results
151
    """
152
    print(f"Scanning folder: {folder_path}")
153
    
154
    # Find all video files
155
    video_files = find_video_files(folder_path)
156
    total_files = len(video_files)
157
    print(f"Found {total_files} video files")
158
    
159
    # Analyze each video
160
    categorized_videos = defaultdict(list)
161
    for i, file_path in enumerate(video_files, 1):
162
        print(f"\rAnalyzing video {i}/{total_files}: {os.path.basename(file_path)}", end='')
163
        
164
        video_info = get_video_info(file_path)
165
        if video_info:
166
            category = categorize_bitrate(video_info)
167
            if category:
168
                categorized_videos[category].append(video_info)
169
    
170
    print("\nAnalysis complete!")
171
    return categorized_videos
172
173
def display_results(categorized_videos):
174
    """
175
    Display categorized videos sorted by bitrate
176
    """
177
    print("\nVideo Analysis Results:")
178
    print("=" * 100)
179
    
180
    # Sort categories in order: 4K, 1080p, 720p, SD, each with High, Medium, Low
181
    category_order = []
182
    for res in ['4K', '1080p', '720p', 'SD']:
183
        for quality in ['High', 'Medium', 'Low']:
184
            category_order.append(f"{res} - {quality}")
185
    
186
    # Display results for each category
187
    for category in category_order:
188
        if category in categorized_videos:
189
            videos = categorized_videos[category]
190
            # Sort videos by bitrate (highest to lowest)
191
            videos.sort(key=lambda x: x['bitrate'], reverse=True)
192
            
193
            print(f"\n{category} Quality Videos:")
194
            print("-" * 100)
195
            print(f"{'Filename':<50} {'Resolution':<15} {'Bitrate':>10} {'Size':>10}")
196
            print("-" * 100)
197
            
198
            for video in videos:
199
                filename = video['filename']
200
                if len(filename) > 47:
201
                    filename = filename[:44] + "..."
202
                print(f"{filename:<50} {video['width']}x{video['height']:<15} {video['bitrate']:>8.0f}k {video['size_mb']:>8.1f}MB")
203
204
def main():
205
    # Prompt for folder path
206
    folder_path = input("Enter the folder path to analyze: ").strip('"')
207
    
208
    # Validate folder exists
209
    if not os.path.isdir(folder_path):
210
        print("Folder does not exist. Please check the path and try again.")
211
        return
212
    
213
    # Analyze videos
214
    categorized_videos = analyze_folder(folder_path)
215
    
216
    # Display results
217
    display_results(categorized_videos)
218
219
if __name__ == "__main__":
220
    main()