# FFmpeg Java API **Repository Path**: shileicode_master/ffmpeg-java-api ## Basic Information - **Project Name**: FFmpeg Java API - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-02-04 - **Last Updated**: 2026-02-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # FFmpeg Java API 基于Spring Boot 3.x的FFmpeg常用操作REST API服务,支持视频转码、压缩(包括按比例压缩)、音频提取、视频截图、音频拼接和音视频合成等功能。 ## 技术栈 - Spring Boot 3.x - Spring MVC - Spring Data MongoDB - Redis (轻量队列/缓存) - AWS S3 (文件存储) - OkHttp3 (HTTP/HTTPS文件下载) - FFmpeg (音视频处理) ## 项目结构 ``` src/main/java/com/ffmpeg/api/ ├── controller/ffmpeg/ # REST API控制器 ├── controller/ai/ # AI扩展层控制器 ├── service/ffmpeg/ # 核心业务逻辑 ├── service/ai/ # AI扩展层服务 ├── service/task/ # 后台任务消费器 ├── dao/ # MongoDB数据访问 ├── entity/ # 实体类 ├── entity/ai/ # AI扩展层实体类 ├── util/ # 工具类 ├── util/ai/ # AI扩展层工具类 └── config/ # 配置类 ``` ## 核心功能 ### 1. 视频转码 将视频转换为不同格式,支持多种目标格式。 ### 2. 视频压缩 支持两种压缩模式: - **固定分辨率压缩**:支持720p、480p等固定分辨率 - **按比例压缩**:支持自定义压缩比例,如75%、50%、25%等 ### 3. 无损压缩 使用容器级无损压缩,直接复制音视频流,不重新编码,保持原始质量。 ### 4. 音频提取 从视频中提取音频,支持多种音频格式。 ### 5. 视频截图 从视频的指定时间点提取截图,支持多种图片格式。 ### 6. 音频拼接 将多个音频文件拼接成一个,支持多种音频格式。 ### 7. 音视频合成 将音频和视频合成为一个文件,支持多种合成模式: - 音频主体模式 - 视频主体模式 - 固定时长模式 ## AI扩展层配置 在`application.yml`文件中添加AI接口配置: ```yaml app: ai: base-url: "https://ark.cn-beijing.volces.com/api/v3/chat/completions" # 即梦AI API地址 api-key: "your-api-key" # 即梦AI API密钥 model: "ep-20240601170147-p2g9v" # 即梦AI模型ID ``` ## AI扩展层使用示例 ### 端到端测试示例 1. **生成FFmpeg命令并绑定动态API** ```bash curl -X POST http://localhost:8080/api/ai/ffmpeg/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "把 mp4 视频转成 720P 的 mkv,码率 2000k,提取音频为 mp3"}' ``` 2. **调用生成的动态API** ```bash curl -X POST http://localhost:8080/api/ffmpeg/ai/123e4567-e89b-12d3-a456-426614174000 \ -H "Content-Type: application/json" \ -d '{"file_url": "https://example.com/video.mp4"}' ``` 3. **查询处理结果** ```bash curl http://localhost:8080/api/ffmpeg/task/{taskId} ``` 4. **获取S3地址** 从查询结果中获取`outputUrl`字段,即为处理后的文件在S3上的地址。 ### 异常场景测试 1. **AI调用失败** - 配置错误的API密钥 - 网络连接问题 - 响应:`{"code": 500, "message": "AI调用失败: ...", "data": null}` 2. **命令语法错误** - AI生成了错误的FFmpeg命令 - 响应:`{"code": 500, "message": "命令语法错误", "data": null}` 3. **动态API创建失败** - MongoDB连接问题 - 响应:`{"code": 500, "message": "动态API创建失败", "data": null}` ## API接口 ### 1. AI生成FFmpeg命令 + 自动绑定动态API - **请求路径**: `/api/ai/ffmpeg/generate` - **请求方法**: POST - **请求体**: ```json { "prompt": "把 mp4 视频转成 720P 的 mkv,码率 2000k,提取音频为 mp3" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": { "taskId": "task_1234567890", "apiPath": "/ffmpeg/ai/123e4567-e89b-12d3-a456-426614174000", "ffmpegCmd": "ffmpeg -i {input_file} -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k {output_file}", "inputSchema": "{\"type\": \"object\", \"properties\": {\"file_url\": {\"type\": \"string\", \"required\": true}}}" } } ``` ### 2. 视频转码 - **请求路径**: `/api/ffmpeg/transcode` - **请求方法**: POST - **请求体**: ```json { "file_url": "https://example.com/video.mp4", "targetFormat": "avi" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 3. 视频压缩 - **请求路径**: `/api/ffmpeg/compress` - **请求方法**: POST - **请求体**: ```json { "file_url": "https://example.com/video.mp4", "resolution": "720p", // 支持固定分辨率(720p/480p)或按比例压缩(如50%) "bitRate": "2000k" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 4. 无损压缩 - **请求路径**: `/api/ffmpeg/lossless-compress` - **请求方法**: POST - **请求体**: ```json { "file_url": "https://example.com/video.mp4", "compressType": "video" // 支持video或audio } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 5. 音频提取 - **请求路径**: `/api/ffmpeg/extract-audio` - **请求方法**: POST - **请求体**: ```json { "file_url": "https://example.com/video.mp4", "audioFormat": "mp3" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 6. 视频截图 - **请求路径**: `/api/ffmpeg/snapshot` - **请求方法**: POST - **请求体**: ```json { "file_url": "https://example.com/video.mp4", "timeFrame": "00:01:00", "imgFormat": "png" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 7. 音频拼接 - **请求路径**: `/api/ffmpeg/concat-audio` - **请求方法**: POST - **请求体**: ```json { "file_urls": [ "https://example.com/audio1.mp3", "https://example.com/audio2.mp3" ], "audioFormat": "mp3", "s3Path": "openlist/2026-02-01/" // 可选,指定上传到S3的路径 } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 8. 音视频合成 - **请求路径**: `/api/ffmpeg/compose` - **请求方法**: POST - **请求体**: ```json { "composeMode": "audio-main", // audio-main, video-main, fixed-duration "duration": "60", // 固定时长模式下的时长(秒) "adaptMode": "loop", // loop, stretch, pad "keepOriginalAudio": false, "video_input": "https://example.com/video.mp4", "audio_input": "https://example.com/audio.mp3" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "taskId" } ``` ### 9. 结果查询 - **请求路径**: `/api/ffmpeg/result/{taskId}` - **请求方法**: GET - **响应**: ```json { "code": 200, "message": "success", "data": { "id": "taskId", "ffmpegCmd": "ffmpeg command", "inputParams": { "file_urls": [ "https://example.com/audio1.mp3", "https://example.com/audio2.mp3" ], "audioFormat": "mp3", "s3Path": "openlist/2026-02-01/" }, "outputParams": { "s3_url": "https://s3.amazonaws.com/bucket/openlist/2026-02-01/taskId/output.mp3", "file_name": "output.mp3" }, "status": "SUCCESS", "errorMsg": null, "createTime": "2024-01-01T12:00:00", "updateTime": "2024-01-01T12:01:00" } } ``` ### 10. 参数说明 | 参数名 | 类型 | 必填 | 说明 | 适用接口 | | --- | --- | --- | --- | --- | | file_url | String | 是 | 文件URL | 转码、压缩、音频提取、视频截图、无损压缩 | | file_urls | Array | 是 | 多个文件URL,用于拼接 | 音频拼接 | | targetFormat | String | 是 | 目标格式,可选值:avi/mkv/mp4 | 转码 | | resolution | String | 是 | 分辨率,可选值:720p/480p 或压缩比例(如50%) | 压缩 | | bitRate | String | 否 | 比特率,例如:2000k | 压缩 | | compressType | String | 是 | 压缩类型:video/audio | 无损压缩 | | audioFormat | String | 是 | 音频格式,可选值:mp3/wav | 音频提取、音频拼接 | | timeFrame | String | 是 | 时间点,格式:00:01:00 | 视频截图 | | imgFormat | String | 是 | 图片格式,可选值:png/jpg | 视频截图 | | s3Path | String | 否 | 上传到S3的路径,例如:openlist/2026-02-01/ | 所有接口 | | composeMode | String | 是 | 合成模式:audio-main/video-main/fixed-duration | 音视频合成 | | duration | String | 否 | 固定时长(fixed-duration模式) | 音视频合成 | | adaptMode | String | 否 | 适配方式:loop/stretch/pad | 音视频合成 | | keepOriginalAudio | Boolean | 否 | 是否保留原视频音频 | 音视频合成 | | video_input | String | 是 | 视频输入文件URL | 音视频合成 | | audio_input | String | 是 | 音频输入文件URL | 音视频合成 | ### 3. 配置说明 - **核心配置文件**: `src/main/resources/application.yml` **主要配置项**: 1. **服务器配置** - `server.port`: 服务端口 - `server.servlet.context-path`: API 前缀 2. **存储配置** - `spring.data.mongodb.uri`: MongoDB 连接字符串 - `spring.data.redis`: Redis 连接配置 - `spring.datasource`: PostgreSQL 连接配置 3. **应用配置** - `app.temp-dir`: 临时文件目录 - `app.s3`: S3 存储配置 - `app.ffmpeg.path`: FFmpeg 可执行文件路径 - `app.rate-limit`: 限流配置 - `app.ai`: AI 相关配置 **配置方法**: 项目使用环境变量进行配置,所有敏感信息均通过环境变量注入。配置步骤如下: 1. **复制环境变量示例文件**: ```bash cp .env.example .env ``` 2. **编辑 .env 文件**: 根据实际情况填写配置值,例如: ``` # MongoDB 配置 MONGODB_URI=mongodb://username:password@host:port/database # Redis 配置 REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD= ``` 3. **启动应用**: 应用会自动加载 `.env` 文件中的环境变量。 ## 快速开始 ### 1. 环境配置 **本地开发配置**: 1. 复制 `.env.example` 为 `.env` 文件 2. 编辑 `.env` 文件,填入相应的配置值 3. 启动应用,Spring Boot 会自动加载 `.env` 文件中的环境变量 **示例命令**: ```bash # 复制示例配置文件 cp .env.example .env # 编辑配置文件(根据实际情况修改) # 启动应用 mvn spring-boot:run ``` ### 2. 项目构建 ```bash # 构建项目(跳过测试) mvn clean package -DskipTests ``` ### 3. Docker 部署 **构建 Docker 镜像**: ```bash docker build -t ffmpeg-java-api:1.0.0 . ``` **运行 Docker 容器**: **基础运行**(使用默认配置): ```bash docker run -d \ -p 8080:8080 \ --name ffmpeg-java-api \ ffmpeg-java-api:1.0.0 ``` **自定义配置运行**(使用环境变量文件): ```bash docker run -d \ -p 8080:8080 \ --name ffmpeg-java-api \ --env-file .env \ ffmpeg-java-api:1.0.0 ``` **生产环境运行**(挂载卷和资源限制): ```bash docker run -d \ -p 8080:8080 \ --name ffmpeg-java-api \ --env-file .env \ -v /path/to/temp:/app/temp \ -v /path/to/logs:/app/logs \ --restart unless-stopped \ --cpus 2 \ --memory 4g \ ffmpeg-java-api:1.0.0 ``` ### 4. 验证部署 **检查容器状态**: ```bash docker ps -a | grep ffmpeg-java-api ``` **查看容器日志**: ```bash docker logs ffmpeg-java-api ``` **测试健康检查接口**: ```bash curl http://localhost:8080/actuator/health ``` ### 5. API 使用方式 **视频压缩**: - **请求**:`POST /api/ffmpeg/compress` - **参数**: - `file`:视频文件(multipart/form-data) - `targetSize`:目标大小(可选,单位:MB) - `crf`:压缩质量(可选,范围:0-51,默认:23) - **响应**:压缩后的视频文件 **视频格式转换**: - **请求**:`POST /api/ffmpeg/convert` - **参数**: - `file`:视频文件(multipart/form-data) - `format`:目标格式(如:mp4, webm, avi) - **响应**:转换后的视频文件 **视频剪辑**: - **请求**:`POST /api/ffmpeg/cut` - **参数**: - `file`:视频文件(multipart/form-data) - `startTime`:开始时间(如:00:00:00) - `endTime`:结束时间(如:00:01:00) - **响应**:剪辑后的视频文件 **视频合并**: - **请求**:`POST /api/ffmpeg/merge` - **参数**: - `files`:多个视频文件(multipart/form-data) - **响应**:合并后的视频文件 **音频提取**: - **请求**:`POST /api/ffmpeg/extract-audio` - **参数**: - `file`:视频文件(multipart/form-data) - `format`:音频格式(如:mp3, aac, wav) - **响应**:提取的音频文件 **视频信息获取**: - **请求**:`POST /api/ffmpeg/info` - **参数**: - `file`:视频文件(multipart/form-data) - **响应**:视频详细信息(JSON) ### 6. 其他服务器快速部署 **步骤**: 1. **克隆项目**: ```bash git clone cd ffmpeg-java-api ``` 2. **配置环境变量**: ```bash cp .env.example .env # 编辑 .env 文件,填入相应的配置值 ``` 3. **构建和运行**: ```bash # 构建 Docker 镜像 docker build -t ffmpeg-java-api:1.0.0 . # 运行容器 docker run -d -p 8080:8080 --name ffmpeg-java-api --env-file .env ffmpeg-java-api:1.0.0 ``` 4. **验证部署**: ```bash curl http://localhost:8080/actuator/health ``` ### 5. Gitee 托管指南 #### 5.1 项目托管步骤 1. **创建 Gitee 仓库** - 登录 Gitee 账号 - 点击「新建仓库」 - 填写仓库名称(如 `ffmpeg-java-api`) - 选择公开或私有 - 点击「创建」 2. **初始化本地仓库** ```bash # 进入项目目录 cd ffmpeg-java-api # 初始化 Git 仓库 git init # 添加远程仓库 git remote add origin https://gitee.com/your-username/ffmpeg-java-api.git # 添加文件 git add . # 提交代码 git commit -m "Initial commit" # 推送代码 git push -u origin master ``` #### 5.2 密钥配置管理 项目已配置 `.gitignore` 文件,确保以下文件不会被提交到版本控制系统: - `.env` 文件(环境变量配置) - `target/` 目录(构建产物) - IDE 配置文件 **环境变量配置方法**: 1. **本地开发**: - 复制 `.env.example` 文件为 `.env` - 编辑 `.env` 文件,填写实际的配置值 - 启动应用时会自动加载 `.env` 文件中的环境变量 2. **Docker 部署**: - 使用 `-e` 参数传递环境变量 - 或使用 `--env-file` 参数指定环境变量文件 - 详细配置请参考 [Docker 部署指南](#docker-部署指南) 部分 ### 6. 环境变量配置说明 项目使用以下环境变量进行配置,所有敏感信息均通过环境变量注入,确保安全: | 类别 | 环境变量 | 说明 | 示例值 | |------|----------|------|--------| | 服务器 | SERVER_PORT | 服务器端口 | 8080 | | 服务器 | API_PREFIX | API 前缀 | /api/ffmpeg | | MongoDB | MONGODB_URI | MongoDB 连接字符串 | mongodb://username:password@host:port/database | | Redis | REDIS_HOST | Redis 主机 | localhost | | Redis | REDIS_PORT | Redis 端口 | 6379 | | Redis | REDIS_USERNAME | Redis 用户名 | | | Redis | REDIS_PASSWORD | Redis 密码 | | | Redis | REDIS_DB | Redis 数据库索引 | 0 | | PostgreSQL | POSTGRES_URL | PostgreSQL 连接 URL | jdbc:postgresql://localhost:5432/postgres | | PostgreSQL | POSTGRES_USER | PostgreSQL 用户名 | postgres | | PostgreSQL | POSTGRES_PASSWORD | PostgreSQL 密码 | postgres | | S3 存储 | S3_BUCKET_NAME | S3 存储桶名称 | your-bucket-name | | S3 存储 | S3_REGION | S3 区域 | your-region | | S3 存储 | S3_ACCESS_KEY | S3 访问密钥 | your-access-key | | S3 存储 | S3_SECRET_KEY | S3 密钥 | your-secret-key | | S3 存储 | S3_ENDPOINT | S3 端点 URL | https://s3.example.com | | FFmpeg | FFMPEG_PATH | FFmpeg 可执行文件路径 | ffmpeg | | 限流 | RATE_LIMIT_PER_MINUTE | 每分钟请求限制 | 60 | | AI | AI_JIMENG_API_KEY | 即梦AI API密钥 | your-jimeng-api-key | | AI | AI_JIMENG_API_URL | 即梦AI API URL | https://api.jimeng.io/v1/chat/completions | | AI | AI_TIMEOUT | AI 请求超时时间 | 60 | | AI | AI_FALLBACK_ENABLE | 是否启用降级方案 | false | | AI | AI_FALLBACK_API_URL | 降级方案 API URL | https://api.openai.com/v1/chat/completions | | AI | AI_FALLBACK_API_KEY | 降级方案 API 密钥 | your-fallback-api-key | | 临时目录 | TEMP_DIR | 临时文件目录 | /tmp/ffmpeg-temp | **注意**:所有敏感信息(如密码、API 密钥)必须通过环境变量配置,不得硬编码在代码中。 ## 任务处理流程 1. 客户端发送FFmpeg操作请求 2. 服务器生成唯一taskId,创建任务并保存到MongoDB 3. 服务器将taskId推入Redis队列 4. 后台任务消费器从Redis队列获取任务 5. 下载文件到本地临时目录 6. 执行FFmpeg命令处理文件 7. 上传处理后的文件到S3 8. 更新任务状态到MongoDB 9. 清理本地临时文件 10. 客户端通过taskId查询处理结果 ## 核心工具类 ### FfmpegCmdUtil 核心工具类,用于生成各种FFmpeg命令: - `generateTranscodeCmd`: 生成视频转码命令 - `generateCompressCmd`: 生成视频压缩命令(支持固定分辨率和按比例压缩) - `generateLosslessCompressVideoCmd`: 生成视频无损压缩命令 - `generateLosslessCompressAudioCmd`: 生成音频无损压缩命令 - `generateExtractAudioCmd`: 生成音频提取命令 - `generateSnapshotCmd`: 生成视频截图命令 - `generateAudioConcatCmd`: 生成音频拼接命令 - `generateVideoAudioComposeCmd`: 生成音视频合成命令 - `validateFfmpegCommand`: 验证FFmpeg命令的语法 - `executeCommand`: 执行FFmpeg命令 ### 按比例压缩功能 `generateCompressCmd`方法支持按比例压缩,通过以下方式实现: 1. 检查`resolution`参数是否以`%`结尾 2. 如果是比例压缩模式,提取比例值并转换为小数 3. 使用FFmpeg的`scale`滤镜实现按比例缩放:`-vf scale=iw*0.5:-1` 4. 如果是传统固定分辨率模式,使用`-s`参数设置具体像素值 ### 无损压缩功能 无损压缩使用容器级压缩,直接复制音视频流,不重新编码: - 视频无损压缩:`ffmpeg -i {input} -c:v copy -c:a copy {output}.mp4` - 音频无损压缩:`ffmpeg -i {input} -c:a copy {output}.mp3` ## 动态API框架 ### 简介 基于Spring MVC原生动态路由实现的动态API框架,支持运行时创建、管理和调用基于FFmpeg任务的动态API。 ### 核心组件 - **DynamicFfmpegApi**: 动态API配置实体类,与FfmpegTask通过taskId关联 - **DynamicApiHandler**: 动态API的核心处理器,处理动态API的请求 - **DynamicApiRegister**: 动态路由注册器,基于RequestMappingHandlerMapping实现动态路由的注册和删除 - **DynamicApiService**: 动态API业务逻辑处理服务 - **DynamicApiController**: 动态API管理控制器,提供动态API的CRUD操作 ### 动态API管理接口 #### 1. 创建动态API - **请求路径**: `/api/dynamic/ffmpeg/create` - **请求方法**: POST - **请求体**: ```json { "apiPath": "/ffmpeg/ai/gen_123", "taskId": "taskId", "inputSchema": "{\"file_url\":\"required\",\"format\":\"optional\"}" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "API创建成功" } ``` #### 2. 查询动态API - **请求路径**: `/api/dynamic/ffmpeg/query` - **请求方法**: GET - **请求参数**: - taskId (可选): 关联的任务ID - apiPath (可选): 动态API路径 - **响应**: ```json { "code": 200, "message": "success", "data": { "id": "uuid", "apiPath": "/ffmpeg/ai/gen_123", "requestMethod": "POST", "taskId": "taskId", "inputSchema": "{\"file_url\":\"required\",\"format\":\"optional\"}", "createTime": "2024-01-01T12:00:00" } } ``` #### 3. 删除动态API - **请求路径**: `/api/dynamic/ffmpeg/delete` - **请求方法**: POST - **请求体**: ```json { "apiPath": "/ffmpeg/ai/gen_123" } ``` - **响应**: ```json { "code": 200, "message": "success", "data": "API删除成功" } ``` ### 动态API使用示例 #### 1. 创建动态API ```bash curl -X POST http://localhost:8080/api/dynamic/ffmpeg/create \ -H "Content-Type: application/json" \ -d '{ "apiPath": "/ffmpeg/ai/gen_123", "taskId": "taskId", "inputSchema": "{\"file_url\":\"required\",\"format\":\"optional\"}" }' ``` #### 2. 调用动态API ```bash curl -X POST http://localhost:8080/ffmpeg/ai/gen_123 \ -H "Content-Type: application/json" \ -d '{ "file_url": "https://example.com/video.mp4", "format": "avi" }' ``` #### 3. 查询动态API ```bash curl -X GET "http://localhost:8080/api/dynamic/ffmpeg/query?apiPath=/ffmpeg/ai/gen_123" ``` #### 4. 删除动态API ```bash curl -X POST http://localhost:8080/api/dynamic/ffmpeg/delete \ -H "Content-Type: application/json" \ -d '{ "apiPath": "/ffmpeg/ai/gen_123" }' ``` ### 动态API工作流程 1. 客户端创建动态API,指定apiPath、taskId和inputSchema 2. 服务器验证apiPath唯一性,创建DynamicFfmpegApi实体并保存到MongoDB 3. 服务器通过DynamicApiRegister注册动态路由 4. 客户端调用动态API,发送请求 5. DynamicApiHandler接收请求,解析入参,验证inputSchema 6. 根据taskId查询FfmpegTask,执行FFmpeg命令 7. 将taskId推入Redis队列,由后台任务消费器处理 8. 返回统一的ApiResult,包含taskId 9. 客户端通过taskId查询处理结果 ## 注意事项 - 确保已安装FFmpeg并添加到系统PATH - 确保MongoDB和Redis服务正在运行 - 配置 `application.yml` 中的相关参数 - 对于大文件处理,可能需要调整临时目录大小和HTTP超时设置 - 动态API的apiPath必须唯一,且格式正确 - 动态API与FfmpegTask强关联,taskId不存在则无法创建动态API - 在Windows环境下,执行FFmpeg命令时,文件路径需要用双引号包裹,特别是包含空格或中文的路径 - 按比例压缩时,使用FFmpeg的scale滤镜实现,格式为:`-vf scale=iw*0.5:-1`,其中0.5为压缩比例 - 无损压缩使用容器级压缩,直接复制音视频流,不重新编码,因此文件大小基本不变