大鱼自制索尼XVAC素材时间码修复改工具
已更新修复 支持Intel Mac电脑 感谢抖音网友 @格蚤(zao) 的反馈 感谢阿伟找到问题根源排除bug
2024.9.4更新 增加拖放区突出显示 方便拖放文件 增加另存为勾选框 增加调试信息显示窗口方便排查错误
本软件用途是解决索尼微单素材FCPX编辑生成fcpxml导入达芬奇或者剪映无法链接素材的问题
原理是暴力修改素材开始时间码为00:00:00:00,让FCPX和达芬奇剪映对素材有统一开始时间码
界面非常简洁 使用也很简单 手动选择素材或者将素材文件夹拖放到界面中 就自动完成处理 整个过程不涉及转码 所以非常快 也不破坏文件结构 实测修改FCPX正在编辑的素材都不会有任何影响
⚠️注意 本软件默认是在原始素材上进行修改 请确保你有备份或者勾选另存为
警告:本软件仅支持修改索尼微单素材 ,其他机型素材请勿处理。修改索尼微单素材不影响剪辑过的FCPX资源库。
本身是为自己开发的 自己怎么方便怎么来 其他人不懂用法 胡乱操作 搞烂了工程资源库 本人概不负责
以下是为其他开发平台准备的依赖库安装和源代码,Mac用户可以跳过不用看 各位可以自己编译 也欢迎各位大佬进行改进优化
1.Homebrew安装
终端运行
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
2 Python安装也可以去Python官网下载 我是下的3.12版本 也可以终端运行
brew install python
3 ffmpeg安装
brew install ffmpeg
4 tkinterdnd2依赖库安装
pip3 install tkinterdnd2
依赖库安装看起来麻烦 但其实只需要第一次安装就可 以后再用到这些依赖库则无需安装。安装完以后你可以在Python自带的IDLE程序里面粘贴以下源码 点击上方的Run也能跑起来
编译成应用程序,首先cd 你存放源码.py目录 终端输入cd空格把文件夹拖进终端即可 再输入以下代码回车
pyinstaller --onefile --windowed --add-data "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/tkinterdnd2:tkinterdnd2" --hidden-import=tkinterdnd2 --add-binary "libtkdnd2.9.4.dylib:." --add-data "/usr/local/bin/ffmpeg:." --target-arch x86_64 大鱼自制索尼素材时间码修改器(替换成你的文件名).py
以下是原始代码
import os
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
from tkinterdnd2 import DND_FILES, TkinterDnD
import subprocess
import sys
import threading
import tkinterdnd2
def get_ffmpeg_path():
if getattr(sys, 'frozen', False):
# 如果是冻结状态(即打包后的应用),从临时目录中获取
return os.path.join(sys._MEIPASS, 'ffmpeg')
else:
# 否则,使用开发环境中的路径
return '/opt/homebrew/bin/ffmpeg' # 或其他你的开发环境路径
def check_lib_path():
if getattr(sys, 'frozen', False):
lib_path = os.path.join(sys._MEIPASS, 'libtkdnd2.9.4.dylib')
else:
lib_path = os.path.join(os.path.dirname(__file__), 'libtkdnd2.9.4.dylib')
print("Library path:", lib_path)
if not os.path.exists(lib_path):
print("Library not found!")
check_lib_path()
def get_tkdnd_lib_path():
if getattr(sys, 'frozen', False):
return os.path.join(sys._MEIPASS, 'libtkdnd2.9.4.dylib')
else:
return os.path.join(os.path.dirname(__file__), 'libtkdnd2.9.4.dylib')
tkinterdnd2.TkinterDnD._tkdnd_lib_path = get_tkdnd_lib_path()
def get_ffmpeg_path():
if getattr(sys, 'frozen', False):
return os.path.join(sys._MEIPASS, 'ffmpeg')
else:
return FFMPEG_PATH
def modify_timecode(file_path):
ffmpeg_path = get_ffmpeg_path()
temp_file = file_path + ".temp.mp4"
try:
command = [
ffmpeg_path, '-i', file_path, '-c', 'copy',
'-timecode', '00:00:00:00', temp_file
]
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
# 打印详细日志记录
print("FFmpeg stdout:", result.stdout)
print("FFmpeg stderr:", result.stderr)
if result.returncode != 0:
raise subprocess.CalledProcessError(result.returncode, command, output=result.stdout, stderr=result.stderr)
# 覆盖原文件
os.replace(temp_file, file_path)
except subprocess.CalledProcessError as e:
error_message = f"处理文件时出错:{e.stderr}"
print(error_message) # 在控制台打印错误信息
root.after(0, lambda: messagebox.showerror("错误", error_message))
finally:
# 删除临时文件(如果存在)
if os.path.exists(temp_file):
os.remove(temp_file)
def process_files(files_to_process):
processed_files = []
progress_bar["maximum"] = len(files_to_process)
for i, file_path in enumerate(files_to_process):
modify_timecode(file_path)
processed_files.append(file_path)
progress_bar["value"] = i + 1
progress_label.config(text=f"正在处理文件 {i + 1} / {len(files_to_process)}")
root.update_idletasks()
if processed_files:
root.after(0, lambda: progress_label.config(text=f"处理完成,共处理 {len(processed_files)} 个文件"))
else:
root.after(0, lambda: progress_label.config(text="未找到需要处理的视频文件"))
def select_folder(folder_path=None):
if folder_path is None:
folder_path = filedialog.askdirectory()
if folder_path:
files_to_process = []
for root_dir, dirs, files in os.walk(folder_path):
for file in files:
if file.lower().endswith((".mp4", ".mov")):
file_path = os.path.join(root_dir, file)
files_to_process.append(file_path)
# 在新线程中处理文件
threading.Thread(target=process_files, args=(files_to_process,)).start()
def drop(event):
folder_path = event.data.strip('{}')
select_folder(folder_path)
# 创建GUI
root = TkinterDnD.Tk()
root.title("索尼XAVC视频时间码修改器")
frame = tk.Frame(root, padx=10, pady=10)
frame.pack(padx=10, pady=10)
select_button = tk.Button(frame, text="选择需要处理的素材文件夹", command=select_folder)
select_button.pack()
progress_bar = ttk.Progressbar(frame, orient="horizontal", length=300, mode="determinate")
progress_bar.pack(pady=10)
progress_label = tk.Label(frame, text="")
progress_label.pack()
drop_label = tk.Label(frame, text="或者拖放需要处理的素材文件夹到这里")
drop_label.pack(pady=10)
drop_label.drop_target_register(DND_FILES)
drop_label.dnd_bind('<<Drop>>', drop)
root.mainloop()