ffmpeg 常用命令
转化视频大小
ffmpeg -i class.mp4 -vf "scale=500:300" out.mp4
转化图片大小
ffmpeg -i t.jpg -vf "scale=500:900" t2.jpg
背景合并
ffmpeg -i out.mp4 -i mp3/bg.mp3 -vf "movie=t2.jpg [bg]; [bg][in] overlay=0:300" out2.mp4
提取背景音乐
ffmpeg -i F58F63BF-742E-4CFF-B251-9A924E50FDD5.mov.mp4 -vn bg.mp3
截去开头和结尾1S
ffmpeg -ss {start_time} -to {end_time} -i {src} -t 60 -c:v copy -c:a copy result/video/{dst}"
精准剪切:
ffmpeg -ss 00:00:11.50 -to 00:00:12 -accurate_seek -i
D:\boding\videoFile\20210113\20210113053015\20210113053015-7.mp4 -c:v libx264 -
avoid_negative_ts 1 E:\ffmpeg\bin\cutVideo\2.mp4 -y
主动镜像(左右翻转)
ffmpeg -i {src} -vf hflip result/video/{dst}
视频缩放
ffmpeg -i {src} -vf \"scale={x}:{y}\" result/video/{dst} -hide_banner
自动滤镜
对比度 contrast -2.0-9.0 默认为1
ffmpeg -i {src} -vf eq=contrast={contrast} result/video/{dst}
饱和度 saturation -10 -10 默认1
ffmpeg -i /Users/c/Downloads/rolex/python/result/video/test.mp4 -vf hue=s=1.05 result/video/test_saturation_011.mp4 -y
锐化 -2是模糊 2是锐化 默认1
ffmpeg -i {src} -vf unsharp=5:5:-2 result/video/{dst} -y
修改md5
echo ' '>>{src} && cp {src} ./result/video/{dst}
python 工具类 videohelper.py
import os
import ffmpeg
import hashlib
import math
from PIL import Image
def get_video_dir(task_id):
video_dir = os.path.abspath(os.path.dirname(os.getcwd())) + "/data/video/" + str(task_id) + "/"
if not os.path.exists(video_dir):
os.mkdir(video_dir.encode("utf-8"))
return video_dir
def video_info_detail(video_path):
video = ffmpeg.probe(video_path)
streams = video["streams"]
width = streams[0]["width"]
height = streams[0]["height"]
duration = video["format"]["duration"]
return width, height, duration
def image_resize_pixel(input_file, output_file, x, y):
Image.open(input_file).resize((x, y), Image.ANTIALIAS).save(output_file)
class FFmpegHelper:
def __init__(self, video_src, rule, task_id):
# 原始视频路径
self.video_src = video_src
self.rule = rule
self.task_id = task_id
self.video_dir = get_video_dir(task_id)
def video_info(self):
video = ffmpeg.probe(self.video_dir + self.video_src)
streams = video["streams"]
width = streams[0]["width"]
height = streams[0]["height"]
duration = video["format"]["duration"]
return width, height, duration
"""
改变视频长宽 比例
"""
def resize_by_coefficient(self, lambda_x, lambda_y):
dst = "resizeByCoefficient_" + str(self.video_src)
lambda_x = lambda_x if lambda_x else 1.0
lambda_y = lambda_y if lambda_y else 1.0
width, height, duration = self.video_info()
resize_cmd = "ffmpeg -i {src} -vf \"scale=w={x}:h={y}\" {dst} -y -hide_banner" \
.format(src=self.video_dir + self.video_src, dst=self.video_dir + dst, x=int(lambda_x * width),
y=int(lambda_y * height))
os.system(resize_cmd)
self.video_src = dst
return dst
"""
改变视频长宽 具体像素
"""
def resize_by_px(self, width, height):
dst = "resizeByPx_" + str(self.video_src)
resize_cmd = "ffmpeg -i {src} -vf \"scale={x}:{y},setdar={x}/{y}\" {dst} -y" \
.format(src=self.video_dir + self.video_src, dst=self.video_dir + dst, x=width,
# delta=float(height) / float(width),
y=height
)
os.system(resize_cmd)
self.video_src = dst
return dst
'''
视频加水印 文字
wateMark 水印路径
'''
def add_water_mark_txt(self, txt, size, color):
dst = "addWaterMarkTxt_" + self.video_src
# todo 添加字体 yellow
cmd = "ffmpeg -i {src} -vf \"drawtext=/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/tff/微软雅黑14M.ttf: text='{txt}':x=100:y=10:fontsize={size}:fontcolor={color}:shadowy=2\" {dst} -y".format(
src=self.video_dir + self.video_src,
txt=txt,
size=size,
color=color,
dst=self.video_dir + dst
)
os.system(cmd)
self.video_src = dst
return dst
def add_water_mark_img(self, img, w, h, x, y):
water_mark = self.video_dir + str(w) + "x" + str(h) + "_" + str(img.split("/")[-1])
dst = "addWaterMarkImg_" + self.video_src
cmd_img = "ffmpeg -i {img} -vf scale={w}:{h} {water_mark} -y" \
.format(img=img, w=w, h=h, water_mark=water_mark)
print(cmd_img)
os.system(cmd_img)
# main_w-overlay_w-10:main_h-overlay_h-10
cmd = "ffmpeg -i {src} -vf \"movie={img} [watermark];[in][watermark] overlay={x}:{y} [out]\" {dst} -y".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst,
x=x,
y=y,
img=water_mark)
os.system(cmd)
self.video_src = dst
return dst
'''
视频加背景
backImage 背景图片路径
'''
def add_back_ground(self, back_image):
dst = "backImg_" + self.video_src
# todo 设置背景图片和 前景关系 需要修改
cmd = "ffmpeg -y -i {src} -i {image} -filter_complex \"[1:v]scale=450:800:force_original_aspect_ratio=1," \
"pad=450:800:0:264:color=black@0,setsar=1[inner];[0:v][inner]overlay=0:0[video]\" -map \"[video]\" -map " \
"0:a -c:a copy -to 00:00:15.000 {dst}".format(
src=self.video_dir + self.video_src, dst=self.video_dir + dst,
image=back_image)
os.system(cmd)
self.video_src = dst
return dst
def add_front_video(self, front_video):
"""
main_w 或 W 主输入(背景窗口)宽度
main_h 或 H 主输入(背景窗口)高度
overlay_w 或 w overlay 输入(前景窗口)宽度
overlay_h 或 h overlay 输入(前景窗口)高度
"""
_, _, duration_front = video_info_detail(front_video)
_, _, duration_background = self.video_info()
if float(duration_front) > 0:
times = float(duration_background) / float(duration_front)
print("times:", times)
else:
times = 1
dst = "addFrontVideo_" + self.video_src
cmd = "ffmpeg -i {src} -vf \"movie={front_video}:loop={times},setpts=N/FRAME_RATE/TB[logo];[0:v][logo]overlay=x=100:y=100\" {dst} -y".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst,
times=times,
front_video=front_video)
os.system(cmd)
self.video_src = dst
return dst
'''
在开始插入视频
src 插入的视频地址
'''
def add_video_on_begin(self, src):
return self.add_video(src, "on_begin")
'''
在结尾插入视频
src 插入的视频地址
'''
def add_video_on_end(self, src):
return self.add_video(src, "on_end")
def add_video(self, src_add, on_end_or_begin):
ts1 = self.video_src.replace(".mp4", ".ts")
ts2 = str(src_add.split("/")[-1]) + ".ts"
if on_end_or_begin == "on_begin":
dst = "addVideoOnBegin_" + self.video_src
concat = self.video_dir + ts1 + "|" + self.video_dir + ts2
else:
dst = "addVideoOnEnd_" + self.video_src
concat = self.video_dir + ts2 + "|" + self.video_dir + ts1
cut_cmd = "ffmpeg -i {src_add} -vcodec copy -acodec copy -vbsf h264_mp4toannexb {ts1} -y &&" \
"ffmpeg -i {src} -vcodec copy -acodec copy -vbsf h264_mp4toannexb {ts2} -y && " \
"ffmpeg -i \"concat:{concat}\" -c copy -bsf:a aac_adtstoasc -movflags +faststart " \
"{dst} -y".format(
ts1=self.video_dir + ts1,
ts2=self.video_dir + ts2,
concat=concat,
src=self.video_dir + self.video_src,
src_add=src_add,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
def add_img_on_mid(self, img_src, start_time, keep_time, flag_str):
# flag_str "addImageHead_" or "addImageMid_" or "addImageFoot_"
width, height, duration = self.video_info()
print(width, height, duration)
m = hashlib.md5()
m.update(str(img_src).encode(encoding="utf-8"))
img_dst = self.video_dir + str(m.hexdigest()) + ".jpg"
cmd_resize_image = "ffmpeg -i {img_src} -vf scale={width}:{height} {img_dst} -y".format(
img_src=img_src,
width=width,
height=height,
img_dst=img_dst
)
os.system(cmd_resize_image)
dst = flag_str + self.video_src
cut_cmd = "ffmpeg -i {src} -i {img} -filter_complex \" overlay=0:0:enable='between(t,{start_time}," \
"{end_time})'\" -pix_fmt yuv420p -c:a copy {dst} -y".format(
src=self.video_dir + self.video_src,
img=img_dst,
start_time=start_time,
end_time=float(start_time) + float(keep_time),
dst=self.video_dir + dst
)
os.system(cut_cmd)
self.video_src = dst
os.system("rm -rf {img_dst}".format(img_dst=img_dst))
return dst
'''
在中间或指定位置插入图片
img_src 插入的图片路径
startTime 插入开始时间
keep_time 持续时间
'''
def add_img_on_foot(self, img_src, keep_time):
width, height, duration = self.video_info()
print(duration)
return self.add_img_on_mid(img_src, float(duration) - float(keep_time), float(keep_time), "addImageFoot_")
def add_img_on_head(self, img_src, keep_time):
return self.add_img_on_mid(img_src, 0.0, float(keep_time), "addImageHead_")
'''
设置速度
快/慢放
speed 速度
'''
def set_speed(self, speed):
width, height, duration = self.video_info()
dst = "setSpeed_" + self.video_src
speed = 1.0 / float(speed)
cmd = "ffmpeg -i {src} -filter:v \"setpts={speed}*PTS\" -ss 0 -t {duration} {dst} -y".format(
src=self.video_dir + self.video_src, dst=self.video_dir + dst, speed=speed,
duration=float(duration) * speed)
os.system(cmd)
self.video_src = dst
return dst
'''
去除背景音乐
'''
def remove_bgm(self):
# todo 待测试
dst = "removeBgm_" + self.video_src
cut_cmd = "ffmpeg -i {src} -c:v copy -an {dst} -y".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
添加背景音乐
[1:a]aloop=loop=-1:size=2e+09[out]; 无限循环
[out][0:a]amix 将背景音和视频中的音频混合
src 背景音乐路径
https://blog.csdn.net/yu540135101/article/details/85936923?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control
'''
def add_bgm(self, bgm):
dst = "addBgm_" + self.video_src
width, height, duration = self.video_info()
cut_cmd = "ffmpeg -an -i {src} -stream_loop -1 -i {bgm} -t {duration} '{dst}' -y".format(
src=self.video_dir + self.video_src,
bgm=bgm,
duration=duration,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
左右翻转视频
'''
def flip_video(self):
dst = "hflip_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf hflip {dst} -y".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
视频裁剪
w,h,x,y 长宽,左上角坐标
'''
def crop_video(self, w, h, x, y):
dst = "corp_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf crop={w}:{h}:{x}:{y} -threads 5 -preset ultrafast -strict -2 {dst} -y".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst,
w=w, h=h, x=x, y=y)
os.system(cut_cmd)
self.video_src = dst
return dst
def video_burl(self):
dst = "burl_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf boxblur=5:1 {dst} -y".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
视频锐化
ratio 锐化参数 默认值为1.0, >1.0时表示 锐化
'''
def set_sharp_ratio(self, ratio):
dst = "sharpRatio_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf unsharp=5:5:{ratio} {dst} -y".format(
src=self.video_dir + self.video_src,
ratio=float(ratio),
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
设置视频对比度
ratio 对比度 对比度 (-2.0,10.0) 默认0
'''
def set_contrast_ratio(self, ratio):
dst = "contrastRatio_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf eq=contrast={ratio} {dst} -y".format(
src=self.video_dir + self.video_src,
ratio=float(ratio),
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
设置视频饱和度
ratio 饱和度 (-10,10) 默认1.0
'''
def set_saturated_ratio(self, ratio):
dst = "saturatedRatio_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf hue=s={ratio} {dst} -y".format(
src=self.video_dir + self.video_src,
ratio=float(ratio),
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
def set_video_brightness(self, brightness):
"""
亮度调节 (-1,1)
"""
dst = "setBrightness_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf \"eq=brightness={brightness}\" -an {dst} -y".format(
src=self.video_dir + self.video_src,
brightness=float(brightness),
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
def set_color_(self):
"""
设置色温 todo http://help.tmtyum.com/content.php?id=18
"""
return
def set_video_h(self, h):
"""
色调角度度数 (0,360) 默认 0
"""
dst = "seth_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf \"hue=h={h}\" -an {dst} -y".format(
src=self.video_dir + self.video_src,
h=float(h),
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
'''
剪辑视频
startTime 开始时间
endTime 结束时间
'''
def cut_video(self, start_time, end_time):
dst = "cut_" + self.video_src
# todo 改成指定 格式视频
cut_cmd = "ffmpeg -ss {start_time} -to {end_time} -i {src} -c:v copy -c:a copy {dst} -y".format(
src=self.video_dir + self.video_src,
start_time=start_time,
end_time=end_time,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
def process_video(self):
# todo 根据规则修改视频 确定规则格式 json or str?
rule = self.rule
video_src = self.video_src
return "target_dir"
def video_reverse(self):
dst = "reverse_" + self.video_src
cut_cmd = "ffmpeg -i {src} -vf reverse -y {dst}".format(
src=self.video_dir + self.video_src,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
def change_md5(self):
dst = "changeMd5_" + self.video_src
cut_cmd = "echo ' '>>{src} && cp {src} {dst}".format(src=self.video_dir + self.video_src,
dst=self.video_dir + dst)
os.system(cut_cmd)
self.video_src = dst
return dst
def add_bk_video(self, px, py):
"""
添加原视频模糊高斯背景
px:py 背景比例 16 :9 ,4 :3,9 :16,3 :4,1:1
"""
width, height, _ = self.video_info()
if float(px) / float(py) > width / height:
new_h = height
new_w = float(px) / float(py) * height
x, y = float(new_w - width)/2.0, 0
# 原视频竖放
elif float(px) / float(py) < width / height:
# 原视频横放
new_h = float(py) / float(px) * width
new_w = width
x, y = 0, float(new_h - height) /2.0
else:
new_h = height
new_w = width
x, y = 0, 0
ffmpeg_helper2 = FFmpegHelper(rule=None, video_src=str(self.video_src), task_id=self.task_id)
# print("new_w:", new_w, "new_h:", new_h)
ffmpeg_helper2.resize_by_px(new_w, new_h)
bk = ffmpeg_helper2.video_burl()
dst = "bkVideo_" + self.video_src
# cmd = "ffmpeg -i {src} -vf \"split[a][b];[a]scale={x}:{y},boxblur=10:5[1];[b]scale=1080:ih*1080/iw[2];[1][2]overlay=0:(H-h)/2\" -c:v libx264 -crf 18 -preset veryfast -aspect 9:16 {dst} -y" \
# .format(src=self.video_dir + self.video_src,
# dst=self.video_dir + dst,
# x=new_w,
# y=new_h
# )
cmd = "ffmpeg -i {bk} -i {fd} -filter_complex overlay={x}:{y} {dst} -y" \
.format(bk=self.video_dir + bk,
fd=self.video_dir + self.video_src,
x=x,
y=y,
dst=self.video_dir + dst)
os.system(cmd)
self.video_src = dst
return dst
def test(rule, task_id, video_src):
ffmpeg_helper = FFmpegHelper(rule=rule,
video_src=video_src, task_id=task_id)
ffmpeg_helper.cut_video("00:00:00", "00:00:04")
ffmpeg_helper.set_speed(2)
ffmpeg_helper.remove_bgm()
# ffmpeg_helper.crop_video(480, 480, 0, 0)
ffmpeg_helper.flip_video()
ffmpeg_helper.video_reverse()
# ffmpeg_helper.add_front_video()
ffmpeg_helper.resize_by_px(2040, 2040)
ffmpeg_helper.add_water_mark_txt("www.biadu.com", size=20, color="yellow")
ffmpeg_helper.add_bk_video(3, 4)
ffmpeg_helper.change_md5()
print(ffmpeg_helper.video_src)
# todo 画面调节 特效
if __name__ == '__main__':
test(rule="", video_src="111.mp4", task_id=12)
print()
# ffmpeg_helper = FFmpegHelper(rule="",
# video_src="111.mp4", task_id=11)
#
# ffmpeg_helper.cut_video("00:00:00", "00:00:06")
# print(ffmpeg_helper.video_info())
# ffmpeg_helper.resize_by_px(540, 540)
# # ffmpeg_helper.resize_by_coefficient(1, 5)
# print(ffmpeg_helper.video_info())
# # ffmpeg_helper.change_md5()
#
# ffmpeg_helper.video_reverse()
# ffmpeg_helper.add_bk_video(9,16)
# # ffmpeg_helper.set_video_h(360)
# # ffmpeg_helper.set_video_brightness(0.2)
# ffmpeg_helper.add_water_mark_txt("www.biadu.com", size=20, color="yellow")
# # ffmpeg_helper.add_front_video("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/video/tlp.mp4")
# # ffmpeg_helper.flip_video()
# # # ffmpeg_helper.resize_by_coefficient(0.5, 0.5)
# # ffmpeg_helper.set_speed(0.5)
# # ffmpeg_helper.set_saturated_ratio(1)
# # ffmpeg_helper.set_contrast_ratio(1)
# # ffmpeg_helper.set_sharp_ratio(1)
# #
# # ffmpeg_helper.add_video_on_begin(
# # "/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/video/ab6bc4e27c8a38a17190708fc0e17c4b.mp4")
# # ffmpeg_helper.add_video_on_end(
# # "/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/video/ab6bc4e27c8a38a17190708fc0e17c4b.mp4")
# #
# # ffmpeg_helper.add_img_on_mid("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/img/1.jpg", 1.5, 0.5,
# # "addImageMid_")
# # ffmpeg_helper.add_img_on_head("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/img/2.jpg", 0.5)
# # ffmpeg_helper.add_img_on_foot("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/img/2.jpg", 0.5)
# #
# # ffmpeg_helper.add_back_ground("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/img/2.jpg")
# #
# # ffmpeg_helper.add_bgm("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/bgm/bg.mp3")
# # ffmpeg_helper.crop_video(300, 200, 100, 100)
# # ffmpeg_helper.add_water_mark_img("/Users/c/PycharmProjects/ShortVideoTools-GetInfo-Python/data/img/2.jpg", 200, 100, 200,
# # 150)
# print(ffmpeg_helper.video_src)