ffmpeg视频转码相关
- 简介
- 参数
- 实战举栗子
- 获取视频时长
- 视频转码
- mp4文件转为hls m3u8 ts等文件
- 图片转视频
- 抽取视频第一帧
- 获取基本信息
- 转码日志输出详解
- 转码耗时测试
简介
FFmpeg 是领先的多媒体框架,能够解码、编码、 转码、复用、解复用、流、过滤和播放 几乎所有人类和机器创建的东西。
ffmpeg官网: https://ffmpeg.org/
ffmpeg中文网: https://ffmpeg.p2hp.com/
参数
-
基本操作
输入文件
-i input.mp4:指定输入文件。输出文件
output.mp4:指定输出文件名称。
-
视频参数
设置分辨率
-s 1280x720:设置输出视频的分辨率(宽x高)。设置帧率
-r 24:设置输出视频的帧率(帧每秒,FPS)。设置视频码率
-b:v 2000k:设置视频码率(比特率)。设置GOP大小
-g 48:设置GOP(组图像)大小,通常与帧率相关。设置封面
-ss 00:00:01:从指定时间点截取一帧作为封面(配合 -vframes 1 使用)。
-
音频参数
设置音频码率
-b:a 128k:设置音频码率。设置采样率
-ar 44100:设置音频采样率。选择音频通道
-ac 2:设置音频通道数(如立体声为2)。
- 格式转换
指定输出格式
-f mp4:强制指定输出格式。
-
截图和分片
截图
-ss 00:00:05 -vframes 1 output.jpg:从第5秒时间点截取一帧并保存为图片。分片输出
-f segment -segment_time 10 -c copy output%03d.mp4:将视频每10秒切成一个分片。
-
音视频同步
同步音视频
-async 1:在流式传输中同步音视频。声音延迟
-itsoffset 0.5 -i input.mp4:调整声音与视频的同步(+延迟/-提前)。
-
旋转或翻转视频
旋转video
-vf “rotate=90”:旋转视频90度(支持0,90,180,270度)。水平翻转
-vf “hflip”:水平翻转视频。垂直翻转
-vf “vflip”:垂直翻转视频。
-
过滤器
ffmpeg 支持复杂的过滤器链,例如:添加水印
-i watermark.png -filter_complex “overlay=W-w:0” output.mp4:在视频右下角添加水印。画中画
-i small.mp4 -filter_complex “overlay=main_w/2:main_h/2” output.mp4:在视频中插入另外一个小视频。
-
编码器
指定视频编码器
-c:v h264:使用H.264编码器。指定音频编码器
-c:a aac:使用AAC音频编码器。
-
时间控制
播放速度
-vf “setpts=2*PTS”:将视频速度加快2倍。剪辑视频
-ss 00:01:00 -t 00:01:00 -c copy output.mp4:从第1分钟开始剪辑1分钟的视频。提取音频
-vn -ar 44100 -ac 2 -ab 128k output.mp3:提取视频中的音频并保存为MP3。生成静音
-f lavfi -i anullsrc -c:a aac output.mka:生成一个没有视频的静音文件。
-
压缩和质量
CRF(质量控制)
-crf 18:设置视频质量(18-28,数值越小质量越高)。预设
-preset ultrafast:设置编码速度(如:ultrafast, superfast, veryfast, faster, fast, medium)。
示例
将 MP4 转换为 H.264 编码的 MKV:
ffmpeg -i input.mp4 -c:v h264 output.mkv
将视频压缩到1Mbps:
ffmpeg -i input.mp4 -c:v h264 -b:v 1000k output.mp4
提取视频的音频:
ffmpeg -i input.mp4 -vn -ar 44100 -ac 2 -ab 128k output.mp3
将视频旋转90度:
ffmpeg -i input.mp4 -vf “rotate=90” output.mp4
实战举栗子
获取视频时长
// Duration: 00:00:30.03, start: 0.000000, bitrate: 1191 kb/s
public String getVideoDuration(String inputFilePath) {
Process process = null;
try {
// 定义远程视频的URL
// 构建FFmpeg命令
ProcessBuilder processBuilder = new ProcessBuilder(ffmpegPath, "-i",inputFilePath);
// 读取FFmpeg的输出信息
// 创建ProcessBuilder并执行命令
processBuilder.redirectErrorStream(true);
process = processBuilder.start();
// 读取FFmpeg命令输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("Duration:")) {
// 获取包含视频时长信息的行
String durationLine = line.split("Duration:")[1].split(",")[0].split("\\.")[0].trim();// 00:00:30
// String durationLine = line.split("Duration:")[1].split(",")[0].trim();// 00:00:30.03
// String[] durationParts = durationLine.split(":");
// int hours = Integer.parseInt(durationParts[0].trim());
// int minutes = Integer.parseInt(durationParts[1].trim());
// double seconds = Double.parseDouble(durationParts[2].trim());
// // 计算总秒数
// double totalSeconds = hours * 3600 + minutes * 60 + seconds;
System.out.println("视频时长:" + durationLine);
return durationLine;
}
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
} finally {
if (process != null) {
process.destroyForcibly(); // 强制终止进程
}
}
System.out.println("无法获取视频时长。");
return null;
}
public Integer getVideoDurationSecond(String inputFilePath) {
String videoDuration = getVideoDuration(inputFilePath);
if (videoDuration == null) {
return 0;
}
String[] durationParts = videoDuration.split(":");
int hours = Integer.parseInt(durationParts[0].trim());
int minutes = Integer.parseInt(durationParts[1].trim());
int seconds = Integer.parseInt(durationParts[2].trim());
// 计算总秒数
return hours * 3600 + minutes * 60 + seconds;
}
视频转码
public void transcodeVideo(String inputFilePath, String outputFilePath) {
ProcessBuilder processBuilder = new ProcessBuilder(ffmpegPath, "-i",inputFilePath, "-c:v", "libx264", "-c:a", "aac", outputFilePath);
try {
processBuilder.inheritIO(); // 将FFmpeg的输出信息打印到控制台
// processBuilder.redirectErrorStream(true); // 合并错误输出流
Process process = processBuilder.start();
int exitCode = process.waitFor();
if (exitCode == 0) {
log.info("视频转码成功!");
} else {
log.info("视频转码失败!");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
mp4文件转为hls m3u8 ts等文件
public void convertMp4ToM3u8(String inputFilePath, String outputDirectory, String defineOutputFileName) {
File inputFile = new File(inputFilePath);
if (!inputFile.exists()) {
throw new IllegalArgumentException("Input file not found: " + inputFilePath);
}
File outputDir = new File(outputDirectory);
if (!outputDir.exists()) {
outputDir.mkdirs();
}
// Output filename without extension
String outputFileName = inputFile.getName().replaceFirst("[.][^.]+$", "");
if (StringUtils.isNotBlank(defineOutputFileName)) {// 自定义名称
outputFileName = defineOutputFileName;
}
Process process = null;
try {
// Command to convert MP4 to M3U8 using FFmpeg
List<String> command = new ArrayList<>();
command.add(ffmpegPath);
command.add("-i");
command.add(inputFilePath);
command.add("-c:v");
command.add("libx264");
command.add("-hls_time");
command.add("10"); // 设置每个分片的时长,单位为秒
command.add("-hls_list_size");
command.add("0");
command.add("-hls_segment_filename");
command.add(outputDirectory + "/" + outputFileName + "_%03d.ts");
command.add(outputDirectory + "/" + outputFileName + ".m3u8");
ProcessBuilder pb = new ProcessBuilder(command);
pb.inheritIO(); // 将FFmpeg的输出信息打印到控制台
process = pb.start();
int exitCode = process.waitFor();
if (exitCode == 0) {
log.info("视频转换成功!");
} else {
log.info("视频转换失败!");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
} finally {
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
}
// Check if the conversion was successful
File m3u8File = new File(outputDirectory + "/" + outputFileName + ".m3u8");
if (!m3u8File.exists()) {
throw new RuntimeException("M3U8 file was not generated");
}
}
图片转视频
/**
* 图片转为视频
* E://yla-tool//ffmpeg//ffmpeg-7.0.1-full_build//bin//ffmpeg.exe -framerate 0.2 -f image2 -i 素材%d.png -vf scale=1920:1080 -c:v libx264 -profile:v high -crf 20 -pix_fmt yuv420p test.mp4
* E://yla-tool//ffmpeg//ffmpeg-7.0.1-full_build//bin//ffmpeg.exe -r 15 -loop 1 -i 01.jpg -vf scale=1920:1080 -c:v libx264 -profile:v high -crf 20 -pix_fmt yuv420p -t 10 -r 15 111.mp4
* 暂不支持多张图片
* @param imagePaths
* @param outputVideoPath
* @param r 帧率
* @param t 时长
*/
public Integer generateVideo (List<String> imagePaths, String outputVideoPath, int r, int t) {
// StringBuilder ffmpegCommand = new StringBuilder(ffmpegPath + " -framerate ");
// ffmpegCommand.append(fps).append(" -i ");// 设置帧率和输入格式
StringBuilder ffmpegCommand = new StringBuilder(ffmpegPath);
ffmpegCommand.append(" -r ");
ffmpegCommand.append(r);
ffmpegCommand.append(" -loop 1 ");
ffmpegCommand.append(" -i ");// 设置帧率和输入格式
for (String imagePath : imagePaths) {
ffmpegCommand.append(imagePath).append(" ");// 添加每个图片的路径
}
ffmpegCommand.append("-vf scale=1920:1080 -c:v libx264 -profile:v high -crf 20 -pix_fmt yuv420p ")// 设置视频编码和质量
.append(" -t ")
.append(t)
.append(" -r ")
.append(r)
.append(" ")
.append(outputVideoPath);// 设置视频输出路径
Process process = null;
try {
process = Runtime.getRuntime().exec(ffmpegCommand.toString());
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
int exitCode = process.waitFor();
if (exitCode == 0) {
log.info("视频生成成功,路径:" + outputVideoPath);
} else {
log.info("视频生成失败!");
}
return exitCode;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
} finally {
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
}
return null;
}
抽取视频第一帧
public void previewVideo (HttpServletResponse response, String videoPath) {
// String videoPath = "path/to/your/video/sample.mp4"; // 替换为你的视频文件路径
// int startTimeSeconds = 0; // 开始时间,单位为秒
// int durationSeconds = 5; // 需要提取的视频时长,单位为秒
int frameTime = 0; // 提取第一帧图像的时间,单位为秒 (原取1 但是1秒钟的视频 抽帧图片缺失故改为0)
//
// try {
// // 构建 FFmpeg 命令
// String ffmpegCmd = String.format(ffmpegPath + " -ss %d -i %s -t %d -f image2pipe -vcodec mjpeg -", startTimeSeconds, videoPath, durationSeconds);
Process process = null;
try {
// 构建 FFmpeg 命令
// String ffmpegCmd = String.format(ffmpegPath + " -ss %d -i %s -frames:v 1 -f image2pipe -vcodec mjpeg -", frameTime, videoPath);
String imagePath = fileDir + "temp_image_" + UUID.randomUUID() + ".jpg";
System.out.println(imagePath);
// -ss 0 -i input.mp4 -frames:v 1 -f image2 output.jpg
// String ffmpegCmd = String.format(" -ss %d -i %s -frames:v 1 -f image2 %s", frameTime, videoPath, imagePath);
// process = Runtime.getRuntime().exec(ffmpegCmd);
ProcessBuilder processBuilder = new ProcessBuilder(ffmpegPath,
"-ss", frameTime+"",
"-i", videoPath,
"-frames:v", "1",
"-q:v", "30",
imagePath
);
processBuilder.inheritIO(); // 将FFmpeg的输出信息打印到控制台
process = processBuilder.start();
int exitCode = process.waitFor();
if (exitCode == 0) {
log.info("抽取第一帧成功!");
} else {
log.info("抽取第一帧失败!");
}
// 读取生成的图片
InputStream inputStream = new FileInputStream(imagePath);
// 设置响应头
response.setContentType("image/jpeg");
OutputStream outputStream = response.getOutputStream();
// 从 FFmpeg 输出流读取数据并写入到 Servlet 输出流
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
outputStream.close();
inputStream.close();
// 删除临时图片文件
Files.delete(Paths.get(imagePath));
} catch (IOException | InterruptedException e) {
e.printStackTrace();
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
if (process != null) {
process.destroyForcibly(); // 如果发生异常,强制终止进程
}
}
}
获取基本信息
package net.yla.board.core.utils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class VideoConverter {
public static void main(String[] args) {
// "-c:v", "libx264", "-b:v", "4027k", "-preset", "ultrafast", "-threads", "4", "-c:a", "aac",
// String inputVideo = "E:\\testm3u8\\西藏2.mp4";
String inputVideo = "E:\\图片夹\\视频雪景.mp4";
String outputPlaylist = "E:\\testm3u8\\output.m3u8";
long l1 = System.currentTimeMillis();
// ProcessBuilder processBuilder = new ProcessBuilder("E:\\yla-tool\\ffmpeg\\ffmpeg-7.0.1-full_build\\bin\\ffmpeg.exe", "-i",inputVideo);
// E:\\yla-tool\\ffmpeg\\ffmpeg-7.0.1-full_build\\bin\\ffmpeg.exe -i E:\图片夹\公司宣传.mp4 -c:v libx264 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename E:\\图片夹\\output%03d.ts E:\图片夹\output.m3u8
// ProcessBuilder processBuilder = new ProcessBuilder("E:\\yla-tool\\ffmpeg\\ffmpeg-7.0.1-full_build\\bin\\ffmpeg.exe", "-i", inputVideo, "-c:v", "libx264", "-hls_time", "10", "-hls_list_size", "0", "-f", "hls", "-hls_segment_filename", "E:\\testm3u8\\" + "output%03d.ts", outputPlaylist);
ProcessBuilder processBuilder = new ProcessBuilder("E:\\yla-tool\\ffmpeg\\ffmpeg-7.0.1-full_build\\bin\\ffmpeg.exe", "-i",inputVideo);
// ProcessBuilder processBuilder = new ProcessBuilder("E:\\yla-tool\\ffmpeg\\ffmpeg-7.0.1-full_build\\bin\\ffmpeg.exe", "-i",inputVideo, "-c:v", "libx264", "-b:v", "4000k", "-preset", "ultrafast", "-c:a", "aac", System.currentTimeMillis() + ".mp4");
try {
processBuilder.inheritIO(); // 将FFmpeg的输出信息打印到控制台
// processBuilder.redirectErrorStream(true); // 合并错误输出流
Process process = processBuilder.start();
// BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
// String line;
//
// while ((line = reader.readLine()) != null) {
// System.out.println(line); // 打印FFmpeg输出的每一行
// // 解析进度信息
// if (line.contains("frame=")) {
// String[] parts = line.split(" ");
// for (String part : parts) {
// if (part.startsWith("time=")) {
// String time = part.split("=")[1];
// System.out.println("Current Time: " + time);
// }
// }
// }
// }
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("视频转换成功!");
System.out.println("转换耗时:" + (System.currentTimeMillis() - l1) / 1000 + "秒");
} else {
System.out.println("视频转换失败!");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
基本信息打印结果如下:
ffmpeg version 7.0.1-full_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libaribcaption --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libxevd --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxeve --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libcodec2 --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'E:\图片夹\视频雪景.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
creation_time : 2023-11-24T11:51:45.000000Z
Duration: 00:00:07.64, start: 0.000000, bitrate: 26320 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160, 26340 kb/s, 59.94 fps, 59.94 tbr, 60k tbn (default)
Metadata:
creation_time : 2023-11-24T11:51:45.000000Z
handler_name : Vimeo Artax Video Handler
vendor_id : [0][0][0][0]
encoder : AVC Coding
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
Metadata:
creation_time : 2023-11-24T11:51:45.000000Z
handler_name : Vimeo Artax Audio Handler
vendor_id : [0][0][0][0]
At least one output file must be specified
转码日志输出详解
输出内容如下:
视频码率:23604
ffmpeg version 7.0.1-full_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libaribb24 --enable-libaribcaption --enable-libdav1d --enable-libdavs2 --enable-libuavs3d --enable-libxevd --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxeve --enable-libxvid --enable-libaom --enable-libjxl --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-liblensfun --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libshaderc --enable-vulkan --enable-libplacebo --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libcodec2 --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'E:\图片夹\视频-GreatWall.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
creation_time : 2024-02-04T21:36:53.000000Z
Duration: 00:00:48.73, start: 0.000000, bitrate: 23604 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160, 23601 kb/s, 30 fps, 30 tbr, 30 tbn (default)
Metadata:
creation_time : 2024-02-04T21:36:53.000000Z
handler_name : Vimeo Artax Video Handler
vendor_id : [0][0][0][0]
encoder : AVC Coding
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[libx264 @ 000001e505081300] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 000001e505081300] profile Constrained Baseline, level 5.1, 4:2:0, 8-bit
[libx264 @ 000001e505081300] 264 - core 164 r3191 4613ac3 - H.264/MPEG-4 AVC codec - Copyleft 2003-2024 - http://www.videolan.org/x264.html - options: cabac=0 ref=1 deblock=0:0:0 analyse=0:0 me=dia subme=0 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=9 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=0 keyint=250 keyint_min=25 scenecut=0 intra_refresh=0 rc=abr mbtree=0 bitrate=23604 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=0
Output #0, mp4, to '1744097594286.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
encoder : Lavf61.1.100
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160, q=2-31, 23604 kb/s, 30 fps, 15360 tbn (default)
Metadata:
creation_time : 2024-02-04T21:36:53.000000Z
handler_name : Vimeo Artax Video Handler
vendor_id : [0][0][0][0]
encoder : Lavc61.3.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/23604000 buffer size: 0 vbv_delay: N/A
[out#0/mp4 @ 000001e5043e8100] video:140862KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.005820%
frame= 1462 fps= 80 q=-1.0 Lsize= 140870KiB time=00:00:48.73 bitrate=23680.1kbits/s speed=2.68x
[libx264 @ 000001e505081300] frame I:6 Avg QP:29.67 size:814006
[libx264 @ 000001e505081300] frame P:1456 Avg QP:32.41 size: 95713
[libx264 @ 000001e505081300] mb I I16..4: 100.0% 0.0% 0.0%
[libx264 @ 000001e505081300] mb P I16..4: 1.3% 0.0% 0.0% P16..4: 51.9% 0.0% 0.0% 0.0% 0.0% skip:46.8%
[libx264 @ 000001e505081300] final ratefactor: 29.74
[libx264 @ 000001e505081300] coded y,uvDC,uvAC intra: 41.9% 22.8% 1.1% inter: 19.3% 5.8% 0.0%
[libx264 @ 000001e505081300] i16 v,h,dc,p: 23% 26% 35% 16%
[libx264 @ 000001e505081300] i8c dc,h,v,p: 53% 24% 14% 8%
[libx264 @ 000001e505081300] kb/s:23678.63
视频转换成功!
转换耗时:19秒
以下是对这段FFmpeg日志的逐行解释:
- FFmpeg版本信息
ffmpeg version 7.0.1-full_build-www.gyan.dev Copyright © 2000-2024 the FFmpeg developers
built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
这是FFmpeg的版本信息,显示当前使用的是 FFmpeg 7.0.1。 -©©opyright信息表明FFmpeg是一个开源软件,由全球开发者社区维护。
编译信息:使用了 gcc 13.2.0 编译,通过MSYS2项目构建。
- 配置信息
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads […] --enable-libx264 --enable-libx265 […]
这是FFmpeg的配置选项,表示在编译时启用了某些功能:
–enable-gpl:启用GPL(GNU通用公共许可证)许可协议。
–enable-version3:启用GPL第三版协议。
–enable-static:编译为静态库,而不是动态库。
–enable-libx264 和 --enable-libx265:启用H.264(x264)和H.265(x265)编码支持。
[…] 表示省略了其他配置选项。
- FFmpeg核心库版本
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
这些是FFmpeg的核心库版本信息,分别对应:
libavutil:实用函数库。
libavcodec:音视频编解码器库。
libavformat:音视频格式处理库。
libavdevice:输入/输出设备处理库。
libavfilter:音视频滤镜库。
libswscale:视频缩放和格式转换库。
libswresample:音频重采样库。
libpostproc:视频后处理库。
- 输入文件信息
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from ‘E:\图片夹\视频-GreatWall.mp4’:
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
creation_time : 2024-02-04T21:36:53.000000Z
Duration: 00:00:48.73, start: 0.000000, bitrate: 23604 kb/s
Stream #0:00x1: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160, 23601 kb/s, 30 fps, 30 tbr, 30 tbn (default)
Metadata:
creation_time : 2024-02-04T21:36:53.000000Z
handler_name : Vimeo Artax Video Handler
vendor_id : [0][0][0][0]
encoder : AVC Coding
输入文件路径:E:\图片夹\视频-GreatWall.mp4。
文件Metadata:
major_brand:主要品牌标识为 mp42。
minor_version:次要版本号为 0。
compatible_brands:兼容的品牌标识,包括 mp42 和 isom。
creation_time:文件创建时间为 2024-02-04T21:36:53Z。
流媒体信息:
Stream #0:0 是输入文件的视频流。
编码格式:H.264 (High)。
分辨率:3840x2160(4K)。
比特率:23601 kb/s。
帧率:30 fps。
色彩空间:yuv420p,适用于电视(tv),颜色空间为 bt709。
Metadata:
handler_name:处理器名称为 Vimeo Artax Video Handler。
vendor_id:供应商ID为空。
encoder:编码器为 AVC Coding。
- 流映射
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
流映射:指明输入的流如何映射到输出。
Stream #0:0:输入的视频流(H.264)。
输出的流:h264 (libx264),即使用 libx264 编码器重新编码。
- 按键提示
Press [q] to stop, [?] for help
提示用户可以按 q 停止转码过程,或按 ? 查看帮助信息。
- 视频编码器信息
[libx264 @ 000001e505081300] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 000001e505081300] profile Constrained Baseline, level 5.1, 4:2:0, 8-bit
[libx264 @ 000001e505081300] 264 - core 164 r3191 4613ac3 - H.264/MPEG-4 AVC codec - Copyleft 2003-2024 - http://www.videolan.org/x264.html - options: cabac=0 ref=1 deblock=0:0:0 analyse=0:0 me=dia subme=0 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=9 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=0 keyint=250 keyint_min=25 scenecut=0 intra_refresh=0 rc=abr mbtree=0 bitrate=23604 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=0
libx264:H.264编码器的详细信息。
CPU支持:列出了CPU支持的指令集(如AVX、AVX2等)。
Profile:使用的 profiles 是 Constrained Baseline,适用于移动设备和网页播放。
Level:视频编码级别为 5.1,适用于分辨率高达 4K 的视频。
编码选项:详细列出了编码器的参数设置,包括:
cabac=0:不使用 CABAC 熵编码。
ref=1:参考帧数量。
deblock=0:0:0:去块过滤器的强度为0。
psy=1:启用心理学优化。
bitrate=23604:目标比特率为23604 kbps,与输入文件一致。
qcomp=0.60:量化压缩系数。
- 输出文件信息
Output #0, mp4, to ‘1744097594286.mp4’:
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
encoder : Lavf61.1.100
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160, q=2-31, 23604 kb/s, 30 fps, 15360 tbn (default)
Metadata:
creation_time : 2024-02-04T21:36:53.000000Z
handler_name : Vimeo Artax Video Handler
vendor_id : [0][0][0][0]
encoder : Lavc61.3.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/23604000 buffer size: 0 vbv_delay: N/A
输出文件路径:1744097594286.mp4。
输出Metadata:
major_brand 和 compatible_brands 与输入文件一致。
encoder:使用的 muxer( multiplexor,复用器)版本号为 Lavf61.1.100。
流媒体信息:
视频流的编码格式为 H.264,分辨率为 3840x2160,比特率为 23604 kb/s。
q=2-31:量化参数范围。
tbn=15360:时间基数(timebase numerator)。
Side data:关于igrams buffer的信息。
- 转码进度
frame= 1462 fps= 80 q=-1.0 Lsize= 140870KiB time=00:00:48.73 bitrate=23680.1kbits/s speed=2.68x
frame=1462:总共处理了1462帧。
fps=80:实际转码速度为80帧每秒。
q=-1.0:量化参数 (-1 表示自动调整)。
Lsize=140870KiB:输出文件大小约为 140.87 MB。
time=00:00:48.73:转码完成时长为 48.73 秒。
bitrate=23680.1kbits/s:实际比特率为23680.1 kbps。
speed=2.68x:转码速度是实时速度的2.68倍。
- 编码统计
[libx264 @ 000001e505081300] frame I:6 Avg QP:29.67 size:814006
[libx264 @ 000001e505081300] frame P:1456 Avg QP:32.41 size: 95713
[libx264 @ 000001e505081300] mb I I16…4: 100.0% 0.0% 0.0%
[libx264 @ 000001e505081300] mb P I16…4: 1.3% 0.0% 0.0% P16…4: 51.9% 0.0% 0.0% 0.0% 0.0% skip:46.8%
[libx264 @ 000001e505081300] final ratefactor: 29.74
[libx264 @ 000001e505081300] coded y,uvDC,uvAC intra: 41.9% 22.8% 1.1% inter: 19.3% 5.8% 0.0%
帧类型统计:
I帧:6个,平均QP(量化参数)为29.67,大小为814006 bytes。
P帧:1456个,平均QP为32.41,大小为95713 bytes。
宏块(mb)统计:
I帧宏块:100% 使用 I16…4 模式。
P帧宏块:
I16…4 模式占1.3%。
P16…4 模式占51.9%。
skip(跳过运动补偿)占46.8%。
final ratefactor:最终的速率因子为29.74。
编码效率统计:
chtěIntra(内存预测):41.9% 的Y分量、22.8% 的UV分量DC、1.1% 的UV分量AC。 -_RETRY(运动预测):19.3% 的Y分量、5.8% 的UV分量。
总结:
这是一个H.264视频的转码过程,输入和输出格式均为MP4,分辨率为4K(3840x2160),比特率保持不变,使用了x264编码器进行重新编码。转码速度较快(2.68x),最终输出文件大小为约140.87 MB。
转码耗时测试
ffmpeg安装位置:E:\yla-tool\ffmpeg\ffmpeg-7.0.1-full_build\bin\ffmpeg.exe
// 获取源文件码率
String videoBitrate = getVideoBitrate(inputVideo);
简单基本命令和加了参数preset 和 b:v码率设置
文件和命令 | “E:\yla-tool\ffmpeg\ffmpeg-7.0.1-full_build\bin\ffmpeg.exe”, “-i”,inputVideo, “-c:v”, “libx264”, “-c:a”, “aac”, System.currentTimeMillis() + “.mp4” | “E:\yla-tool\ffmpeg\ffmpeg-7.0.1-full_build\bin\ffmpeg.exe”, “-i”,inputVideo, “-c:v”, “libx264”, “-b:v”, videoBitrate+“k”, “-preset”, “ultrafast”, “-c:a”, “aac”, System.currentTimeMillis() + “.mp4” |
---|---|---|
视频雪景.mp4( 7s 23M 总比特率25116kbps 帧速率59.94帧/秒) | 40s(44M 码率45243kbps) | 8s(19M 码率20346kbps) |
视频-GreatWall.mp4( 48s 137M 总比特率23472kbps 帧速率30帧/秒) | 121s(140M 码率相似) | 19s(140M 码率相似) |
参数后续……