欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python批量實(shí)現(xiàn)橫屏轉(zhuǎn)豎屏的視頻處理工具

 更新時(shí)間:2025年02月26日 09:35:43   作者:探客白澤  
這篇文章主要為大家詳細(xì)介紹了如何使用Python和Tkinter框架開發(fā)一個(gè)視頻處理器應(yīng)用,用于批量橫屏轉(zhuǎn)豎屏視頻處理,支持多種視頻格式和編碼選擇,需要的可以了解下

1. 簡介

這是一款基于Python和Tkinter框架開發(fā)的視頻處理器應(yīng)用。該應(yīng)用集成了FFmpeg,用于批量橫屏轉(zhuǎn)豎屏視頻處理,支持多種視頻格式和編碼選擇,并提供多線程支持以提升處理效率。用戶可以通過簡潔直觀的圖形界面導(dǎo)入、刪除視頻文件,并且對(duì)每個(gè)文件設(shè)置處理參數(shù),如輸出格式、視頻編碼器、音頻編碼器及高斯模糊效果。應(yīng)用還支持暫停/繼續(xù)和多線程并發(fā)處理,確保在長時(shí)間處理時(shí)能保持靈活性和高效性。

2.功能說明

2.1 文件管理

  • 支持通過拖放或文件選擇對(duì)話框?qū)胍曨l文件。
  • 支持刪除已導(dǎo)入的文件。
  • 顯示導(dǎo)入文件的基本信息,包括文件名和處理狀態(tài)。

2.2 FFmpeg配置

  • 用戶可以選擇視頻輸出格式(MP4、AVI、MOV等)。
  • 提供不同的視頻和音頻編碼器選項(xiàng)(如libx264、aac)。
  • 支持設(shè)置處理線程數(shù),允許用戶根據(jù)系統(tǒng)性能調(diào)整并發(fā)處理數(shù)量。
  • 可選應(yīng)用高斯模糊效果以實(shí)現(xiàn)視頻特效。

2.3 多線程處理

  • 使用ThreadPoolExecutor實(shí)現(xiàn)多線程并發(fā)處理多個(gè)視頻文件。
  • 支持暫停和繼續(xù)處理,用戶可以在處理過程中暫停視頻文件的轉(zhuǎn)換,稍后繼續(xù)。

2.4 輸出文件管理

  • 用戶可以設(shè)置輸出文件夾,處理完成的視頻會(huì)保存至該目錄。
  • 支持在處理完成后直接打開輸出文件夾。

2.5 進(jìn)度監(jiān)控與日志

  • 在文件列表中顯示每個(gè)視頻的處理進(jìn)度。
  • 提供日志框,實(shí)時(shí)顯示處理過程中的信息。

2.6 拖放支持

支持通過拖拽文件到窗口的方式導(dǎo)入視頻文件,提升用戶體驗(yàn)。

2.7 錯(cuò)誤處理與反饋

針對(duì)文件已存在、格式不支持等情況提供相應(yīng)的錯(cuò)誤提示。

3. 運(yùn)行效果

視頻處理轉(zhuǎn)換前(橫屏狀態(tài)):

視頻處理轉(zhuǎn)換后(豎屏狀態(tài)):

4. 相關(guān)源碼

import os
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import filedialog, messagebox, END, Text, StringVar, IntVar, BooleanVar, Menu
from concurrent.futures import ThreadPoolExecutor, as_completed
import subprocess
import threading
import psutil
import re
import sys
 
from tkinterdnd2 import TkinterDnD, DND_FILES
 
def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
 
    return os.path.join(base_path, relative_path)
 
