.m3u8格式HLS直播流不间断拉取切割分段转换成MP4格式

在原文链接代码里进行了调整:非常感谢原文作者
原文链接:利用FFmpeg将HLS直播列表.m3u8格式转为mp4保存
原文代码中已经实现[利用FFmpeg将HLS直播列表.m3u8格式转为mp4保存,在此基础上因业务需求做了以下调整:
1、24小时不间断拉取直播流并分段保存。
2、在拉取过程中将过程文件存入临时目录中。
3、在拉取过程中突然拉几个视频就停了,问题处理。
只贴一下修改的类代码:
HlsToMp4TestController

package cn.piesat.web.controller.app;import cn.piesat.app.domain.VideoParamsVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;/*** description:** @author jwb* @date 2022/1/12*/
@RestController
@Slf4j
@RequestMapping("/app/convert")
public class HlsToMp4TestController {static final String DEST_VIDEO_TYPE = ".mp4";static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMddHHmmssSSS");//查看json文件@Value("${sys-config.video-path}")private String videoPath;@PostMapping("/convert_to_mp4")public void convertToMp4(@RequestBody VideoParamsVO dataVO) throws InterruptedException {String sourceVideoUrl = dataVO.getSourceVideoUrl();Assert.notNull(sourceVideoUrl, "视频源不能为空");// 将m3u8格式视频转为mp4本地文件(用于转换格式的中间文件)String destFileName = HlsToMp4Processor.process(sourceVideoUrl,videoPath);if (StringUtils.isEmpty(destFileName)) {log.error("操作失败");}// 推送流if(StringUtils.isNotEmpty(dataVO.getDestVideoPath())) {// Thread.sleep(20000);new VideoPusher().from(destFileName).to(dataVO.getDestVideoPath()  + "ceshi_" + SDF.format(new Date()) + DEST_VIDEO_TYPE).go();// 删除中间文件new File(destFileName).delete();}//递归调用,重新拉取convertToMp4(dataVO);}
}

HlsToMp4Processor

package cn.piesat.web.controller.app;import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.Loader;
import org.springframework.util.StringUtils;import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** description:* 根据hls直播地址,将hls的m3u8播放列表格转为mp4格式* 如果原视频不是m3u8格式则不用进行中间转换。** javacv的采集器FFmpegFrameGrabber并不支持直接读取hls的m3u8格式文件,* 所以没法直接用采集、录制的方式进行m3u8到mp4的转换。* 这里的实现过程是直接操作ffmpeg,** todo:使用ffmepg用于格式转换速度较慢** @author liuxingwu* @date 2022/1/9*/
@Slf4j
public class HlsToMp4Processor{static final String DEST_VIDEO_TYPE = ".mp4";static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMddHHmmssSSS");static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);/*** 方法入口** @param sourceVideoPath   视频源路径* @return*/public static String process(String sourceVideoPath,String tempUrl) {log.info("开始进行格式转换");if (!checkContentType(sourceVideoPath)) {log.info("请输入.m3u8格式的文件");return "";}// 获取文件名String destVideoPath = tempUrl+ "ceshi_" + SDF.format(new Date()) + DEST_VIDEO_TYPE;// 执行转换逻辑return processToMp4(sourceVideoPath, destVideoPath) ? destVideoPath : "";}private static String getFileName(String sourceVideoPath) {return sourceVideoPath.substring(sourceVideoPath.contains("/") ?sourceVideoPath.lastIndexOf("/") + 1 : sourceVideoPath.lastIndexOf("\\") + 1,sourceVideoPath.lastIndexOf("."));}/*** 执行转换逻辑* @author saodisheng_liuxingwu* @modifyDate 2022/1/9*/private static boolean processToMp4(String sourceVideoPath, String destVideoPath) {long startTime = System.currentTimeMillis();List<String> command = new ArrayList<String>();//获取JavaCV中的ffmpeg本地库的调用路径String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);command.add(ffmpeg);// 设置支持的网络协议command.add("-protocol_whitelist");command.add("concat,file,http,https,tcp,tls,crypto");command.add("-i");command.add(sourceVideoPath);//拉取60秒command.add("-t");command.add("60");//跳过40秒,解决拉取几个视频突然停止问题command.add("-ss");command.add("40");command.add(destVideoPath);System.out.print("命令:"+command);try {Process videoProcess = new ProcessBuilder(command).redirectErrorStream(true).start();fixedThreadPool.execute(new ReadStreamInfo(videoProcess.getErrorStream()));fixedThreadPool.execute(new ReadStreamInfo(videoProcess.getInputStream()));videoProcess.waitFor();//这里会生成一个临时的中间文件,转换完成会删除掉log.info("中间转换已完成,生成文件:" + destVideoPath);//  processToMp4(sourceVideoPath,destVideoPath);return true;} catch (Exception e) {e.printStackTrace();return false;} finally {long endTime = System.currentTimeMillis();log.info("用时:" + (int)((endTime - startTime) / 1000) + "秒");}}/*** 检验是否为m3u8文件* @author saodisheng_liuxingwu* @modifyDate 2022/1/9*/private static boolean checkContentType(String filePath) {if (StringUtil.isEmpty(filePath)) {return false;}String type = filePath.substring(filePath.lastIndexOf(".") + 1, filePath.length()).toLowerCase();return "m3u8".equals(type);}
}

创作不易,大家帮忙关注一下公众号,感谢。
在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部