package com.lmk.springboot_ffmpeg.utils;
import com.google.gson.Gson;
import com.lmk.springboot_ffmpeg.bean.MediaInfo;
import com.lmk.springboot_ffmpeg.bean.TranscodeInfo;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import javax.crypto.KeyGenerator;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
public class FFmpegUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(FFmpegUtils.class);
// 跨平台换行符
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String TS = "ts";
/**
* 生成随机16个字节的AESKEY
*
* @return
*/
private static byte[] genAesKey() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
return keyGenerator.generateKey().getEncoded();
} catch (NoSuchAlgorithmException e) {
return null;
}
}
/**
* 在指定的目录下生成key_info, key文件,返回key_info文件
*
* @param folder
* @throws IOException
*/
private static Path genKeyInfo(String folder) throws IOException {
// AES 密钥
byte[] aesKey = genAesKey();
// AES 向量
String iv = Hex.encodeHexString(genAesKey());
// key 文件写入
Path keyFile = Paths.get(folder, "key");
Files.write(keyFile, aesKey, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
// key_info 文件写入
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("key").append(LINE_SEPARATOR); // m3u8加载key文件网络路径
stringBuilder.append(keyFile.toString()).append(LINE_SEPARATOR); // FFmeg加载key_info文件路径
stringBuilder.append(iv); // ASE 向量
Path keyInfo = Paths.get(folder, "key_info");
Files.write(keyInfo, stringBuilder.toString().getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
return keyInfo;
}
/**
* 指定的目录下生成 master index.m3u8 文件
*
* @param file master m3u8文件地址
* @param indexPath 访问子index.m3u8的路径
* @param bandWidth 流码率
* @throws IOException
*/
private static void genIndex(String file, String indexPath, String bandWidth) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("#EXTM3U").append(LINE_SEPARATOR);
stringBuilder.append("#EXT-X-STREAM-INF:BANDWIDTH=" + bandWidth).append(LINE_SEPARATOR); // 码率
stringBuilder.append(indexPath);
Files.write(Paths.get(file), stringBuilder.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
/**
* 转码视频为m3u8
*
* @param source 源视频
* @param destFolder 目标文件夹
* @param config 配置信息
* @throws IOException
* @throws InterruptedException
*/
public static void transcodeToM3u8(String source, String destFolder, TranscodeInfo config) throws IOException, InterruptedException {
// 判断源视频是否存在
if (!Files.exists(Paths.get(source))) {
throw new IllegalArgumentException("文件不存在:" + source);
}
// 创建工作目录
Path workDir = Paths.get(destFolder, TS);
Files.createDirectories(workDir);
// 在工作目录生成KeyInfo文件
Path keyInfo = genKeyInfo(workDir.toString());
// 构建命令
List<String> commands = new ArrayList<>();
commands.add("ffmpeg");
commands.add("-i");
commands.add(source); // 源文件
commands.add("-force_key_frames"); // 强制每1秒一个关键帧
commands.add("expr:gte(t,n_forced*1)"); // 强制每1秒一个关键帧
commands.add("-c:v");
commands.add("libx264"); // 视频编码为H264
commands.add("-c:a");
commands.add("copy"); // 音频直接copy
commands.add("-hls_key_info_file");
commands.add(keyInfo.toString()); // 指定密钥文件路径
commands.add("-hls_time");
commands.add(config.getTsSeconds()); // ts切片大小
commands.add("-hls_playlist_type");
commands.add("vod"); // 点播模式
commands.add("-hls_segment_filename");
commands.add("%06d.ts"); // ts切片文件名称
if (StringUtils.hasText(config.getCutStart())) {
commands.add("-ss");
commands.add(config.getCutStart()); // 开始时间
}
if (StringUtils.hasText(config.getCutEnd())) {
commands.add("-to");
commands.add(config.getCutEnd()); // 结束时间
}
commands.add("index.m3u8"); // 生成m3u8文件
// 构建进程
Process process = new ProcessBuilder()
.command(commands)
.directory(workDir.toFile())
.start();
// 读取进程标准输出
new Thread(() -> {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line = null;
while ((line = bufferedReader.readLine()) != null) {
LOGGER.info(line);
}
} catch (IOException e) {
}
}).start();
// 读取进程异常输出
new Thread(() -> {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
String line = null;
while ((line = bufferedReader.readLine()) != null) {
LOGGER.info(line);
}
} catch (IOException e) {
}
}).start();
// 阻塞直到任务结束
if (process.waitFor() != 0) {
throw new RuntimeException("视频切片异常");
}
// 切出封面
if (!screenShots(source, String.join(File.separator, destFolder, TS+"/poster.jpg"), config.getPoster())) {
throw new RuntimeException("封面截取异常");
}
// 获取视频信息
final MediaInfo[] mediaInfo = {getMediaInfo(source)};
if (mediaInfo[0] == null) {
throw new RuntimeException("获取媒体信息异常");
}
// 生成index.m3u8文件
genIndex(String.join(File.separator, destFolder, TS+"index.m3u8"), TS+"/index.m3u8", mediaInfo[0].getFormat().getBitRate());
// 删除keyInfo文件
Files.delete(keyInfo);
}
/**
* 获取视频文件的媒体信息
*
* @param source
* @return
* @throws IOException
* @throws InterruptedException
*/
public static MediaInfo getMediaInfo(String source) throws IOException, InterruptedException {
List<String> commands = new ArrayList<>();
commands.add("ffprobe");
commands.add("-i");
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
springboot + FFmpeg 实战视频切片,主要用于大视频切片上传处理。客户端上传视频到服务器,服务器对视频进行切片后,返回m3u8,封面等访问路径。可以在线的播放。 服务器可以对视频做一些简单的处理,例如裁剪,封面的截取时间。
资源推荐
资源详情
资源评论
收起资源包目录
springboot + FFmpeg 实战视频切片 (128个子文件)
.gitignore 395B
index.html 2KB
springboot_ffmpeg.iml 13KB
FFmpegUtils.java 10KB
FileTestController.java 4KB
UrlToMultipartFile.java 3KB
TranscodeInfo.java 527B
MediaStream.java 394B
MediaInfo.java 369B
SpringbootFfmpegApplication.java 350B
MediaFormat.java 299B
SpringbootFfmpegApplicationTests.java 236B
hls.min.js 435KB
HELP.md 1005B
workspace.xml 26KB
uiDesigner.xml 9KB
pom.xml 4KB
compiler.xml 885B
Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_13_2.xml 736B
Maven__org_thymeleaf_extras_thymeleaf_extras_java8time_3_0_4_RELEASE.xml 725B
Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_6_6.xml 713B
Maven__org_springframework_boot_spring_boot_starter_thymeleaf_2_6_6.xml 706B
Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml 700B
Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_13_2.xml 695B
Maven__org_springframework_boot_spring_boot_starter_logging_2_6_6.xml 692B
Maven__org_springframework_boot_spring_boot_starter_tomcat_2_6_6.xml 685B
Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_13_2.xml 681B
Maven__org_springframework_boot_spring_boot_autoconfigure_2_6_6.xml 678B
Maven__org_springframework_boot_spring_boot_starter_json_2_6_6.xml 671B
Maven__org_springframework_boot_spring_boot_starter_test_2_6_6.xml 671B
Maven__org_springframework_boot_spring_boot_starter_web_2_6_6.xml 664B
Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_60.xml 660B
Maven__com_fasterxml_jackson_core_jackson_annotations_2_13_2.xml 651B
Maven__com_fasterxml_jackson_core_jackson_databind_2_13_2_2.xml 644B
Maven__org_springframework_boot_spring_boot_devtools_2_6_6.xml 643B
Maven__org_thymeleaf_thymeleaf_spring5_3_0_15_RELEASE.xml 641B
Maven__org_springframework_boot_spring_boot_starter_2_6_6.xml 636B
Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml 633B
Maven__org_junit_platform_junit_platform_commons_1_8_2.xml 633B
Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml 633B
Maven__org_junit_platform_junit_platform_engine_1_8_2.xml 626B
Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_60.xml 625B
Maven__org_junit_jupiter_junit_jupiter_params_5_8_2.xml 615B
Maven__org_springframework_boot_spring_boot_test_2_6_6.xml 615B
Maven__org_junit_jupiter_junit_jupiter_engine_5_8_2.xml 615B
Maven__org_apache_tomcat_embed_tomcat_embed_el_9_0_60.xml 611B
Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml 611B
Maven__org_springframework_spring_expression_5_3_18.xml 609B
Maven__org_apache_logging_log4j_log4j_to_slf4j_2_17_2.xml 608B
Maven__commons_fileupload_commons_fileupload_1_2_2.xml 605B
Maven__org_bytedeco_ffmpeg_platform_4_3_1_1_5_4.xml 602B
Maven__com_fasterxml_jackson_core_jackson_core_2_13_2.xml 602B
Maven__org_mockito_mockito_junit_jupiter_4_0_0.xml 598B
Maven__org_junit_jupiter_junit_jupiter_api_5_8_2.xml 594B
Maven__org_attoparser_attoparser_2_0_5_RELEASE.xml 589B
Maven__org_springframework_spring_context_5_3_18.xml 588B
Maven__org_thymeleaf_thymeleaf_3_0_15_RELEASE.xml 585B
Maven__net_bytebuddy_byte_buddy_agent_1_11_22.xml 585B
Maven__org_springframework_spring_webmvc_5_3_18.xml 581B
Maven__org_springframework_boot_spring_boot_2_6_6.xml 580B
Maven__org_unbescape_unbescape_1_1_6_RELEASE.xml 578B
Maven__ch_qos_logback_logback_classic_1_2_11.xml 575B
Maven__org_springframework_spring_beans_5_3_18.xml 574B
Maven__org_apache_logging_log4j_log4j_api_2_17_2.xml 573B
Maven__org_apiguardian_apiguardian_api_1_1_2.xml 572B
Maven__org_bytedeco_ffmpeg_android_x86_64_4_3_1_1_5_4.xml 569B
Maven__org_bytedeco_ffmpeg_windows_x86_64_4_3_1_1_5_4.xml 569B
Maven__org_bytedeco_ffmpeg_android_arm64_4_3_1_1_5_4.xml 567B
Maven__org_springframework_spring_test_5_3_18.xml 567B
Maven__org_bytedeco_ffmpeg_macosx_x86_64_4_3_1_1_5_4.xml 567B
Maven__org_bytedeco_javacpp_platform_1_5_4.xml 567B
Maven__org_bytedeco_ffmpeg_linux_ppc64le_4_3_1_1_5_4.xml 567B
Maven__org_springframework_spring_core_5_3_18.xml 567B
Maven__org_junit_jupiter_junit_jupiter_5_8_2.xml 566B
Maven__org_bytedeco_ffmpeg_linux_x86_64_4_3_1_1_5_4.xml 565B
Maven__org_bytedeco_ffmpeg_linux_arm64_4_3_1_1_5_4.xml 563B
Maven__org_bytedeco_ffmpeg_android_x86_4_3_1_1_5_4.xml 563B
Maven__org_bytedeco_ffmpeg_linux_armhf_4_3_1_1_5_4.xml 563B
Maven__org_bytedeco_ffmpeg_android_arm_4_3_1_1_5_4.xml 563B
Maven__org_bytedeco_ffmpeg_windows_x86_4_3_1_1_5_4.xml 563B
Maven__org_springframework_spring_web_5_3_18.xml 560B
Maven__org_springframework_spring_aop_5_3_18.xml 560B
Maven__org_springframework_spring_jcl_5_3_18.xml 560B
Maven__org_bytedeco_ffmpeg_linux_x86_4_3_1_1_5_4.xml 559B
Maven__net_minidev_accessors_smart_2_4_8.xml 556B
Maven__ch_qos_logback_logback_core_1_2_11.xml 554B
Maven__com_jayway_jsonpath_json_path_2_6_0.xml 546B
Maven__commons_codec_commons_codec_1_15.xml 543B
Maven__net_bytebuddy_byte_buddy_1_11_22.xml 543B
Maven__org_assertj_assertj_core_3_21_0.xml 542B
Maven__org_bytedeco_ffmpeg_4_3_1_1_5_4.xml 539B
Maven__org_skyscreamer_jsonassert_1_5_0.xml 537B
Maven__org_mockito_mockito_core_4_0_0.xml 535B
Maven__org_xmlunit_xmlunit_core_2_8_4.xml 535B
Maven__org_bytedeco_javacpp_windows_x86_64_1_5_4.xml 534B
Maven__org_slf4j_jul_to_slf4j_1_7_36.xml 534B
Maven__org_bytedeco_javacpp_android_x86_64_1_5_4.xml 534B
Maven__org_opentest4j_opentest4j_1_2_0.xml 533B
Maven__org_bytedeco_javacpp_linux_ppc64le_1_5_4.xml 532B
Maven__org_bytedeco_javacpp_macosx_x86_64_1_5_4.xml 532B
共 128 条
- 1
- 2
迟到的微笑
- 粉丝: 432
- 资源: 52
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
- 3
前往页