处理视频帧率的完整解决方案

HTML代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>视频帧率处理器</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        accent: '#8B5CF6',
                        dark: '#1E293B',
                        light: '#F8FAFC'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .transition-custom {
                transition: all 0.3s ease-in-out;
            }
            .shadow-custom {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
            }
            .progress-bar {
                height: 4px;
                background: linear-gradient(90deg, #3B82F6 0%, #8B5CF6 100%);
                transform-origin: left;
                transform: scaleX(0);
                transition: transform 0.3s ease;
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen flex flex-col">
    <!-- 导航栏 -->
    <header class="bg-white shadow-md sticky top-0 z-50">
        <div class="container mx-auto px-4 py-3 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-film text-primary text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold text-dark">视频帧率处理器</h1>
            </div>
            <nav class="hidden md:flex space-x-6">
                <a href="#" class="text-gray-700 hover:text-primary transition-custom">首页</a>
                <a href="#features" class="text-gray-700 hover:text-primary transition-custom">功能</a>
                <a href="#about" class="text-gray-700 hover:text-primary transition-custom">关于</a>
            </nav>
            <button class="md:hidden text-gray-700 focus:outline-none">
                <i class="fa fa-bars text-xl"></i>
            </button>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="flex-grow container mx-auto px-4 py-8">
        <!-- 介绍部分 -->
        <section class="mb-12 text-center max-w-3xl mx-auto">
            <h2 class="text-[clamp(1.8rem,3vw,2.5rem)] font-bold text-dark mb-4">轻松调整视频帧率</h2>
            <p class="text-gray-600 text-lg mb-8">上传视频文件,选择目标帧率,一键处理并下载优化后的视频</p>
            <div class="flex flex-wrap justify-center gap-4">
                <div class="flex items-center px-4 py-2 bg-blue-50 rounded-full">
                    <i class="fa fa-check-circle text-primary mr-2"></i>
                    <span>高质量处理</span>
                </div>
                <div class="flex items-center px-4 py-2 bg-blue-50 rounded-full">
                    <i class="fa fa-check-circle text-primary mr-2"></i>
                    <span>快速转换</span>
                </div>
                <div class="flex items-center px-4 py-2 bg-blue-50 rounded-full">
                    <i class="fa fa-check-circle text-primary mr-2"></i>
                    <span>多种格式支持</span>
                </div>
            </div>
        </section>

        <!-- 视频处理区域 -->
        <section class="bg-white rounded-xl shadow-custom p-6 md:p-8 max-w-4xl mx-auto mb-12">
            <div class="grid grid-cols-1 md:grid-cols-2 gap-8 items-center">
                <!-- 左侧:视频预览 -->
                <div class="rounded-lg overflow-hidden border-2 border-gray-200 relative">
                    <div id="preview-container" class="w-full h-64 md:h-80 bg-gray-100 flex items-center justify-center">
                        <i class="fa fa-film text-gray-300 text-6xl"></i>
                        <p class="text-gray-400 mt-4">上传视频后在此预览</p>
                    </div>
                    <video id="preview-video" class="w-full h-full object-contain hidden" controls></video>
                </div>

                <!-- 右侧:处理选项 -->
                <div>
                    <h3 class="text-xl font-semibold text-dark mb-4">视频设置</h3>
                    
                    <!-- 文件上传 -->
                    <div class="mb-6">
                        <label class="block text-gray-700 mb-2">选择视频文件</label>
                        <div class="relative">
                            <input type="file" id="video-upload" accept="video/*" class="hidden">
                            <label for="video-upload" class="block w-full px-4 py-3 bg-primary/10 text-primary rounded-lg border-2 border-dashed border-primary/30 cursor-pointer hover:bg-primary/20 transition-custom text-center">
                                <i class="fa fa-upload mr-2"></i> 点击上传视频
                            </label>
                        </div>
                        <p id="file-name" class="text-sm text-gray-500 mt-2 hidden"></p>
                    </div>

                    <!-- 帧率选择 -->
                    <div class="mb-6">
                        <label for="fps" class="block text-gray-700 mb-2">目标帧率 (FPS)</label>
                        <div class="flex items-center">
                            <input type="range" id="fps-slider" min="5" max="60" value="30" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
                            <span id="fps-value" class="ml-3 min-w-[3rem] text-center font-medium">30</span>
                        </div>
                        <div class="flex justify-between text-xs text-gray-500 mt-1">
                            <span>5 FPS</span>
                            <span>60 FPS</span>
                        </div>
                    </div>

                    <!-- 按钮组 -->
                    <div class="flex flex-wrap gap-3">
                        <button id="process-btn" class="flex-1 px-6 py-3 bg-primary text-white rounded-lg hover:bg-primary/90 transition-custom shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center">
                            <i class="fa fa-cog mr-2"></i> 处理视频
                        </button>
                        <button id="download-btn" class="flex-1 px-6 py-3 bg-secondary text-white rounded-lg hover:bg-secondary/90 transition-custom shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center" disabled>
                            <i class="fa fa-download mr-2"></i> 下载视频
                        </button>
                    </div>
                </div>
            </div>

            <!-- 进度条 -->
            <div id="progress-container" class="mt-6 hidden">
                <div class="h-4 bg-gray-200 rounded-full overflow-hidden">
                    <div id="progress-bar" class="progress-bar h-full"></div>
                </div>
                <p id="progress-text" class="text-sm text-gray-600 mt-2 text-center">处理中...</p>
            </div>
        </section>

        <!-- 功能特点 -->
        <section id="features" class="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-5xl mx-auto mb-16">
            <div class="bg-white p-6 rounded-xl shadow-custom hover:shadow-lg transition-custom">
                <div class="w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center mb-4">
                    <i class="fa fa-bolt text-primary text-xl"></i>
                </div>
                <h3 class="text-lg font-semibold text-dark mb-2">快速处理</h3>
                <p class="text-gray-600">利用高效算法和优化技术,确保视频处理速度快且质量高。</p>
            </div>
            
            <div class="bg-white p-6 rounded-xl shadow-custom hover:shadow-lg transition-custom">
                <div class="w-12 h-12 bg-accent/10 rounded-full flex items-center justify-center mb-4">
                    <i class="fa fa-sliders text-accent text-xl"></i>
                </div>
                <h3 class="text-lg font-semibold text-dark mb-2">灵活控制</h3>
                <p class="text-gray-600">精确调整视频帧率,满足不同场景需求,从慢动作到高速播放。</p>
            </div>
            
            <div class="bg-white p-6 rounded-xl shadow-custom hover:shadow-lg transition-custom">
                <div class="w-12 h-12 bg-secondary/10 rounded-full flex items-center justify-center mb-4">
                    <i class="fa fa-shield-alt text-secondary text-xl"></i>
                </div>
                <h3 class="text-lg font-semibold text-dark mb-2">安全可靠</h3>
                <p class="text-gray-600">本地处理视频,不会上传到服务器,确保您的视频内容安全。</p>
            </div>
        </section>

        <!-- 关于部分 -->
        <section id="about" class="bg-white rounded-xl shadow-custom p-6 md:p-8 max-w-4xl mx-auto">
            <h3 class="text-xl font-semibold text-dark mb-4">关于视频帧率处理</h3>
            <p class="text-gray-600 mb-4">
                帧率(FPS,Frames Per Second)是视频的重要参数,影响视频的流畅度和文件大小。较高的帧率(如60 FPS)使视频更加流畅,适合动作场景;较低的帧率(如15 FPS)则可减小文件大小,但可能显得不够流畅。
            </p>
            <p class="text-gray-600">
                本工具允许您根据需要调整视频帧率,无论是为了创建特殊效果、优化视频大小,还是适配特定设备。我们使用先进的视频处理技术,确保在转换过程中保持视频质量。
            </p>
        </section>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark text-white py-8">
        <div class="container mx-auto px-4">
            <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
                <div>
                    <h4 class="text-lg font-semibold mb-4">视频帧率处理器</h4>
                    <p class="text-gray-400">轻松调整视频帧率,优化您的视频体验。</p>
                </div>
                <div>
                    <h4 class="text-lg font-semibold mb-4">联系我们</h4>
                    <ul class="space-y-2 text-gray-400">
                        <li class="flex items-center">
                            <i class="fa fa-envelope mr-2"></i>
                            <a href="mailto:support@example.com" class="hover:text-white transition-custom">support@example.com</a>
                        </li>
                        <li class="flex items-center">
                            <i class="fa fa-phone mr-2"></i>
                            <span>+86 123 4567 8901</span>
                        </li>
                    </ul>
                </div>
                <div>
                    <h4 class="text-lg font-semibold mb-4">关注我们</h4>
                    <div class="flex space-x-4">
                        <a href="#" class="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-custom">
                            <i class="fa fa-weixin"></i>
                        </a>
                        <a href="#" class="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-custom">
                            <i class="fa fa-weibo"></i>
                        </a>
                        <a href="#" class="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-custom">
                            <i class="fa fa-github"></i>
                        </a>
                    </div>
                </div>
            </div>
            <div class="border-t border-gray-700 mt-8 pt-6 text-center text-gray-400">
                <p>&copy; 2023 视频帧率处理器 | 保留所有权利</p>
            </div>
        </div>
    </footer>

    <script>
        // DOM 元素
        const videoUpload = document.getElementById('video-upload');
        const previewContainer = document.getElementById('preview-container');
        const previewVideo = document.getElementById('preview-video');
        const fileName = document.getElementById('file-name');
        const fpsSlider = document.getElementById('fps-slider');
        const fpsValue = document.getElementById('fps-value');
        const processBtn = document.getElementById('process-btn');
        const downloadBtn = document.getElementById('download-btn');
        const progressContainer = document.getElementById('progress-container');
        const progressBar = document.getElementById('progress-bar');
        const progressText = document.getElementById('progress-text');

        let processedVideoUrl = null;

        // 监听文件上传
        videoUpload.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (!file) return;

            // 显示文件名
            fileName.textContent = `已选择: ${file.name}`;
            fileName.classList.remove('hidden');

            // 预览视频
            const videoUrl = URL.createObjectURL(file);
            previewVideo.src = videoUrl;
            previewVideo.classList.remove('hidden');
            previewContainer.classList.add('hidden');

            // 启用处理按钮
            processBtn.disabled = false;
        });

        // 监听帧率滑块
        fpsSlider.addEventListener('input', () => {
            fpsValue.textContent = fpsSlider.value;
        });

        // 处理视频按钮点击
        processBtn.addEventListener('click', async () => {
            const file = videoUpload.files[0];
            if (!file) return;

            const targetFps = parseInt(fpsSlider.value);

            // 显示进度条
            progressContainer.classList.remove('hidden');
            progressBar.style.transform = 'scaleX(0)';
            progressText.textContent = '准备处理视频...';

            // 禁用按钮
            processBtn.disabled = true;
            downloadBtn.disabled = true;

            try {
                // 模拟处理进度
                await simulateProgress(targetFps);

                // 处理完成,启用下载按钮
                downloadBtn.disabled = false;
                progressText.textContent = '处理完成!';
                
                // 创建一个模拟的处理后视频URL(实际项目中应从服务器获取)
                processedVideoUrl = createMockProcessedVideoUrl(file, targetFps);
            } catch (error) {
                console.error('处理视频时出错:', error);
                progressText.textContent = '处理失败,请重试';
            }
        });

        // 下载按钮点击
        downloadBtn.addEventListener('click', () => {
            if (!processedVideoUrl) return;

            // 创建下载链接
            const a = document.createElement('a');
            a.href = processedVideoUrl;
            a.download = `processed_${fileName.textContent.split(': ')[1].split('.')[0]}_${fpsSlider.value}fps.mp4`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        });

        // 模拟处理进度(实际项目中应从服务器获取进度)
        async function simulateProgress(targetFps) {
            return new Promise((resolve) => {
                let progress = 0;
                const interval = setInterval(() => {
                    progress += Math.random() * 10;
                    if (progress >= 100) {
                        progress = 100;
                        clearInterval(interval);
                        resolve();
                    }
                    
                    progressBar.style.transform = `scaleX(${progress / 100})`;
                    progressText.textContent = `处理中: ${Math.round(progress)}% - 调整至 ${targetFps} FPS`;
                }, 200);
            });
        }

        // 创建模拟的处理后视频URL(实际项目中应从服务器获取)
        function createMockProcessedVideoUrl(originalFile, targetFps) {
            // 在实际项目中,这里应该是从服务器获取的处理后视频URL
            // 这里仅作演示,返回原始视频URL
            return URL.createObjectURL(originalFile);
        }

        // 平滑滚动
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>

