工具-使用ffmpeg命令做一个快捷视频裁剪小助手

233 阅读4分钟

工作中经常需要对一个视频进行裁剪,比如一个视频有20s,只需要裁剪其中的5-10s即可。当然有PS等工具可以使用,但是比较麻烦,因为要安装还要熟悉使用方法,作为程序员,学了ffmpeg,就可以自己做一个视频裁剪工具了。

1、先介绍工具

这里我定义为视频裁剪小助手,功能目前是单一的,当然在这个基础上也可以做视频合并、渲染、加动效等特殊操作,通过本文章的说明,相信你可以设计出来:

3de7ec72-bc95-4496-acd6-f407c35e6e49.png

2、小工具实现方法

2.1 使用的环境 界面是使用 pycharm + pyqy5 环境完成的。 1、直接在pycharm环境中创建一个新项目,然后创建一个py脚本,就可以开始编写了

image.png

2.2 利用pyQt5创建UI界面

使用ui进行绘制页面,更加的具体形象,绘制完成之后,使用pyuic转为python,直接引用即可

image.png

3、所有的代码

main.py

import os
import sys
import ffmpeg
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QApplication, QPushButton, QMainWindow, QFileDialog, QTextBrowser, QTextEdit, QMessageBox
from cutVideo import Ui_MainWindow


class CutVideo(QMainWindow, Ui_MainWindow):
    global_video_path = ''

    def __init__(self):
        # 从文件中加载UI定义
        # self.ui = uic.loadUi("cutVideo.ui")
        # self.slot_init()  # 初始化槽函数
        super(CutVideo, self).__init__()
        self.setupUi(self)
        self.slot_init()  # 初始化槽函数

    '''初始化所有槽函数'''
    def slot_init(self):
        # 这个是选择视频之后显示出来的视频文件信息
        self.selectVideoInfoText = self.findChild(QTextBrowser, 'text_select_video_file_info')
        # 这个是选择视频的按钮
        self.openVideoButton = self.findChild(QPushButton, 'button_open_video_file')
        self.openVideoButton.clicked.connect(self.open_file)

        # 截取视频的开始时间,比如01
        self.cutVideoStartTime = self.findChild(QTextEdit, 'cut_video_start_time')
        # 截取视频的结束时间,比如13
        self.cutVideoEndTime = self.findChild(QTextEdit, 'cut_video_end_time')

        # 截取视频的按钮
        self.cutVideoButton = self.findChild(QPushButton, 'button_cut_video_file')
        self.cutVideoButton.clicked.connect(self.cut_video_file)

        # 截取视频成功之后跳转到对应文件夹的按钮
        self.openCutVideoButton = self.findChild(QPushButton, 'button_open_cut_video_file')
        self.openCutVideoButton.clicked.connect(self.open_cut_video_folder)
        self.openCutVideoButton.setVisible(False)

    def open_file(self):
        self.openCutVideoButton.setVisible(False)
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, "Open File", "", "Video Files (*.mp4 *.mov *.avi *.mkv *.wmv *.flv)", options=options)
        if fileName:
            CutVideo.global_video_path = str(fileName)
            duration = self.get_video_info(CutVideo.global_video_path)
            self.selectVideoInfoText.setText(f'你选择的文件是: \n\n {fileName} \n\n 视频长度是 {duration} 秒')
            print(f'Selected file: ' + CutVideo.global_video_path)

    def cut_video_file(self):
        startTimeStr = self.cutVideoStartTime.toPlainText()
        endTimeStr = self.cutVideoEndTime.toPlainText()
        try:
            startTimeInt = int(startTimeStr)
            endTimeInt = int(endTimeStr)
            print(f"cut video and startTimeInt is {startTimeInt} endTimeInt is {endTimeInt}")
            if startTimeInt > endTimeInt:
                QMessageBox.information(self, "Info", "截取开始时间大于截取结束时间")
                return
        except ValueError:
            print("The input is not a valid integer")

        # 取选择视频文件的文件夹
        folder_path = os.path.dirname(CutVideo.global_video_path)
        # 在相同的文件夹输出截取后的视频
        output_video = folder_path + 'output.mp4'
        start_time = f'00:00:{startTimeStr}'
        end_time = f'00:00:{endTimeStr}'
        print(f"cutVideo and global_video_path: {CutVideo.global_video_path}")
        try:
            ffmpeg.input(CutVideo.global_video_path).filter('trim', start=start_time, end=end_time).output(output_video).run()
            self.openCutVideoButton.setVisible(True)
        except ffmpeg.Error as e:
            self.openCutVideoButton.setVisible(False)

    def get_video_info(self, source_video_path):
        probe = ffmpeg.probe(source_video_path)
        print('source_video_path: {}'.format(source_video_path))
        format = probe['format']
        bit_rate = int(format['bit_rate']) / 1000
        duration = format['duration']
        size = int(format['size']) / 1024 / 1024
        video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
        if video_stream is None:
            print('No video stream found!')
            return
        width = int(video_stream['width'])
        height = int(video_stream['height'])
        num_frames = int(video_stream['nb_frames'])
        fps = int(video_stream['r_frame_rate'].split('/')[0]) / int(video_stream['r_frame_rate'].split('/')[1])
        duration = float(video_stream['duration'])
        print('width: {}'.format(width))
        print('height: {}'.format(height))
        print('num_frames: {}'.format(num_frames))
        print('bit_rate: {}k'.format(bit_rate))
        print('fps: {}'.format(fps))
        print('size: {}MB'.format(size))
        print('duration: {}'.format(duration))
        return duration

    def open_cut_video_folder(self):
        folder_path = os.path.dirname(CutVideo.global_video_path)
        url = QUrl.fromLocalFile(folder_path)
        QDesktopServices.openUrl(url)


