ffmpeg+Python实现B站MP4格式⾳频与视频的合并⽰例代码⽬录
安装
环境变量
验证
ffmpeg的使⽤
Python实现⾃动处理
⽂件结构
番剧缓存结构
常规缓存结构
⽂件信息
代码
具体代码
代码说明
安装
官⽹下载
选择需要的版本
将解压后得到的以下⼏个⽂件放置在E:\FFmpeg下
环境变量
此电脑--属性--⾼级系统设置--环境变量
在系统变量(也就是下⾯那⼀半)处到新建,按如下所⽰的⽅法填写
再将%FFMPEG_HOME%以及%FFMPEG_HOME%\bin写⼊系统变量的Path中
然后⼀路确定即可
验证
廖雪峰的javascript教程win+R,cmd
输⼊ffmpeg -version
ffmpeg的使⽤
对于我将B站PC端缓存的⾳频mp4和视频mp4⽂件合并的需求,需要⽤到的命令为:
< -i audio1.mp4 -i video.mp4 -acodec copy -vcodec copy output.mp4
可以把mp4的⽂件设置成绝对路径,这样就可以转换指定路径的⽂件以及保存到指定路径了,⽐如这样:
< -i "E:\哔哩哔哩视频\ss27993\77413703\1\audio1.mp4" -i "E:\哔哩哔哩视频\ss27993\77413703\1\video.mp4" -acodec copy -vcodec copy "E:\B站导出视频\Dr.STONE⽯纪元\第22话宝物.mp4通过PC端缓存的未合并的视频和⾳频,全都是命名为video.mp4和audio.mp4
PS:有些兄弟是导出的⼿机端缓存的视频和⾳频,是m4s格式的,⽅法也⼀样
但光有这条命令还不够,需要⾃⼰⼿动⼀个个操作,太⿇烦了
因此我还需要使⽤Python来⾃动帮我完成⼯作
Python实现⾃动处理
虽然Python可以实现⾃动化,减少时间的浪费,但最快的还是以后记得缓存时勾选⾃动合并
⽂件结构
PC端缓存的视频保存的⽂件结构有很多种,我只是根据我碰到的情况写的,但⼤同⼩异,修改起来也不⿇烦,只是再加个if和else罢了
番剧缓存结构
缓存的番剧是这种结构:
上⾯举的例⼦是Dr.stone⽯纪元,我缓存的⿁灭之刃也是如此
特点是在⼀个以视频ID号名称的⽂件夹(ss27993)后,跟着许多⼦⽂件夹(57983089等),然后在这些⼦⽂件夹中⼜有⼀个或多个⼦⽂件夹(⽐如1),然后缓存的视频保存在这个⽂件夹⾥,⾥⾯有⼀个info⽂件(就是json格式),还有audio1.mp4和video.mp4。
PS:
还有⼀个xml⽂件,是弹幕信息,暂时我不知道怎么处理
常规缓存结构
除了番剧,⼀般的视频缓存的结构是这样的
不难看出,这⽐番剧要少⼀个层级
⽂件信息
⽂件信息主要由info⽂件和dvi⽂件来记录
这两种⽂件都可以直接以json⽂件来处理,也就是,⾸先open函数打开⽂件,然后⽤json.load转成字典。。。
然后我还发现了⼀个特点是,视频和⾳频所在的⽬录下是info⽂件,⽽它的上⼀层⽬录下是dvi⽂件
虽然⽂件格式基本是⼀致的,但是⾥⾯的键-值关系却不⼀致,单集视频的名称在番剧中对应的是键Description,在其他视频中对应的是PartName
视频总的名称保存在外层的⽬录下的info⽂件或dvi⽂件中,番剧中对应的键是SeasonTitle,在其他视频中对应的是Title
具体问题具体分析,⾸先由于我实践得较少,这样的总结不⼀定对,然后以后也许也会有新的格式、新的变化
代码
具体代码
以下是我的Python代码,你可以先试试能不能⽤,⽤不了的话,可以在理解的基础上修改。理解不了的话可以看我的后⾯的解释,以及代码中的注释,对于运⾏过程中⼀些变量的值,我都把它放在注释
中了,⽅便你理解。
# -*- coding = utf-8 -*-
# @time:2020/10/17/017 23:09
# Author:cyx
# @File:main.py.py
# @Software:PyCharm
# 从.info⽂件中获得了Title信息,但是如果其中有某些特殊字符,保存时可能出现问题
def get_correct_title(title):
error_set = ['/', '\\', ':', '*', '?', '"', '|', '<', '>', '\b', ' ', '.']
correct_title = title
# print(title)
for c in correct_title:
if c in error_set:
correct_title = place(c, '')
return correct_title
def popen(cmd):
# blog.csdn/qq_41451161/article/details/82901235
try:
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE)
怎么将字母转化为ascii码
popen.wait()
lines = adlines()
return [line.decode('gbk') for line in lines]
except BaseException as e:
return -1
if __name__ == '__main__':
import os
import json
import subprocess
# ffmpeg -i video.m4s -i audio.m4s -c:v copy -c:a aac -strict experimental output.mp4
# -i audio1.mp4 -i video.mp4 -acodec copy -vcodec copy output.mp4
AVhao = input("请输⼊视频AV号:")
superPath = "E:\\哔哩哔哩视频" + "\\" + AVhao
partDirs = [] # 保存每P视频所在的⽂件夹路径
paths = os.listdir(superPath) # 获取当前路径下所有的⽂件(包括⽂件夹)名称
# paths = ['8','9']
# 有时候,会莫名其妙的少了⼏个视频,可以通过重载来重新加载缺失的视频
# print(paths)
# paths
# ['27993.info', '57983089', '58612211', '59811008', '60862133', '61898240', '62925012', '64005445', '65020725', '66013155', '66808912', '67587875', '68398229', '69175748', '70021307', '70873680', '71617211', '73379440', '74051851', '74974157', '75746600', '7661940 # 获取每P视频所在的⽂件夹路径
savePos = ''
seq = []
# 鉴于有些up主命名时毫⽆规律,导出后⽆法正常排序,只能⼿动排序了
# 根据AV号名⽂件夹下的⼦⽂件夹的名称进⾏排序,但是番剧的话不是这样排序,不过番剧单集的名称很规范,不需要这样
for p in paths:
if '.' not in p:
seq.append(p)
美国总统大选时间2024if 'info' in p:
# print(p)
# p:
# 27993.info
info = superPath + "\\" + p
with open(info, 'r', encoding='utf-8') as load_f:
load_dict = json.load(load_f)
projectTitle = load_dict['SeasonTitle']
projectTitle = get_correct_title(projectTitle)
savePos = 'E:\\B站导出视频\\' + projectTitle
print('savePos: ', savePos)
if 'dvi' in p:
# print(p)
# P:php大作业源码
# 328738595.dvi
dvi = superPath + "\\" + p
with open(dvi, 'r', encoding='utf-8') as load_f:
load_dict = json.load(load_f)
projectTitle = load_dict['Title']
projectTitle = get_correct_title(projectTitle)
savePos = 'E:\\B站导出视频\\' + projectTitle
print('savePos: ', savePos)
# 防⽌⽂件存在时再次⽣成该⽂件夹出现错误
try:
os.mkdir(savePos)
break
except:
pass
subDir = superPath + "\\" + p
if os.path.isdir(subDir):
# print(subDir)
# 所有⼦⽂件夹的路径保存在partDirs中
partDirs.append(subDir)
# print("partDirs: ",partDirs)
# partDirs: ['E:\\哔哩哔哩视频\\ss27993\\57983089', 'E:\\哔哩哔哩视频\\ss27993\\58612211', 'E:\\哔哩哔哩视频\\ss27993\\59811008', 'E:\\哔哩哔哩视频\\ss27993\\60862133', 'E:\\哔哩哔哩视频\\ss27993\\61898240', 'E:\\哔哩哔哩视频\\ss27993\\62925012', 'E:\\哔 videoPos = ''
i = 0
for p in partDirs:
# print(p)
# 列出⼦⽂件夹中的所有⽂件
sublist = os.listdir(p)
# 检查info⽂件是否在当前⼦⽂件夹中
for file in sublist:
# print(file)
# file:
# 1
# 57983089.
# dvi
# cover.jpg
# desktop.ini
if 'info' in file:
infoPos = p + "\\" + file
videoPos = p
else:
subsubDir = p + "\\" + file
if os.path.isdir(subsubDir):
# print(subsubDir)
# subsubDir: E:\哔哩哔哩视频\ss27993\57983089\1
subsubList = os.listdir(subsubDir)
for subsubFile in subsubList:
if 'info' in subsubFile:
infoPos = subsubDir + "\\" + subsubFile
videoPos = subsubDir
break
with open(infoPos, 'r', encoding='utf-8') as load_f:
精品php源码load_dict = json.load(load_f)
if 'ss' in AVhao:
videoTitle = load_dict['Description']
else:
videoTitle = load_dict['PartName']
videoTitle = get_correct_title(videoTitle)
print('videoTitle: ', videoTitle)
videoDir = videoPos + "\\" + 'video.mp4'
audioDir = videoPos + "\\" + 'audio1.mp4'
# print('videoDir: ', videoDir)
# print('audioDir: ', audioDir)
# videoDir: E:\哔哩哔哩视频\ss27993\74051851\1\video.mp4
# audioDir: E:\哔哩哔哩视频\ss27993\74051851\1\audio1.mp4
if 'ss' in AVhao:
outDir = savePos + "\\" + videoTitle + '.mp4'
else:
outDir = savePos + "\\" + seq[i] + '_' + videoTitle + '.mp4'
i += 1
# 对于那些命名很规范的视频,可以不⽤⾃⼰再排序,进⾏⼀下重载,不规范的视频再把这句注释掉就好
outDir = savePos + "\\" + videoTitle + '.mp4'
# command = 'cd ' + superPath + '\\64 && ' # && 多名命令
# command = 'cd ' + 'E:\\ProgramFiles\\ffmpeg' + ' && '
command = 'E:\\FFmpeg\\bin\\ -i ' + '"' + audioDir + '"' ' -i ' + '"' + videoDir + '"'+ ' -acodec copy -vcodec copy ' + '"' + outDir + '"'
# print("保存地址",outDir)
# 保存地址 E:\B站导出视频\[Lynda视频]⾳频录制录⾳技巧教程(中英双语字幕)全集130课时AudioRecordingTechniques混⾳录⾳棚⾳乐⼯作室歌曲调⾳\98录制独奏萨克斯演奏技巧⼆.mp4
# print(command)
# command = 'E:\\FFmpeg\\bin\\ -i "E:\哔哩哔哩视频\ss27993\77413703\1\audio1.mp4" -i "E:\哔哩哔哩视频\ss27993\77413703\1\video.mp4" -acodec copy -vcodec copy "E:\B站导出视频\Dr.STONE⽯纪元\第22话宝物.mp4'
# os.system(command)
popen(command)
# -i audio1.mp4 -i video.mp4 -acodec copy -vcodec copy output.mp4
break
代码说明
如你所见我的编程⽔平不⾼,模块化做的很差,不便于理解,所以有必要进⾏说明。
直接从main开始看起吧。
AVhao = input("请输⼊视频AV号:")
python入门教程视屏superPath = "E:\\哔哩哔哩视频" + "\\" + AVhao
partDirs = [] # 保存每P视频所在的⽂件夹路径
paths = os.listdir(superPath) # 获取当前路径下所有的⽂件(包括⽂件夹)名称
⾸先是⽤input接收AV号或BV号的输⼊,放⼊AVhao变量中。
然后⽤superPath变量存放你需要合并的视频的根⽬录。⽐如我在B站缓存的所有视频存放在E:\哔哩哔哩视频下,注意程序中要有两条\,然后superPath就是E:\哔哩哔哩视频\AVhao。
os.listdir(),括号中的参数必须是⼀个真实的路径,这个函数可以得到这个路径下所有的⽂件和⽂件夹的名称。
我⽤paths来存放E:\哔哩哔哩视频\AVhao路径下所有的⽂件名称和⽂件夹名称。
为了防⽌我的表达能⼒有限带来的理解上的不便,你可以看图,paths对应的是下图中的内容:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论