最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

1. 簡(jiǎn)介

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

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

相關(guān)文章

  • Python爬蟲爬取ts碎片視頻+驗(yàn)證碼登錄功能

    Python爬蟲爬取ts碎片視頻+驗(yàn)證碼登錄功能

    這篇文章主要介紹了Python爬蟲爬取ts碎片視頻+驗(yàn)證碼登錄功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • python中列表對(duì)象pop()方法的使用說明

    python中列表對(duì)象pop()方法的使用說明

    這篇文章主要介紹了python中列表對(duì)象pop()方法的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Python利用matplotlib.pyplot繪圖時(shí)如何設(shè)置坐標(biāo)軸刻度

    Python利用matplotlib.pyplot繪圖時(shí)如何設(shè)置坐標(biāo)軸刻度

    Matplotlib是Python提供的一個(gè)二維繪圖庫,所有類型的平面圖,包括直方圖、散點(diǎn)圖、折線圖、點(diǎn)圖、熱圖以及其他各種類型,都能由Python制作出來。本文主要介紹了關(guān)于Python利用matplotlib.pyplot繪圖時(shí)如何設(shè)置坐標(biāo)軸刻度的相關(guān)資料,需要的朋友可以參考下。
    2018-04-04
  • Pandas讀取外部數(shù)據(jù)的幾種實(shí)現(xiàn)方法

    Pandas讀取外部數(shù)據(jù)的幾種實(shí)現(xiàn)方法

    本文主要介紹了Pandas讀取外部數(shù)據(jù)的幾種實(shí)現(xiàn)方法,主要包括文本文件、Excel文件、JSON文件以及數(shù)據(jù)庫文件(MySQL/PostgreSQL)的讀取方式,感興趣的可以了解一下
    2026-04-04
  • Python生成隨機(jī)密碼的方法

    Python生成隨機(jī)密碼的方法

    這篇文章主要為大家詳細(xì)介紹了Python生成隨機(jī)密碼的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • python3圖片轉(zhuǎn)換二進(jìn)制存入mysql

    python3圖片轉(zhuǎn)換二進(jìn)制存入mysql

    MYSQL是支持把圖片存入數(shù)據(jù)庫的,也相應(yīng)的有一個(gè)專門的字段BLOB (Binary Large Object),即較大的二進(jìn)制對(duì)象字段,看下面代碼
    2013-12-12
  • Python實(shí)現(xiàn)arctan換算角度的示例

    Python實(shí)現(xiàn)arctan換算角度的示例

    本文主要介紹了Python實(shí)現(xiàn)arctan換算角度的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • selenium+python 去除啟動(dòng)的黑色cmd窗口方法

    selenium+python 去除啟動(dòng)的黑色cmd窗口方法

    今天小編就為大家分享一篇selenium+python 去除啟動(dòng)的黑色cmd窗口方法。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python實(shí)現(xiàn)對(duì)adb命令封裝

    Python實(shí)現(xiàn)對(duì)adb命令封裝

    這篇文章主要介紹了Python實(shí)現(xiàn)對(duì)adb命令封裝,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • python PyGame五子棋小游戲

    python PyGame五子棋小游戲

    大家好,本篇文章主要講的是python PyGame五子棋小游戲,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01

最新評(píng)論

卓资县| 大城县| 洛阳市| 姜堰市| 达孜县| 东城区| 乌拉特中旗| 刚察县| 绍兴市| 安宁市| 石屏县| 金堂县| 沙坪坝区| 乃东县| 思南县| 德江县| 惠水县| 清远市| 宜宾市| 武穴市| 亳州市| 务川| 曲麻莱县| 肥乡县| 昌宁县| 金溪县| 柏乡县| 保康县| 奉新县| 徐汇区| 芒康县| 云梦县| 靖宇县| 马尔康县| 阜南县| 云南省| 府谷县| 惠州市| 石阡县| 昌黎县| 栾川县|