Spaces:
Running
Running
File size: 6,147 Bytes
ac5e4c8 fe72b7c ac5e4c8 fe72b7c ac5e4c8 60ab7b2 ac5e4c8 60ab7b2 ac5e4c8 60ab7b2 ac5e4c8 60ab7b2 ac5e4c8 fe72b7c ac5e4c8 fe72b7c ac5e4c8 3bce222 fe72b7c ac5e4c8 fe72b7c ac5e4c8 fe72b7c ac5e4c8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
import gradio as gr
import subprocess
import os
import tempfile
import shutil
from video_merger import merge_videos
def extract_last_frame(video_file):
if video_file is None:
return None, "請上傳影片檔案"
try:
# 創建固定名稱的輸出檔案
temp_output = tempfile.mktemp(suffix='.jpg')
# 獲取影片總幀數
frame_count_cmd = [
'ffprobe',
'-v', 'error',
'-select_streams', 'v:0',
'-count_frames',
'-show_entries', 'stream=nb_read_frames',
'-of', 'default=nokey=1:noprint_wrappers=1',
video_file
]
frame_result = subprocess.run(frame_count_cmd, capture_output=True, text=True)
# 如果無法獲取幀數,使用反向讀取方法
if not frame_result.stdout.strip() or frame_result.returncode != 0:
# 方法2: 使用 select 過濾器選擇最後一幀
extract_cmd = [
'ffmpeg',
'-i', video_file,
'-vf', 'select=eq(n\\,0)',
'-vsync', '0',
'-q:v', '2',
'-frames:v', '1',
temp_output,
'-y'
]
# 先嘗試從尾部讀取
extract_cmd_reverse = [
'ffmpeg',
'-sseof', '-3',
'-i', video_file,
'-vframes', '1',
'-vf', 'select=eq(pict_type\\,I)',
'-vsync', '0',
'-q:v', '2',
temp_output,
'-y'
]
result = subprocess.run(extract_cmd_reverse, capture_output=True, text=True)
# 如果失敗,使用標準方法
if result.returncode != 0 or not os.path.exists(temp_output):
subprocess.run(extract_cmd, capture_output=True, text=True)
else:
# 方法1: 使用幀數選擇最後一幀
total_frames = int(frame_result.stdout.strip())
last_frame = total_frames - 1
extract_cmd = [
'ffmpeg',
'-i', video_file,
'-vf', f'select=eq(n\\,{last_frame})',
'-vsync', '0',
'-q:v', '2',
'-frames:v', '1',
temp_output,
'-y'
]
subprocess.run(extract_cmd, check=True, capture_output=True)
if os.path.exists(temp_output) and os.path.getsize(temp_output) > 0:
# 重新命名為 lastframe.jpg
output_dir = tempfile.gettempdir()
final_output = os.path.join(output_dir, 'lastframe.jpg')
shutil.copy2(temp_output, final_output)
os.remove(temp_output)
return final_output, "成功提取最後一幀!"
else:
return None, "提取失敗,請確認影片格式正確"
except subprocess.CalledProcessError as e:
return None, f"處理錯誤: {str(e)}"
except Exception as e:
return None, f"發生錯誤: {str(e)}"
def merge_videos_wrapper(video_files):
"""包裝合併函數以處理檔名"""
if not video_files:
return None, "請上傳影片檔案"
temp_output, message = merge_videos(video_files)
if temp_output and os.path.exists(temp_output):
# 重新命名為 final.mp4
output_dir = tempfile.gettempdir()
final_output = os.path.join(output_dir, 'final.mp4')
shutil.copy2(temp_output, final_output)
os.remove(temp_output)
return final_output, message
else:
return None, message
# 創建 Gradio 界面
with gr.Blocks(title="Grok影片工具箱") as demo:
gr.Markdown("# Grok影片工具箱")
gr.Markdown("提供影片最後一幀提取和多段影片合併功能")
with gr.Tabs():
# Tab 1: 提取最後一幀
with gr.Tab("提取最後一幀"):
gr.Markdown("上傳影片(最大 100MB),自動提取最後一幀為 JPEG 圖片")
with gr.Row():
with gr.Column():
video_input = gr.Video(
label="上傳影片",
max_length=None,
height=400
)
extract_btn = gr.Button("提取最後一幀", variant="primary")
with gr.Column():
image_output = gr.Image(
label="最後一幀 (lastframe.jpg)",
type="filepath",
height=400
)
status_output = gr.Textbox(label="狀態", interactive=False)
extract_btn.click(
fn=extract_last_frame,
inputs=[video_input],
outputs=[image_output, status_output]
)
# Tab 2: 合併影片
with gr.Tab("合併影片"):
gr.Markdown("上傳多個 MP4 影片,按照上傳順序合併為一個影片")
with gr.Row():
with gr.Column():
videos_input = gr.File(
label="上傳影片檔案(可多選)",
file_count="multiple",
file_types=["video"],
height=300
)
merge_btn = gr.Button("合併影片", variant="primary")
with gr.Column():
merged_video_output = gr.Video(
label="合併後的影片 (final.mp4)",
height=400
)
merge_status_output = gr.Textbox(label="狀態", interactive=False)
merge_btn.click(
fn=merge_videos_wrapper,
inputs=[videos_input],
outputs=[merged_video_output, merge_status_output]
)
if __name__ == "__main__":
demo.launch()
|