if __name__ == '__main__':
    App = QApplication(sys.argv)  # 创建QApplication对象,作为GUI主程序入口
    stats = CutVideo()
    stats.show()
    sys.exit(App.exec_())

cutVideo.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'cutVideo.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(10, 20, 201, 16))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(10, 210, 311, 16))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_2.setFont(font)
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(10, 420, 201, 16))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label_3.setFont(font)
        self.label_3.setObjectName("label_3")
        self.button_open_video_file = QtWidgets.QPushButton(self.centralwidget)
        self.button_open_video_file.setGeometry(QtCore.QRect(60, 60, 121, 41))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setBold(True)
        font.setWeight(75)
        self.button_open_video_file.setFont(font)
        self.button_open_video_file.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.button_open_video_file.setStyleSheet("background-color: rgb(223, 223, 223);")
        self.button_open_video_file.setObjectName("button_open_video_file")
        self.cut_video_start_time = QtWidgets.QTextEdit(self.centralwidget)
        self.cut_video_start_time.setGeometry(QtCore.QRect(110, 250, 104, 31))
        self.cut_video_start_time.setObjectName("cut_video_start_time")
        self.label_select_video_info_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_select_video_info_2.setGeometry(QtCore.QRect(40, 250, 71, 21))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(9)
        self.label_select_video_info_2.setFont(font)
        self.label_select_video_info_2.setObjectName("label_select_video_info_2")
        self.cut_video_end_time = QtWidgets.QTextEdit(self.centralwidget)
        self.cut_video_end_time.setGeometry(QtCore.QRect(110, 300, 104, 31))
        self.cut_video_end_time.setObjectName("cut_video_end_time")
        self.label_select_video_info_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_select_video_info_3.setGeometry(QtCore.QRect(40, 300, 71, 21))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(9)
        self.label_select_video_info_3.setFont(font)
        self.label_select_video_info_3.setObjectName("label_select_video_info_3")
        self.text_select_video_file_info = QtWidgets.QTextBrowser(self.centralwidget)
        self.text_select_video_file_info.setGeometry(QtCore.QRect(210, 60, 541, 81))
        self.text_select_video_file_info.setStyleSheet("background-color: rgb(0, 0, 0);\n"
"color: rgb(255, 255, 255);")
        self.text_select_video_file_info.setObjectName("text_select_video_file_info")
        self.button_cut_video_file = QtWidgets.QPushButton(self.centralwidget)
        self.button_cut_video_file.setGeometry(QtCore.QRect(60, 460, 121, 41))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setBold(True)
        font.setWeight(75)
        self.button_cut_video_file.setFont(font)
        self.button_cut_video_file.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.button_cut_video_file.setStyleSheet("background-color: rgb(223, 223, 223);")
        self.button_cut_video_file.setObjectName("button_cut_video_file")
        self.button_open_cut_video_file = QtWidgets.QPushButton(self.centralwidget)
        self.button_open_cut_video_file.setGeometry(QtCore.QRect(240, 460, 171, 41))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setBold(True)
        font.setWeight(75)
        self.button_open_cut_video_file.setFont(font)
        self.button_open_cut_video_file.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.button_open_cut_video_file.setStyleSheet("background-color: rgb(255, 170, 0);\n"
"color: rgb(255, 255, 255);")
        self.button_open_cut_video_file.setObjectName("button_open_cut_video_file")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 23))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "视频裁剪"))
        self.label.setText(_translate("MainWindow", "第1步:打开视频文件"))
        self.label_2.setText(_translate("MainWindow", "第2步:设置截取开始时间和结束时间"))
        self.label_3.setText(_translate("MainWindow", "第3步:可以截取视频了"))
        self.button_open_video_file.setText(_translate("MainWindow", "打开视频文件"))
        self.cut_video_start_time.setPlaceholderText(_translate("MainWindow", "01"))
        self.label_select_video_info_2.setText(_translate("MainWindow", "开始时间:"))
        self.cut_video_end_time.setPlaceholderText(_translate("MainWindow", "13"))
        self.label_select_video_info_3.setText(_translate("MainWindow", "结束始时间:"))
        self.button_cut_video_file.setText(_translate("MainWindow", "截取视频"))
        self.button_open_cut_video_file.setText(_translate("MainWindow", "打开截取成功的视频文件"))

完整的代码使用命令: pyinstaller --onefile --windowed main.py

运行之后,就可以在工程根目录下面生成dist文件夹,运行exe文件即可正常使用

image.png