ffmpeg 实现视频转码
什么是视频编码
视频上传成功后需要对视频进行转码处理。
什么是视频编码?
查阅百度百科如下:
首先我们要分清文件格式和编码格式:
- 文件格式:是指
.mp4
、.avi
、.rmvb
等 - 这些不同扩展名的视频文件的文件格式,视频文件的内容主要包括视频和音频,其文件格式是按照一定的编码格式去编码,并且按照该文件所规定的封装格式将视频、音频、字幕等信息封装在一起,
- 播放器会根据它们的封装格式去提取出编码,然后由播放器解码,最终播放音视频。
音视频编码格式:通过音视频的压缩技术,将视频格式转换成另一种视频格式,通过视频编码实现流媒体的传输。比如:一个 .avi
的视频文件原来的编码是 a,通过编码后编码格式变为 b,音频原来为 c,通过编码后变为 d。
音视频编码格式各类繁多,主要有几下几类:
MPEG 系列
- (由 ISO[国际标准组织机构] 下属的 MPEG[运动图象专家组] 开发 )视频编码方面主要是 Mpeg1(vcd 用的就是它)、Mpeg2(DVD 使用)、Mpeg4(的 DVDRIP 使用的都是它的变种,如:divx,xvid 等)、Mpeg4 AVC(正热门);
- 音频编码方面主要是 MPEG Audio Layer 1/2、MPEG Audio Layer 3(大名鼎鼎的 mp3)、MPEG-2 AAC 、MPEG-4 AAC 等等。
- 注意:DVD 音频没有采用 Mpeg 的。
H.26X 系列
- (由 ITU[国际电传视讯联盟] 主导,侧重网络传输,注意:只是视频编码)包括 H.261、H.262、H.263、H.263+、H.263++、H.264(就是 MPEG4 AVC-合作的结晶)
- 目前最常用的编码标准是视频 H.264,音频 AAC。
提问:
H.264 是编码格式还是文件格式?
H.264(也称为 AVC,即高级视频编码)是一种视频编码格式,也就是一种视频压缩标准。它定义了如何对视频数据进行压缩、编码与解码。
- 简单来说,H.264 描述的是视频数据的压缩算法,而不是存储文件的格式。
- 通常,我们会将经过 H.264 编码的视频数据存储在不同的容器文件中,例如 MP4、MKV、AVI 等。
mp4 是编码格式还是文件格式?
MP4(MPEG-4 Part 14)是一种容器文件格式。它用于存储多媒体数据,比如视频、音频、字幕等。容器格式本身不定义视频或音频如何编码,而是作为一个“包装”,能够包含多种编码格式的数据。
常见的情况是:
- 视频部分使用 H.264 编码,
- 音频部分使用 AAC 编码,
- 然后一起存储在 MP4 文件中。
小结
- H.264:是一种视频编码标准,用于压缩视频数据。
- MP4:是一种容器格式,用于存储音视频数据,可以包含使用 H.264 编码的视频和其他编码格式的音频数据。
代码示例
@Slf4j
public class FfmpegProcess {
static String inputFile = VideoConstant.VIDEO_FILE_PATH1;
static String inputFile2 = VideoConstant.VIDEO_INPUT_PATH;
static String transcodeFile = VideoConstant.OUTPUT_FILE_PREFIX + "\\transcode.avi";
public static void main(String[] args) throws Exception {
String command = getVideoTranscodeCommand(inputFile2, transcodeFile);
System.out.println("执行命令: " + command);
// 创建操作系统进程
ProcessBuilder builder = new ProcessBuilder();
// 执行命令
executeCommand(builder, command, "windows");
// 合并标准输出和标准错误输出流
builder.redirectErrorStream(true);
Process process = builder.start();
// 异步读取输出流,避免阻塞
CompletableFuture<Void> future = readOutputAsync(process.getInputStream());
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("执行成功");
} else {
System.err.println("执行过程中出现错误,退出代码:" + exitCode);
}
}
/**
* 获取视频转码的命令
*
* @param inputFile 输入文件路径
* @param transcodeFile 转码文件路径
* @return 视频转码的命令
*/
private static String getVideoTranscodeCommand(String inputFile, String transcodeFile) {
return String.format("%s -y -i %s %s", VideoConstant.FFMPEG_PATH, inputFile, transcodeFile);
}
/**
* 异步读取 ffmpeg 输出流
*/
private static CompletableFuture<Void> readOutputAsync(InputStream inputStream) {
return CompletableFuture.runAsync(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
log.error("读取 ffmpeg 输出流异常", e);
}
});
}
/**
* 执行命令
*
* @param builder 进程构建器
* @param command 命令
* @param osType 操作系统类型
*/
private static void executeCommand(ProcessBuilder builder, String command, String osType) {
switch (osType) {
case "windows":
builder.command("cmd", "/c", command);
break;
case "Linux":
case "macOS":
builder.command("bash", "-c", command);
break;
default:
throw new RuntimeException("不支持的操作系统类型");
}
}
}