从网上下载视频的时候,发现下载的视频是一个个.ts文件组合成的文件夹。在播放的时候每个视频播放1-2s切换下个视频,观看体验感无力吐槽。于是,研究了一下,就有了这篇使用ffmpeg把.ts文件转换成MP4文件的的文章。
- .ts 格式:ts 即 “Transport Stream” 的缩写,全称是 MPEG2-TS。它是一种视频文件格式,常用于广播电视领域和网络视频流传输。其特点是从视频流的任一片段开始都可以独立解码,并且可以包含多个不同的视频流、音频流或者字幕流。比如一个.ts 文件可能同时有高清画质的视频流、多种语言的音频流以及不同语言的字幕流,方便在不同播放设备或软件上,根据用户需求选择合适的视频画质、音频语言和字幕。
- .m3u8 格式:m3u8 文件是一种以 utf-8 编码的 M3U 文件,是一个纯文本文件,属于 HLS 协议规范的一部分,充当.ts 视频切片的索引。它存储了一份完整视频的所有.ts 切片的地址信息,还可以包含视频的元数据,如版本号、加密信息、每个分片的时长等。此外,由于它可以包含不同码率版本的视频源地址,视频服务提供商可以根据用户的网络带宽条件动态切换不同的视频质量,确保视频播放流畅且适应不同网络环境。
1、安装ffmpeg
直达链接:Builds - CODEX FFMPEG @ gyan.dev
直接解压到你中意的位置,不用安装!不用安装!不用安装!
复制文件路径 !
添加环境变量如图所示,新建->bin文件地址->添加->确认
接下来我们就试试,
win + R 输入cmd 进入终端界面
输入 ffmpeg __vision__
出现这样的,就差不多安装完成了。
2. 使用 FFmpeg 进行转换
使用cmd界面用语句转换的效率有点低。因此。我选择使用python来完成这个事情。
第一步:因为我下载的文件有几千个.ts文件。所以首先首先要生成一个文件来存放这些文件名列表。
并且这些得按照顺序来排列。
import os
# 指定文件夹路径
folder_path = 'your_folder_path'
try:
# 获取文件夹中所有.ts文件的文件名
ts_files = []
for filename in os.listdir(folder_path):
if filename.endswith('.ts'):
ts_files.append(filename)
# 按文件名中的数字排序
ts_files.sort(key=lambda x: int(os.path.splitext(x)[0]))
# 构造完整的txt文件路径
txt_file_path = os.path.join(folder_path, 'ts_files_list.txt')
# 创建并打开一个txt文件用于写入
with open(txt_file_path, 'w', encoding='utf-8') as file:
for ts_file in ts_files:
# 按照指定格式写入文件名
file.write(f"file '{ts_file}'\n")
print("文件名已按顺序写入到 {} 中。".format(txt_file_path))
except Exception as e:
print(f"出现错误: {e}")
第二步:调用ffmpeg,把ts文件按txt文档里内容的顺序变成MP4格式的视频
import os
import subprocess
# 指定文件夹路径
folder_path = 'your_folder_path'
# 获取文件夹中所有.ts文件的文件名
ts_files = []
for filename in os.listdir(folder_path):
if filename.endswith('.ts'):
ts_files.append(filename)
# 按文件名中的数字排序
ts_files.sort(key=lambda x: int(os.path.splitext(x)[0]))
# 构造完整的txt文件路径
txt_file_path = os.path.join(folder_path, 'ts_files_list.txt')
# 创建并打开一个txt文件用于写入
with open(txt_file_path, 'w', encoding='utf-8') as file:
for ts_file in ts_files:
# 使用绝对路径
absolute_path = os.path.join(folder_path, ts_file)
file.write(f"file '{absolute_path}'\n")
print("文件名已按顺序写入到 {} 中。".format(txt_file_path))
# 指定输出 MP4 文件路径
output_mp4_path = os.path.join(folder_path, 'output.mp4')
# 构造 ffmpeg 命令
ffmpeg_command = [
'ffmpeg',
'-f', 'concat',
'-safe', '0',
'-i', txt_file_path,
'-c', 'copy',
output_mp4_path
]
try:
# 执行 ffmpeg 命令
subprocess.run(ffmpeg_command, check=True)
print(f"已成功将 ts 文件合并为 {output_mp4_path}")
except subprocess.CalledProcessError as e:
print(f"执行 ffmpeg 命令时出现错误: {e}")
3、获取修改.mp4的文件名
这是我的下载的视频出现的文档。.ts文件都集中在index文件夹中。因此生成的视频我希望他获取文件夹的名字。
获取上一级文件夹名字:
parent_folder_name = os.path.basename(os.path.dirname(folder_path))
生成输出视频文件名:
output_mp4_path = os.path.join(folder_path, f'{parent_folder_name}.mp4')
4、最后我想每次改地址有点麻烦,还是生成一个可以自动运行的脚本比较好。
因此需要获取当前脚本.exe所在的文件夹地址
import os
import subprocess
# 获取当前可执行文件所在的文件夹路径
folder_path = os.path.dirname(os.path.abspath(__file__))
# 获取上一级文件夹的名字
parent_folder_name = os.path.basename(os.path.dirname(folder_path))
# 获取文件夹中所有.ts文件的文件名
ts_files = []
for filename in os.listdir(folder_path):
if filename.endswith('.ts'):
ts_files.append(filename)
# 按文件名中的数字排序
ts_files.sort(key=lambda x: int(os.path.splitext(x)[0]))
# 构造完整的txt文件路径
txt_file_path = os.path.join(folder_path, 'ts_files_list.txt')
# 创建并打开一个txt文件用于写入
with open(txt_file_path, 'w', encoding='utf-8') as file:
for ts_file in ts_files:
# 使用绝对路径
absolute_path = os.path.join(folder_path, ts_file)
file.write(f"file '{absolute_path}'\n")
print("文件名已按顺序写入到 {} 中。".format(txt_file_path))
# 指定输出 MP4 文件路径,使用上一级文件夹名字作为视频文件名
output_mp4_path = os.path.join(folder_path, f'{parent_folder_name}.mp4')
# 构造 ffmpeg 命令
ffmpeg_command = [
'ffmpeg',
'-f', 'concat',
'-safe', '0',
'-i', txt_file_path,
'-c', 'copy',
output_mp4_path
]
try:
# 执行 ffmpeg 命令
subprocess.run(ffmpeg_command, check=True)
print(f"已成功将 ts 文件合并为 {output_mp4_path}")
except subprocess.CalledProcessError as e:
print(f"执行 ffmpeg 命令时出现错误: {e}")
5、打包成脚本
可以使用 PyInstaller
来将 Python 脚本打包成可执行文件,按照以下步骤操作:
安装 PyInstaller
如果还没有安装 PyInstaller
,可以使用以下命令进行安装:
pip install pyinstaller
打包脚本
在命令行中,切换到包含 Python 脚本的目录,然后运行以下命令:
pyinstaller --onefile your_script_name.py
这样就能生成一个可执行文件啦。每次下载视频的时候。把这个文件拖到文件里双击运行。就能自动转换成一个.mp4文件
6、因为生成后的.ts文件还存在。所以如果成功生成.mp4文件就删除掉.ts文件
最后附上完成代码
import os
import subprocess
import sys
try:
# 获取当前可执行文件所在的实际目录
if getattr(sys, 'frozen', False):
# 如果是打包后的 exe 文件,使用 os.getcwd() 获取当前工作目录
base_path = os.getcwd()
else:
# 如果是未打包的 Python 脚本
base_path = os.path.dirname(os.path.abspath(__file__))
# 获取上级文件夹的名字
parent_parent_folder_name = os.path.basename(os.path.dirname(base_path))
# 获取文件夹中所有.ts文件的文件名
ts_files = []
for filename in os.listdir(base_path):
if filename.endswith('.ts'):
ts_files.append(filename)
# 按文件名中的数字排序
ts_files.sort(key=lambda x: int(os.path.splitext(x)[0]))
# 构造完整的txt文件路径
txt_file_path = os.path.join(base_path, 'ts_files_list.txt')
# 创建并打开一个txt文件用于写入
with open(txt_file_path, 'w', encoding='utf-8') as file:
for ts_file in ts_files:
# 使用绝对路径
absolute_path = os.path.join(base_path, ts_file)
file.write(f"file '{absolute_path}'\n")
print("文件名已按顺序写入到 {} 中。".format(txt_file_path))
# 指定输出 MP4 文件路径,使用上级文件夹名字作为视频文件名,保存到上一级目录
parent_dir = os.path.dirname(base_path)
output_mp4_path = os.path.join(parent_dir, f'{parent_parent_folder_name}.mp4')
# 构造 ffmpeg 命令
ffmpeg_command = [
'ffmpeg',
'-f', 'concat',
'-safe', '0',
'-i', txt_file_path,
'-c', 'copy',
output_mp4_path
]
# 执行 ffmpeg 命令
subprocess.run(ffmpeg_command, check=True)
print(f"已成功将 ts 文件合并为 {output_mp4_path}")
# 只有当 MP4 文件生成成功后,才进行删除操作
if os.path.exists(output_mp4_path):
# 删除除了 MP4 文件之外的其他文件
for filename in os.listdir(base_path):
file_path = os.path.join(base_path, filename)
if os.path.isfile(file_path) and filename != os.path.basename(output_mp4_path):
try:
os.remove(file_path)
print(f"已删除文件: {file_path}")
except Exception as e:
print(f"删除文件 {file_path} 时出错: {e}")
else:
print("MP4 文件未成功生成,不进行删除操作。")
except subprocess.CalledProcessError as e:
print(f"执行 ffmpeg 命令时出现错误: {e}")
except Exception as e:
print(f"程序运行过程中出现错误: {e}")