class VideoProcessor:
    def __init__(self, master):
        self.master = master
        self.master.title("視頻處理器  吾愛作者:是誰的大海(是貔貅呀) 版本:1.3")
         
        self.input_files = []
        self.output_folder = ""
        self.process_thread = None
        self.pause_event = threading.Event()
        self.pause_event.set()  # Start in the unpaused state
        self.ffmpeg_processes = []  # List to keep track of all ffmpeg processes
        self.is_closing = False
         
        self.output_format = StringVar(value="mp4")
        self.video_codec = StringVar(value="libx264")
        self.audio_codec = StringVar(value="aac")
        self.thread_count = IntVar(value=1)  # Default to 1 threads
        self.apply_blur = BooleanVar(value=False)  # Boolean to check if blur should be applied
         
        self.create_widgets()
        self.create_menu()
        self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
         
    def create_widgets(self):
        frame = ttk.Frame(self.master, padding=10)
        frame.pack(fill=BOTH, expand=YES)
 
        self.file_list_frame = ttk.Frame(frame)
        self.file_list_frame.pack(fill=BOTH, expand=YES, pady=5)
 
        columns = ('序號(hào)', '文件夾名字', '進(jìn)度')
        self.file_tree = ttk.Treeview(self.file_list_frame, columns=columns, show='headings')
        self.file_tree.heading('序號(hào)', text='序號(hào)')
        self.file_tree.heading('文件夾名字', text='文件夾名字')
        self.file_tree.heading('進(jìn)度', text='進(jìn)度')
         
        self.file_tree.column('序號(hào)', width=100, anchor='center')
        self.file_tree.column('文件夾名字', width=400, anchor='w')
        self.file_tree.column('進(jìn)度', width=100, anchor='center')
         
        self.file_tree.pack(side=LEFT, fill=BOTH, expand=YES)
         
        scrollbar = ttk.Scrollbar(self.file_list_frame, orient="vertical", command=self.file_tree.yview)
        self.file_tree.configure(yscrollcommand=scrollbar.set)
        scrollbar.pack(side=RIGHT, fill=Y)
 
        self.log_text = Text(frame, height=5, state='disabled')
        self.log_text.pack(fill=BOTH, expand=YES, pady=5)
 
        button_frame = ttk.Frame(frame)
        button_frame.pack(fill=BOTH, expand=YES)
 
        self.add_files_button = ttk.Button(button_frame, text="導(dǎo)入文件", command=self.add_files, bootstyle=PRIMARY)
        self.add_files_button.pack(side=LEFT, padx=5, pady=5)
         
        self.remove_files_button = ttk.Button(button_frame, text="刪除文件", command=self.remove_files, bootstyle=DANGER)
        self.remove_files_button.pack(side=LEFT, padx=5, pady=5)
         
        self.pause_button = ttk.Button(button_frame, text="暫停/繼續(xù)", command=self.toggle_pause, bootstyle=WARNING)
        self.pause_button.pack(side=LEFT, padx=5, pady=5)
         
        self.open_output_folder_button = ttk.Button(button_frame, text="打開文件", command=self.open_output_folder, bootstyle=SUCCESS)
        self.open_output_folder_button.pack(side=LEFT, padx=5, pady=5)
         
        self.set_output_folder_button = ttk.Button(button_frame, text="導(dǎo)出文件", command=self.set_output_folder, bootstyle=SUCCESS)
        self.set_output_folder_button.pack(side=LEFT, padx=5, pady=5)
         
        self.process_button = ttk.Button(button_frame, text="開始處理文件", command=self.start_processing, bootstyle=INFO)
        self.process_button.pack(side=RIGHT, padx=5, pady=5)
         
        config_frame = ttk.LabelFrame(frame, text="FFmpeg 配置")
        config_frame.pack(fill=BOTH, expand=YES, pady=5)
         
        ttk.Label(config_frame, text="輸出格式:").pack(side=LEFT, padx=5, pady=5)
        ttk.OptionMenu(config_frame, self.output_format, "mp4", "mp4", "avi", "mov").pack(side=LEFT, padx=5, pady=5)
         
        ttk.Label(config_frame, text="視頻編碼器:").pack(side=LEFT, padx=5, pady=5)
        ttk.OptionMenu(config_frame, self.video_codec, "libx264", "libx264", "libx265", "mpeg4").pack(side=LEFT, padx=5, pady=5)
         
        ttk.Label(config_frame, text="音頻編碼器:").pack(side=LEFT, padx=5, pady=5)
        ttk.OptionMenu(config_frame, self.audio_codec, "aac", "aac", "mp3", "ac3").pack(side=LEFT, padx=5, pady=5)
         
        ttk.Label(config_frame, text="線程數(shù):").pack(side=LEFT, padx=5, pady=5)
        ttk.Entry(config_frame, textvariable=self.thread_count).pack(side=LEFT, padx=5, pady=5)
 
        self.blur_checkbox = ttk.Checkbutton(config_frame, text="應(yīng)用高斯模糊效果", variable=self.apply_blur)
        self.blur_checkbox.pack(side=LEFT, padx=5, pady=5)
 
        # Set up drag and drop
        self.master.drop_target_register(DND_FILES)
        self.master.dnd_bind('<<Drop>>', self.drop_files)
     
    def create_menu(self):
        menu_bar = Menu(self.master)
        self.master.config(menu=menu_bar)
 
        help_menu = Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="幫助", menu=help_menu)
         
        help_menu.add_command(label="使用說明", command=self.show_usage_instructions)
        help_menu.add_command(label="軟件具體說明", command=self.show_software_details)
     
    def show_usage_instructions(self):
        instructions = (
            "使用說明:\n"
            "1. 導(dǎo)入文件:點(diǎn)擊“導(dǎo)入文件”按鈕,選擇需要處理的視頻文件,或?qū)⒁曨l文件拖拽到軟件窗口中。\n"
            "2. 設(shè)置輸出文件夾:點(diǎn)擊“導(dǎo)出文件”按鈕,選擇一個(gè)文件夾作為輸出文件夾。\n"
            "3. 配置FFmpeg參數(shù):在“FFmpeg 配置”區(qū)域,選擇輸出格式、視頻編碼器、音頻編碼器、線程數(shù),并可選擇是否應(yīng)用高斯模糊效果。\n"
            "4. 開始處理:點(diǎn)擊“開始處理文件”按鈕,開始批量處理視頻文件。處理過程中可以查看處理進(jìn)度和日志信息。\n"
            "5. 查看輸出文件:點(diǎn)擊“打開文件”按鈕,打開輸出文件夾查看處理完成的視頻文件。\n"
            "6. 刪除文件:選擇文件列表中的文件,點(diǎn)擊“刪除文件”按鈕刪除不需要處理的文件。\n"
        )
        messagebox.showinfo("使用說明", instructions)
     
    def show_software_details(self):
        details = (
            "僅供學(xué)習(xí),切勿使用到其他用途\n"
            "1. 輸出格式:支持MP4、AVI和MOV等常見格式,用戶可自定義選擇。\n"
            "2. 視頻壓縮:默認(rèn)使用libx264視頻編碼器和aac音頻編碼器,支持高效視頻壓縮,用戶可自定義選擇其他編碼器。\n"
            "3. 視頻裁剪:適用于將1920x1080橫屏視頻裁剪成9:16豎屏視頻,不會(huì)變形。\n"
            "4. 高斯模糊:可選應(yīng)用高斯模糊效果,適用于特殊視頻效果需求。\n"
            "5. 多線程處理:支持多線程并發(fā)處理,用戶可自定義線程數(shù),提高處理效率。\n"
 
        )
        messagebox.showinfo("軟件具體說明", details)
         
    def drop_files(self, event):
        files = self.master.tk.splitlist(event.data)
        for file in files:
            if file not in self.input_files and file.lower().endswith(('.mp4', '.avi', '.mov')):
                self.input_files.append(file)
                self.file_tree.insert('', END, values=(len(self.input_files), os.path.basename(file), "未處理"))
                self.log(f"導(dǎo)入文件: {file}")
            else:
                messagebox.showwarning("警告", f"文件已存在或不支持的文件類型: {os.path.basename(file)}")
     
    def add_files(self):
        files = filedialog.askopenfilenames(title="選擇視頻文件", filetypes=[("視頻文件", "*.mp4 *.avi *.mov")])
        for file in files:
            if file not in self.input_files:
                self.input_files.append(file)
                self.file_tree.insert('', END, values=(len(self.input_files), os.path.basename(file), "未處理"))
                self.log(f"導(dǎo)入文件: {file}")
            else:
                messagebox.showwarning("警告", f"文件已存在: {os.path.basename(file)}")
         
    def remove_files(self):
        selected_items = self.file_tree.selection()
        indices_to_remove = []
         
        for item in selected_items:
            values = self.file_tree.item(item, 'values')
            if values:
                index = int(values[0]) - 1
                indices_to_remove.append(index)
                self.file_tree.delete(item)
         
        # 刪除索引列表中的元素(倒序刪除避免索引問題)
        for index in sorted(indices_to_remove, reverse=True):
            del self.input_files[index]
         
        self.log("刪除選中文件")
        self.refresh_file_list()
     
    def refresh_file_list(self):
        for item in self.file_tree.get_children():
            self.file_tree.delete(item)
        for index, file in enumerate(self.input_files):
            self.file_tree.insert('', END, values=(index + 1, os.path.basename(file), "未處理"))
 
    def set_output_folder(self):
        self.output_folder = filedialog.askdirectory(title="選擇輸出文件夾")
        self.log(f"設(shè)置輸出文件夾: {self.output_folder}")
         
    def start_processing(self):
        if not self.input_files or not self.output_folder:
            messagebox.showerror("錯(cuò)誤", "請(qǐng)?zhí)砑游募⒃O(shè)置輸出文件夾。")
            return
         
        self.process_thread = threading.Thread(target=self.process_videos_concurrently)
        self.process_thread.start()
         
    def toggle_pause(self):
        if self.pause_event.is_set():
            self.pause_event.clear()
            self.log("處理暫停")
            for process in self.ffmpeg_processes:
                proc = psutil.Process(process.pid)
                proc.suspend()
        else:
            self.pause_event.set()
            self.log("處理繼續(xù)")
            for process in self.ffmpeg_processes:
                proc = psutil.Process(process.pid)
                proc.resume()
     
    def open_output_folder(self):
        if self.output_folder:
            os.startfile(self.output_folder)
            self.log(f"打開輸出文件夾: {self.output_folder}")
        else:
            messagebox.showerror("錯(cuò)誤", "請(qǐng)先設(shè)置輸出文件夾。")
     
    def log(self, message):
        if not self.is_closing:
            self.master.after(0, self._log, message)
     
    def _log(self, message):
        if not self.is_closing:
            self.log_text.configure(state='normal')
            self.log_text.insert(END, message + '\n')
            self.log_text.configure(state='disabled')
            self.log_text.yview(END)
     
    def update_tree_status(self, index, status):
        if not self.is_closing:
            self.master.after(0, self._update_tree_status, index, status)
     
    def _update_tree_status(self, index, status):
        if not self.is_closing:
            self.file_tree.item(self.file_tree.get_children()[index], values=(index + 1, os.path.basename(self.input_files[index]), status))
     
    def process_videos_concurrently(self):
        max_workers = self.thread_count.get()
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            futures = [executor.submit(self.process_video, index, input_file) for index, input_file in enumerate(self.input_files)]
            for future in as_completed(futures):
                future.result()
 
    def process_video(self, index, input_file):
        ffmpeg_path = resource_path(os.path.join("ffmpeg_folder", "ffmpeg"))
        filename = os.path.basename(input_file)
        output_file = os.path.join(self.output_folder, f"processed_{filename}.{self.output_format.get()}")
 
        if os.path.exists(output_file):
            overwrite = messagebox.askyesno("文件已存在", f"{output_file} 已存在,是否覆蓋?")
            if not overwrite:
                self.update_tree_status(index, "跳過")
                return
 
        if self.apply_blur.get():
            cmd = [
                ffmpeg_path,
                "-y",  # 自動(dòng)覆蓋輸出文件
                "-i", input_file,
                "-vf", "split[a][b];[a]scale=1080:1920,boxblur=10:5[1];[b]scale=1080:ih*1080/iw[2];[1][2]overlay=0:(H-h)/2",
                "-c:v", self.video_codec.get(),
                "-crf", "18",
                "-preset", "veryfast",
                "-aspect", "9:16",
                "-c:a", self.audio_codec.get(),
                output_file
            ]
        else:
            cmd = [
                ffmpeg_path,
                "-y",  # 自動(dòng)覆蓋輸出文件
                "-i", input_file,
                "-vf", "scale='if(gt(iw/ih,9/16),1080,-2)':'if(gt(iw/ih,9/16),-2,1920)',pad=1080:1920:(1080-iw)/2:(1920-ih)/2",
                "-c:v", self.video_codec.get(),
                "-crf", "18",
                "-preset", "veryfast",
                "-c:a", self.audio_codec.get(),
                output_file
            ]
 
        self.log(f"開始處理: {filename}")
        self.update_tree_status(index, "處理中")
 
        try:
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
 
            process = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True, encoding='utf-8', startupinfo=startupinfo)
            self.ffmpeg_processes.append(process)
 
            for line in process.stderr:
                if self.is_closing:
                    break
                progress = self.parse_progress(line)
                if progress:
                    self.update_tree_status(index, progress)
 
            process.wait()
        except Exception as e:
            self.log(f"處理文件時(shí)出錯(cuò): {filename} - {str(e)}")
            self.update_tree_status(index, "處理失敗")
            return
 
        if self.is_closing:
            self.update_tree_status(index, "未完成")
        else:
            self.log(f"完成處理: {filename}")
            self.update_tree_status(index, "已完成")
            self.ffmpeg_processes.remove(process)
     
    def parse_progress(self, line):
        match = re.search(r'time=(\d+:\d+:\d+\.\d+)', line)
        if match:
            return f"進(jìn)度: {match.group(1)}"
        return None
     
    def on_closing(self):
        self.is_closing = True
        for process in self.ffmpeg_processes:
            proc = psutil.Process(process.pid)
            proc.terminate()
        self.master.destroy()
 