server.py

import os
import subprocess
from flask import Flask, request, jsonify, send_file
from werkzeug.utils import secure_filename
import uuid

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['PROCESSED_FOLDER'] = 'processed'
app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 500  # 500MB

# 创建上传和处理文件夹
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
os.makedirs(app.config['PROCESSED_FOLDER'], exist_ok=True)

@app.route('/')
def index():
    return "视频帧率处理API"

@app.route('/process', methods=['POST'])
def process_video():
    # 检查是否有文件上传
    if 'video' not in request.files:
        return jsonify({"error": "未找到视频文件"}), 400
    
    video_file = request.files['video']
    
    # 检查文件是否有名称
    if video_file.filename == '':
        return jsonify({"error": "未选择视频文件"}), 400
    
    # 检查文件扩展名是否为视频格式
    allowed_extensions = {'mp4', 'avi', 'mov', 'mkv', 'webm'}
    file_ext = video_file.filename.rsplit('.', 1)[1].lower()
    if file_ext not in allowed_extensions:
        return jsonify({"error": "不支持的文件格式"}), 400
    
    # 生成安全的文件名
    secure_name = secure_filename(video_file.filename)
    unique_id = str(uuid.uuid4())
    upload_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{unique_id}_{secure_name}")
    video_file.save(upload_path)
    
    # 获取目标帧率
    target_fps = request.form.get('fps', 30)
    try:
        target_fps = int(target_fps)
        if target_fps < 5 or target_fps > 120:
            target_fps = 30
    except ValueError:
        target_fps = 30
    
    # 处理视频
    processed_filename = f"{unique_id}_processed_{target_fps}fps.mp4"
    processed_path = os.path.join(app.config['PROCESSED_FOLDER'], processed_filename)
    
    try:
        # 使用FFmpeg处理视频帧率
        ffmpeg_cmd = [
            'ffmpeg',
            '-i', upload_path,
            '-r', str(target_fps),
            '-c:v', 'libx264',
            '-preset', 'medium',
            '-crf', '23',
            '-c:a', 'aac',
            '-strict', 'experimental',
            '-b:a', '128k',
            processed_path
        ]
        
        # 执行FFmpeg命令
        process = subprocess.run(
            ffmpeg_cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        
        if process.returncode != 0:
            print("FFmpeg错误:", process.stderr)
            return jsonify({"error": "视频处理失败"}), 500
        
        # 处理成功,返回结果
        return jsonify({
            "success": True,
            "original_filename": video_file.filename,
            "processed_filename": processed_filename,
            "target_fps": target_fps,
            "download_url": f"/download/{processed_filename}"
        })
    
    except Exception as e:
        print("处理异常:", str(e))
        return jsonify({"error": "服务器内部错误"}), 500
    finally:
        # 清理上传的原始文件(可选)
        # os.remove(upload_path)
        pass

@app.route('/download/<filename>')
def download_processed_file(filename):
    processed_path = os.path.join(app.config['PROCESSED_FOLDER'], filename)
    
    if not os.path.exists(processed_path):
        return jsonify({"error": "文件不存在"}), 404
    
    return send_file(processed_path, as_attachment=True)

if __name__ == '__main__':
    app.run(debug=True)    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万能小贤哥

感谢大捞

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值