import os
import subprocess
from datetime import datetime
import ffmpeg

'''
将视频转码成h.265格式用以压缩体积，保留原始的拍摄时间及位置信息。
在指定文件夹下扫描视频文件'.mp4', '.mkv', '.avi', '.mov', '.MOV', '.MP4'，
然后转码并输出至指定目录的同级目录_output文件夹下（指定目录：D:\EV\test；输出目录：D:\EV\test_output）。

准备：
pip install ffmpeg-python
下载exiftool（已下载）/

运行：
修改input_folder参数，然后直接用python运行就可以。
'''

# 指定exiftool的路径
exiftool_path = os.path.join(os.getcwd(), 'exiftool-12.87', 'exiftool.exe')

def extract_metadata(input_file):
    command = [exiftool_path, '-json', input_file]
    print(f"Running extract_metadata command: {' '.join(command)}")  # 调试输出
    try:
        output = subprocess.run(command, capture_output=True, text=False, check=True)
        result = output.stdout.decode('utf-8', errors='ignore')
        print(f"Command output: {output.stdout}")  # 调试输出
        print(f"Command error: {output.stderr}")  # 调试输出
        metadata = output.stdout
        return metadata
    except subprocess.CalledProcessError as e:
        print(f"Error extracting metadata: {e.stderr}")
        return None
    except Exception as e:
        print(f"Unexpected error: {e}")
        return None

def write_metadata(output_file, metadata):
    temp_metadata_file = 'metadata.json'
    with open(temp_metadata_file, 'w') as f:
        f.write(metadata)
    command = [exiftool_path, '-overwrite_original', '-json=' + temp_metadata_file, output_file]
    print(f"Running write_metadata command: {' '.join(command)}")  # 调试输出
    try:
        output = subprocess.run(command, capture_output=True, text=False, check=True)
        result = output.stdout.decode('utf-8', errors='ignore')
        print(f"Command output: {output.stdout}")  # 调试输出
        print(f"Command error: {output.stderr}")  # 调试输出
        print(f"Successfully wrote metadata to {output_file}")
    except subprocess.CalledProcessError as e:
        print(f"Error writing metadata: {e.stderr}")
    except Exception as e:
        print(f"Unexpected error: {e}")
    finally:
        os.remove(temp_metadata_file)

def copy_metadata(original_file, new_file):
    command = [exiftool_path, '-tagsFromFile', original_file, '-all:all', '-overwrite_original', new_file]
    print(f"Running copy_metadata command: {' '.join(command)}")  # 调试输出
    try:
        output = subprocess.run(command, capture_output=True, text=False, check=True)
        result = output.stdout.decode('utf-8', errors='ignore')
        print(f"Command output: {output.stdout}")  # 调试输出
        print(f"Command error: {output.stderr}")  # 调试输出
        print(f"Successfully copied metadata from {original_file} to {new_file}")
    except subprocess.CalledProcessError as e:
        print(f"Error copying metadata: {e.stderr}")
    except Exception as e:
        print(f"Unexpected error: {e}")

def convert_to_h265(input_file, output_file):
    try:
        #获取音轨和字幕数据
        probe = ffmpeg.probe(input_file)
        audio_streams = [stream for stream in probe['streams'] if stream['codec_type'] == 'audio']
        subtitle_streams = [stream for stream in probe['streams'] if stream['codec_type'] == 'subtitle']
        has_multiple_audio_tracks = len(audio_streams) > 0
        has_multiple_subtitles = len(subtitle_streams) > 0

        if(has_multiple_audio_tracks==True & has_multiple_subtitles == True):#存在音轨，字幕
            command = [
                'ffmpeg',
                '-i', input_file,
                '-c:v', 'libx265',
                '-preset', 'medium',
                '-map_metadata', '0',
                '-tag:v', 'hvc1',
                '-map', '0:v:0',
                '-map', '0:a',
                '-map', '0:s',
                output_file
            ]
        elif ((has_multiple_audio_tracks==True) & (has_multiple_subtitles==False)):#只存在音轨，没有字幕
            command = [
                'ffmpeg',
                '-i', input_file,
                '-c:v', 'libx265',
                '-preset', 'medium',
                '-map_metadata', '0',
                '-tag:v', 'hvc1',
                '-map', '0:v:0',
                '-map', '0:a',
                output_file
            ]
        elif ((has_multiple_audio_tracks==False) & (has_multiple_subtitles==True)):#没有音轨，只有字幕（不太可能，所以还是把'-map', '0:a',加上了）
            command = [
                'ffmpeg',
                '-i', input_file,
                '-c:v', 'libx265',
                '-preset', 'medium',
                '-map_metadata', '0',
                '-tag:v', 'hvc1',
                '-map', '0:v:0',
                '-map', '0:a',
                '-map', '0:s',
                output_file
            ]
        else:
            command = [
                'ffmpeg',
                '-i', input_file,
                '-c:v', 'libx265',
                '-preset', 'medium',
                '-map_metadata', '0',
                '-tag:v', 'hvc1',
                '-map', '0:v:0',
                output_file
            ]

        print(f"Running convert_to_h265 command: {' '.join(command)}")  # 调试输出
        subprocess.run(command, check=True)
        print(f'Successfully converted {input_file} to {output_file}')
    except subprocess.CalledProcessError as e:
        print(f'Error occurred while converting {input_file}: {e}')
    except Exception as e:
        print(f"Unexpected error: {e}")

def main(input_folder):
    output_path = os.path.join(os.path.dirname(input_folder), os.path.basename(input_folder) + '_output')
    os.makedirs(output_path, exist_ok=True)

    # 遍历目录结构
    for root, dirs, files in os.walk(input_folder):
        for file in files:
            if file.endswith(('.mp4', '.mkv', '.avi', '.mov', '.MOV', '.MP4')):
                # 构建输入文件的完整路径
                input_file = os.path.join(root, file)
                
                # 构建输出文件的完整路径
                relative_path = os.path.relpath(root, input_folder)
                output_dir = os.path.join(output_path, relative_path)
                os.makedirs(output_dir, exist_ok=True)
                output_file = os.path.join(output_dir, file)

                print(f"Processing file: {input_file}")  # 调试输出
                
                # Extract metadata
                metadata = extract_metadata(input_file)
                if metadata is None:
                    continue
                # Convert video
                convert_to_h265(input_file, output_file)

                # Copy metadata back
                copy_metadata(input_file, output_file)
                print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))


if __name__ == "__main__":
    input_folder = r'E:\2h265'  # 这里是你的文件夹路径
    main(input_folder)
    user_input = input("按任意键结束程序")


