官网:FFmpeg
文章目录
一、下载ffmpeg安装包
到ffmpeg官网下载安装包Download FFmpeg,这里以windows为例
2、解压文件
进入bin目录,可以看到这三个文件
3、设置环境变量
点击“系统属性->高级系统设置->环境变量->系统变量”,选择“Path”条目,点击“编辑->新建”,把第一步的bin文件夹路径复制粘贴进去,然后点击确定即可。
4、测试是否安装成功
按win + R打开运行,输入cmd打开命令运行窗口
输入命令“ffmpeg –version”,输出一下信息即安装成功。
接下来就可以直接使用命令行执行ffmpeg命令进行各种媒体格式的转换了。
二、mp4转m3u8
2.1windows版命令
ffmpeg -i D:/m3u8/demo.mp4 -c:v copy -c:a copy -f ssegment -segment_format mpegts -segment_list D:/m3u8/hls/test.m3u8 -segment_time 10 D:/m3u8/hls/test%05d.ts
D:/m3u8/demo.mp4输入的mp4文件
D:/m3u8/hls/test.m3u8输出的m3u8文件
-segment_time设置每片的长度,单位为秒
-segment_list :段文件的名称,%05d表示5位数字生成的效果是:将demo.mp4视频文件每10秒生成一个ts文件,最后生成一个m3u8文件,m3u8文件是ts的索引文件。
2.2Linux命令
ffmpeg -i 1661672379638590.mp4 -codec copy -hls_list_size 0 -hls_wrap 0 -strict -2 -vbsf h264_mp4toannexb -absf aac_adtstoasc -f hls test4.m3u8
三、java实现
3.1切片工具类
在实际开发中,可以通过java调用cmd命令,使用ffmpeg进行切片操作,主要代码如下:
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/**
* @author hzh
*/
@Component
@Slf4j
public class ProcessUtil {
private ThreadPoolTaskExecutor executor = SpringUtils.getBean("threadPoolTaskExecutor");
/**执行命令
* @param command 命令
* @return 执行结果
*/
public String execute(List<String> command) {
StringBuffer inputStringBuffer = new StringBuffer();
StringBuffer errorStringBuffer = new StringBuffer();
try {
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
log.info("============inputStream============");
// 处理InputStream
executor.execute(() -> {
InputStream input = null;
InputStreamReader reader = null;
BufferedReader buffer = null;
try {
input = process.getInputStream();
reader = new InputStreamReader(input);
buffer = new BufferedReader(reader);
String inputLine = "";
while ((inputLine = buffer.readLine()) != null) {
System.out.println(inputLine);
inputStringBuffer.append(inputLine);
}
//退出循环后表示结束流
log.info("===》》退出循环后表示结束流");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (reader != null) {
reader.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
log.info("============errorStream============");
// 处理ErrorStream
executor.execute(() -> {
InputStream input = null;
InputStreamReader reader = null;
BufferedReader buffer = null;
try {
input = process.getErrorStream();
reader = new InputStreamReader(input);
buffer = new BufferedReader(reader);
String errorLine = "";
while ((errorLine = buffer.readLine()) != null) {
System.out.println(errorLine);
errorStringBuffer.append(errorLine);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (reader != null) {
reader.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
/**
* 只会存在一个输入流返回
*/
if (inputStringBuffer != null) {
return inputStringBuffer.toString();
}
if (errorStringBuffer != null) {
return errorStringBuffer.toString();
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
return null;
}
/**windows版
* ffmpeg实现mp4转m3u8切片(ts)
* @param inputUrl 输入的文件
* @param outputUrl 输出的m3u8文件
* @return cmd打印结果
*/
public String mp4ToM3u8(String inputUrl,String outputUrl){
List<String> command = new ArrayList<>();
command.add("ffmpeg");
command.add("-i");
command.add(inputUrl);
command.add("-c:v");
command.add("copy");
command.add("-c:a");
command.add("copy");
command.add("-f");
command.add("ssegment");
command.add("-segment_format");
command.add("mpegts");
command.add("-segment_list");
command.add(outputUrl);
command.add("-segment_time");
command.add("10");
command.add(outputUrl.substring(0,outputUrl.lastIndexOf("/")) + "/test%05d.ts");
return execute(command);
}
/**
* Linux版
* ffmpeg实现mp4转m3u8切片(ts)
* @param inputUrl 输入的文件
* @param outputUrl 输出的m3u8文件
* @return cmd打印结果
*/
public String mp4ToM3u8ByLinux(String inputUrl,String outputUrl){
List<String> command = new ArrayList<>();
command.add("ffmpeg");
command.add("-i");
command.add(inputUrl);
command.add("-codec");
command.add("copy");
command.add("-hls_list_size");
command.add("0");
command.add("-hls_wrap");
command.add("0");
command.add("-strict");
command.add("-2");
command.add("-vbsf");
command.add("h264_mp4toannexb");
command.add("-absf");
command.add("aac_adtstoasc");
command.add("-f");
command.add("hls");
command.add(outputUrl);
return execute(command);
}
}
3.2相关工具类
3.2.1spring工具类
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* spring工具类 方便在非spring管理环境中获取bean
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
/**
* Spring应用上下文环境
*/
private static ConfigurableListableBeanFactory beanFactory;
private static ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtils.applicationContext = applicationContext;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws BeansException
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws BeansException
*/
public static <T> T getBean(Class<T> clz) throws BeansException {
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws NoSuchBeanDefinitionException
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws NoSuchBeanDefinitionException
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getAliases(name);
}
/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) AopContext.currentProxy();
}
/**
* 获取当前的环境配置,无配置返回null
*
* @return 当前的环境配置
*/
public static String[] getActiveProfiles() {
return applicationContext.getEnvironment().getActiveProfiles();
}
/**
* 获取当前的环境配置,当有多个环境配置时,只获取第一个
*
* @return 当前的环境配置
*/
public static String getActiveProfile() {
final String[] activeProfiles = getActiveProfiles();
return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
}
}
3.2.2线程池配置类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置
*
* @author ruoyi
**/
@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolConfig {
// 核心线程池大小
private int corePoolSize = 50;
// 最大可创建的线程数
private int maxPoolSize = 50;
// 队列最大长度
private int queueCapacity = 1000;
// 线程池维护线程所允许的空闲时间
private int keepAliveSeconds = 300;
@Autowired
VisiableThreadPoolTaskExecutor visiableThreadPoolTaskExecutor;
@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(maxPoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
// 线程池对拒绝任务(无线程可用)的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
3.3实际运用场景
上传视频文件到服务器并进行分片处理的操作,返回m3u8文件url访问路径
3.3.1配置相关类
# 项目相关配置
demo:
# 文件路径 示例( Windows配置D:/e_sign/uploadPath,Linux配置 /home/e_sign/uploadPath)
profile: D:/home/demo/uploadPath
# m3u8分片文件路径
shardingFile: D:/home/demo/uploadPath/m3u8_file
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* @author ruoyi
*/
@Component
@ConfigurationProperties(prefix = "demo")
public class DemoConfig {
/**
* 上传路径
*/
private static String profile;
/**
* m3u8分片文件路径
*/
private static String shardingFile;
public static String getProfile() {
return profile;
}
public void setProfile(String profile) {
DemoConfig.profile = profile;
}
public static String getShardingFile() {
return shardingFile;
}
public void setShardingFile(String shardingFile) {
DemoConfig.shardingFile = shardingFile;
}
}
3.3.2静态资源映射处理
资源映射路径必须以"/"结尾,要不然映射不上去,映射成功就可以用自己的域名跟上映射路径就可以访问到本地的文件夹了
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author : hzh
*/
@SuppressWarnings("deprecation")
@Configuration
public class WebContextConfig extends WebMvcConfigurationSupport {
/**
* 静态资源处理
* 配置静态资源,避免静态资源请求被拦截
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//附件上传静态资源映射
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + DemoConfig.getProfile()+"/");
registry.addResourceHandler(Constants.RESOURCE_PREFIX_M3U8 + "/**").addResourceLocations("file:" + DemoConfig.getShardingFile()+"/");
super.addResourceHandlers(registry);
}
}
常量类
/**
* 通用常量信息
*
* @author ruoyi
*/
public class Constants {
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
/**
* m3u8资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX_M3U8 = "/shardingFile";
}
/**
* 媒体类型工具类
*
* @author ruoyi
*/
public class MimeTypeUtils {
public static final String IMAGE_PNG = "image/png";
public static final String IMAGE_JPG = "image/jpg";
public static final String IMAGE_JPEG = "image/jpeg";
public static final String IMAGE_BMP = "image/bmp";
public static final String IMAGE_GIF = "image/gif";
public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
public static final String[] FLASH_EXTENSION = {"swf", "flv"};
public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb"};
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// pdf
"pdf",
// 视频
"mp4"
};
public static String getExtension(String prefix) {
switch (prefix) {
case IMAGE_PNG:
return "png";
case IMAGE_JPG:
return "jpg";
case IMAGE_JPEG:
return "jpeg";
case IMAGE_BMP:
return "bmp";
case IMAGE_GIF:
return "gif";
default:
return "";
}
}
}
3.3.3文件上传工具类,并调用切片处理
import com.hxqc.esign.exception.file.FileNameLengthLimitExceededException;
import com.hxqc.esign.exception.file.FileSizeLimitExceededException;
import com.hxqc.esign.exception.file.InvalidExtensionException;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
/**
* 文件上传工具类
*
* @author hzh
*/
@Component
public class FileUploadUtils {
@Autowired
private ProcessUtil processUtil;
private static ProcessUtil processUtilStatic;
/**
* 默认大小 300M
*/
public static final long DEFAULT_MAX_SIZE = 300 * 1024 * 1024;
/**
* 默认的文件名最大长度 100
*/
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
/**
* 默认上传的地址
*/
private static String defaultBaseDir = DemoConfig.getProfile();
public static String getDefaultBaseDir() {
return defaultBaseDir;
}
/**
* m3u8分片文件路径
*/
private static String shardingFileDir = DemoConfig.getShardingFile();
public static String getShardingFileDir() {
return shardingFileDir;
}
/**
* 根据文件路径上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @return 文件名称
* @throws IOException
*/
public static final String upload(String baseDir, MultipartFile file) throws IOException {
try {
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
} catch (Exception e) {
throw new IOException(e.getMessage(), e);
}
}
/**
* 文件上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param allowedExtension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长
* @throws IOException 比如读写文件出错时
* @throws InvalidExtensionException 文件校验异常
*/
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException {
int fileNamelength = file.getOriginalFilename().length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
assertAllowed(file, allowedExtension);
String fileName = extractFilename(file);
File desc = getAbsoluteFile(baseDir, fileName);
file.transferTo(desc);
//切片处理
String m3u8Url = getM3u8Url(fileName);
processUtilStatic.mp4ToM3u8(desc.getAbsolutePath(), m3u8Url);
String pathFileName = getPathFileName(baseDir, fileName);// 视频原文件url访问路径
String m3u8FilName = getM3u8PathFileName(m3u8Url); // m3u8文件url访问路径
return m3u8FilName;
}
private static String getM3u8PathFileName(String m3u8Url) {
return Constants.RESOURCE_PREFIX_M3U8 + "/" + m3u8Url.substring(shardingFileDir.length()+1);
}
/**
* @param fileName
* @return
*/
public static final String getM3u8Url(String fileName) throws IOException {
String folderName = fileName.substring(fileName.lastIndexOf("/"), fileName.lastIndexOf("."));
File desc = new File(shardingFileDir + folderName + "/t.txt");
if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
return shardingFileDir + folderName + folderName + ".m3u8";
}
/**
* 编码文件名
*/
public static final String extractFilename(MultipartFile file) {
String extension = getExtension(file);
return DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
}
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
File desc = new File(uploadDir + File.separator + fileName);
if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
if (!desc.exists()) {
boolean newFile = desc.createNewFile();
}
return desc;
}
private static final String getPathFileName(String uploadDir, String fileName) {
return Constants.RESOURCE_PREFIX + "/" + fileName;
}
/**
* 文件大小校验
*
* @param file 上传的文件
* @return
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws InvalidExtensionException
*/
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, InvalidExtensionException {
long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) {
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
String fileName = file.getOriginalFilename();
String extension = getExtension(file);
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
fileName);
} else {
throw new InvalidExtensionException(allowedExtension, extension, fileName);
}
}
}
/**
* 判断MIME类型是否是允许的MIME类型
*
* @param extension
* @param allowedExtension
* @return
*/
public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
for (String str : allowedExtension) {
if (str.equalsIgnoreCase(extension)) {
return true;
}
}
return false;
}
/**
* 获取文件名的后缀
*
* @param file 表单文件
* @return 后缀名
*/
public static final String getExtension(MultipartFile file) {
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension)) {
extension = MimeTypeUtils.getExtension(file.getContentType());
}
return extension;
}
@PostConstruct
private void init() {
processUtilStatic = processUtil;
}
}
相关工具类
public static String fastUUID() {
return UUID.fastUUID().toString();
}
/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static final String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
3.4控制层
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 通用请求处理
*
* @author hzh
*/
@RestController
@RequestMapping("/common")
@Api(tags = {"common"},value = "common")
public class CommonController {
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
@Autowired
private ProcessUtil processUtil;
@ApiOperation("通用上传请求")
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) {
try {
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(ESignConfig.getProfile(), file);
String url = serverConfig.getUrl() + fileName;
Map<String, Object> result = new HashMap<>();
result.put("fileName", fileName);
result.put("url", url);
return AjaxResult.success(ajax);
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
}
服务相关配置
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* 服务相关配置
*
* @author hzh
*/
@Component
public class ServerConfig {
/**
* 获取完整的请求路径,包括:域名,端口,上下文访问路径
*
* @return 服务地址
*/
public String getUrl() {
HttpServletRequest request = ServletUtils.getRequest();
return getDomain(request);
}
public static String getDomain(HttpServletRequest request) {
StringBuffer url = request.getRequestURL();
String contextPath = request.getServletContext().getContextPath();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
}
}
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 客户端工具类
*
* @author ruoyi
*/
public class ServletUtils {
/**
* 获取String参数
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}
/**
* 获取response
*/
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}
/**
* 获取session
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string) {
try {
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 是否是Ajax异步请求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {
return true;
}
return false;
}
}
3.5测试
执行返回结果
生成对应文件
TS切片好处
比如:我们上传一个10MB的视频进行播放,如果不进行切片话,前端页面在播放时需要先下载完整的视频,这样会导致视频加载时间过长。如果使用ts切片后使用m3u8进行播放,在前端播放时页面会自动间隔一定时间下载ts文件进行播放。
参考链接
https://lhz1219.blog.csdn.net/article/details/121875181?spm=1001.2014.3001.5506
https://blog.csdn.net/zhuocailing3390/article/details/121875181