if __name__ == "__main__":
    root = TkinterDnD.Tk()
    root.title("視頻處理器")
    root.geometry("870x520")  # Set the window size to 870x520
    root.resizable(False, False)  # Make the window non-resizable
    app = VideoProcessor(master=root)
    root.mainloop()

5.總結(jié)

該視頻處理器應(yīng)用通過Python與Tkinter提供了一個(gè)強(qiáng)大而簡潔的圖形界面,允許用戶批量處理視頻文件。借助FFmpeg,用戶不僅可以自由選擇輸出格式和編碼器,還可以根據(jù)需求應(yīng)用視頻特效,如高斯模糊。多線程的支持使得處理多個(gè)視頻文件更加高效,確保了在處理過程中能夠靈活控制暫停、繼續(xù)和取消操作。通過增強(qiáng)的文件管理和進(jìn)度監(jiān)控,用戶能夠輕松掌控整個(gè)視頻處理過程。此工具對(duì)于需要批量轉(zhuǎn)換視頻格式或應(yīng)用特效的用戶非常實(shí)用,尤其適合需要高效處理大量視頻文件的場景。

以上就是Python批量實(shí)現(xiàn)橫屏轉(zhuǎn)豎屏的視頻處理工具的詳細(xì)內(nèi)容,更多關(guān)于Python視頻橫屏轉(zhuǎn)豎屏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于pygame實(shí)現(xiàn)貪吃蛇小游戲示例

    基于pygame實(shí)現(xiàn)貪吃蛇小游戲示例

    大家好,本篇文章主要講的是基于pygame實(shí)現(xiàn)貪吃蛇小游戲示例,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Python可視化神器pyecharts繪制折線圖詳情

    Python可視化神器pyecharts繪制折線圖詳情

    這篇文章主要介紹了Python可視化神器pyecharts繪制折線圖詳情,折線圖和柱狀圖一樣是我們?nèi)粘?梢暬疃嗟囊粋€(gè)圖例,當(dāng)然它的優(yōu)勢和適用場景相信大家肯定不陌生,要想快速的得出趨勢,抓住趨勢二字,就會(huì)很快的想到要用折線圖來表示了
    2022-07-07
  • Python 專題五 列表基礎(chǔ)知識(shí)(二維list排序、獲取下標(biāo)和處理txt文本實(shí)例)

    Python 專題五 列表基礎(chǔ)知識(shí)(二維list排序、獲取下標(biāo)和處理txt文本實(shí)例)

    本文主要簡單的介紹使用Python處理txt漢字文字、二維列表排序和獲取list下標(biāo)的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-03-03
  • Python使用Networkx實(shí)現(xiàn)復(fù)雜的人物關(guān)系圖

    Python使用Networkx實(shí)現(xiàn)復(fù)雜的人物關(guān)系圖

    日常工作、生活中我們經(jīng)常會(huì)遇到一些復(fù)雜的事務(wù)關(guān)系,比如人物關(guān)系,那如何才能清楚直觀的看清楚這些任務(wù)關(guān)系呢?所以小編給大家介紹了Python如何使用Networkx實(shí)現(xiàn)復(fù)雜的人物關(guān)系圖,文中通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Python機(jī)器學(xué)習(xí)之隨機(jī)梯度下降法的實(shí)現(xiàn)

    Python機(jī)器學(xué)習(xí)之隨機(jī)梯度下降法的實(shí)現(xiàn)

    如果當(dāng)我們數(shù)據(jù)量和樣本量非常大時(shí),每一項(xiàng)都要參與到梯度下降,那么它的計(jì)算量時(shí)非常大的,所以我們需要采用隨機(jī)梯度下降法。本文介紹了Python實(shí)現(xiàn)隨機(jī)梯度下降法的方法,希望對(duì)大家有所幫助
    2023-02-02
  • Python圖片視頻超分模型RealBasicVSR的使用教程

    Python圖片視頻超分模型RealBasicVSR的使用教程

    這篇文章主要和大家分享一個(gè)有意思的模型:RealBasicVSR。這個(gè)模型可以實(shí)現(xiàn)圖片或視頻的超分處理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-05-05
  • Django中如何使用Celery執(zhí)行異步任務(wù)

    Django中如何使用Celery執(zhí)行異步任務(wù)

    這篇文章主要介紹了Django中如何使用Celery執(zhí)行異步任務(wù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • python水晶球(函數(shù))詳解

    python水晶球(函數(shù))詳解

    大家好,本篇文章主要講的是python水晶球(函數(shù))詳解,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 選擇Python寫網(wǎng)絡(luò)爬蟲的優(yōu)勢和理由

    選擇Python寫網(wǎng)絡(luò)爬蟲的優(yōu)勢和理由

    在本篇文章里小編給各位整理了一篇關(guān)于選擇Python寫網(wǎng)絡(luò)爬蟲的優(yōu)勢和理由以及相關(guān)代碼實(shí)例,有興趣的朋友們閱讀下吧。
    2019-07-07
  • 利用pyinstaller或virtualenv將python程序打包詳解

    利用pyinstaller或virtualenv將python程序打包詳解

    這篇文章主要給大家介紹了利用pyinstaller將python程序打包的相關(guān)資料,文中介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。
    2017-03-03

最新評(píng)論