| import ffmpeg |
| import random |
| import string |
| from datetime import datetime |
| import os |
| |
| target_width = 1080 |
| target_height = 1920 |
|
|
|
|
|
|
| def concatenate_videos(files_timestamps): |
| processed_streams = [] |
| for file_info in files_timestamps: |
| file_path = file_info["path"] |
| start_time = file_info["start"] |
| end_time = file_info["end"] |
|
|
| try: |
| if end_time == "": |
| |
| stream = ffmpeg.input(file_path, ss=start_time) |
| else: |
| time_obj = datetime.strptime(start_time, "%M:%S.%f") |
| start_time = time_obj.minute * 60 + time_obj.second + time_obj.microsecond / 1_000_000 |
| time_obj = datetime.strptime(end_time, "%M:%S.%f") |
| end_time = time_obj.minute * 60 + time_obj.second + time_obj.microsecond / 1_000_000 |
| |
| stream = ffmpeg.input(file_path, ss=start_time, t=end_time - start_time) |
| video = stream.video |
| audio = stream.audio |
| |
| |
| probe = ffmpeg.probe(file_path) |
| video_stream = next(s for s in probe['streams'] if s['codec_type'] == 'video') |
| video_width = int(video_stream['width']) |
| video_height = int(video_stream['height']) |
| video_aspect = video_width / video_height |
| target_aspect = target_width / target_height |
| |
| print(f"Processing {file_path}: resolution={video_width}x{video_height}, aspect={video_aspect:.2f}, trimmed from {start_time}s to {end_time}s") |
| |
| |
| if abs(video_aspect - target_aspect) > 0.01: |
| if video_aspect > target_aspect: |
| |
| video = video.filter('scale', f'min({target_width},iw*({target_height}/ih))', target_height, force_original_aspect_ratio='decrease') |
| |
| video = video.filter('pad', target_width, target_height, 0, '(oh-ih)/2', color='black') |
| else: |
| |
| video = video.filter('scale', target_width, f'min({target_height},ih*({target_width}/iw))', force_original_aspect_ratio='decrease') |
| |
| video = video.filter('pad', target_width, target_height, '(ow-iw)/2', '(oh-ih)/2', color='black') |
| else: |
| |
| video = video.filter('scale', target_width, target_height, force_original_aspect_ratio='decrease') |
| |
| |
| video = video.filter('fps', fps=30) |
| |
| print(f"After scaling {file_path}: target resolution={target_width}x{target_height}") |
| |
| processed_streams.append(video) |
| processed_streams.append(audio) |
| |
| except ffmpeg.Error as e: |
| print(f"Error processing {file_path}: {e.stderr.decode()}") |
| continue |
| except StopIteration: |
| print(f"Error: No video stream found in {file_path}") |
| continue |
| except Exception as e: |
| print(f"Unexpected error processing {file_path}: {str(e)}") |
| continue |
|
|
| |
| if not processed_streams: |
| print("Error: No valid streams to concatenate") |
| exit(1) |
|
|
| |
| joined = ffmpeg.concat(*processed_streams, v=1, a=1).node |
|
|
| |
| output_dir = "edited_videos" |
| if not os.path.exists(output_dir): |
| os.makedirs(output_dir) |
| print(f"Created directory: {output_dir}") |
|
|
| try: |
| |
| random_string = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8)) |
| file_name = f"{output_dir}/video_edited_{random_string}.mp4" |
|
|
| |
| ffmpeg.output(joined[0], joined[1], file_name, **{'c:v': 'libx264', 'c:a': 'aac'}, preset='fast').run(overwrite_output=True) |
| print("Video concatenation successful") |
| return file_name |
| except ffmpeg.Error as e: |
| print(f"Error during concatenation: {e}") |
| return None |
|
|
|
|
|
|