Spaces:
Running
Running
| import gradio as gr | |
| import subprocess | |
| import os | |
| import tempfile | |
| def extract_last_frame(video_file): | |
| if video_file is None: | |
| return None, "請上傳影片檔案" | |
| try: | |
| # 創建臨時輸出檔案 | |
| output_path = tempfile.mktemp(suffix='.jpg') | |
| # 使用 ffmpeg 獲取影片總幀數並提取最後一幀 | |
| # 先獲取影片時長 | |
| duration_cmd = [ | |
| 'ffprobe', | |
| '-v', 'error', | |
| '-show_entries', 'format=duration', | |
| '-of', 'default=noprint_wrappers=1:nokey=1', | |
| video_file | |
| ] | |
| duration_result = subprocess.run(duration_cmd, capture_output=True, text=True) | |
| duration = float(duration_result.stdout.strip()) | |
| # 提取最後一幀 (從最後0.1秒處提取) | |
| extract_cmd = [ | |
| 'ffmpeg', | |
| '-sseof', '-0.1', | |
| '-i', video_file, | |
| '-update', '1', | |
| '-frames:v', '1', | |
| '-q:v', '2', | |
| output_path, | |
| '-y' | |
| ] | |
| subprocess.run(extract_cmd, check=True, capture_output=True) | |
| if os.path.exists(output_path) and os.path.getsize(output_path) > 0: | |
| return output_path, "成功提取最後一幀!" | |
| else: | |
| return None, "提取失敗,請確認影片格式正確" | |
| except subprocess.CalledProcessError as e: | |
| return None, f"處理錯誤: {str(e)}" | |
| except Exception as e: | |
| return None, f"發生錯誤: {str(e)}" | |
| # 創建 Gradio 界面 | |
| with gr.Blocks(title="影片最後一幀提取器") as demo: | |
| gr.Markdown("# 影片最後一幀提取器") | |
| 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="最後一幀", | |
| 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] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |