0
点赞
收藏
分享

微信扫一扫

七牛云直播转mp4并截取视频

1、问题

前几天有一个视频截取的需求,七牛云直播回放地址是m3u8格式的,客户让把m3u8转成mp4格式后再进行视频截取。

2、思路

1.拿到前端传的截取起止时间,先简单判断参数是否合法

2.根据m3u8地址获取文件信息,并解析出直播推流的起止时间

3.判断前端传的截取时间是否在直播推流起止时间范围内,不判断的话后面截取会报错

4.获取key,生成新的key,给七牛云发送转码指令,拿到转码任务ID

5.根据转码任务ID定时查询转码结果

6.转码失败更新表字段状态,转码成功继续发送视频截取指令,拿到截取任务ID

7.根据任务ID轮询查询截取状态

8.截取成功更新状态和截取后的地址

3.关键代码实现

3.1 解析m3u8文件

replayUrl地址是m3u8格式的直播回放地址

文件解析的正则表达式具体还要根据文件生成格式来定

public static final Pattern TS_PATTERN = Pattern.compile("#EXTINF:(.*?),.*?(\\d+-\\d+).ts");
 
 public VideoTsInfo getM3u8Info(String replayUrl){
         VideoTsInfo videoTsInfo = new VideoTsInfo();
         if (StringUtils.isNotBlank(replayUrl)) {
             try {
                 URL url = new URL(replayUrl);
                 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                 connection.setRequestMethod("GET");
                 connection.setConnectTimeout(3000);
                 connection.setReadTimeout(10000);
                 BufferedReader reader = new BufferedReader(new                                  InputStreamReader(connection.getInputStream()));
                 String line;
                 StringBuilder content = new StringBuilder();
                 while ((line = reader.readLine()) != null) {
                     content.append(line);
                 }
                 reader.close();
                 connection.disconnect();
                 String m3u8Content = content.toString();
                 if (StringUtils.isBlank(m3u8Content)) {
                     return null;
                 }
                 Matcher matcher = TS_PATTERN.matcher(m3u8Content);
                 double totalDuration = 0;
                 VideoTsInfo start = null;
                 VideoTsInfo end = null;
                 while (matcher.find()) {
                     String[] strings = matcher.group(2).split("-");
                     if (start == null) {
                         start = new VideoTsInfo(strings);
                     }
                     end = new VideoTsInfo(strings);
                     String durationString = matcher.group(1);
                     double duration = Double.parseDouble(durationString);
                     totalDuration += duration;
                 }
                 if (start != null) {
                     videoTsInfo.setStartTime(start.getStartTime());
                 }
                 if (end != null) {
                     videoTsInfo.setEndTime(end.getEndTime());
                 }
                 videoTsInfo.setDuration((long)totalDuration);
                 return videoTsInfo;
             } catch (Exception e) {
                 logger.info("获取视频的时间信息异常", e);
             }
         }
         return null;
     }

3.2 发送转码指令

这里key,和新key先写死方便测试,key就是回放地址域名后面的部分

livecast是直播桶名

public static String transCodeVideoMp4(String key, String mp4Key) {
     OperationManager operationManager = new OperationManager(auth, new  Configuration(Region.region0()));
         key = "recordings/z1.hljtv-live.fmzb1682668851843/fmzb1682668851843.m3u8";
         mp4Key = "recordings/z1.hljtv-live.fmzb1682668851843/cutVideo/fmzb1682668851843.mp4";
         if (StringUtils.isBlank(key) || StringUtils.isBlank(mp4Key)) {
             logger.info("transCodeVideo,key或者mp4Key为空");
             return null;
         }
         // 设置持久化处理操作参数
         String saveAs = UrlSafeBase64.encodeToString("livecast" + ":" + mp4Key);
         String fops = "avthumb/mp4|saveas/" + saveAs; // 转换并保存为新文件名
         logger.info("直播桶:{},transCodeVideoMp4,key:{},newsKey:{},fops:{}",QiNiuConfig.LIVE_HUB,key,mp4Key,fops);
         try {
             return QiNiuConfig.operationManager.pfop("livecast", key, fops, pipeline,true);
         } catch (QiniuException e) {
             logger.error("transCodeVideo", e);
         }
         return null;
     }

运行测试一下,成功拿到任务id

3.3 查询转码结果

定时任务这里就不写了,简单说一下怎么获取任务结果

直接在浏览器直接访问七牛云的这个地址,后面参数就是任务id

看到code:0代表任务执行成功;items中的key就是我们的转码后的key

3.4 MP4视频截取

转码成功后,我们拿到items中的key去发送视频截取指令,代码如下:

发送成功后会获取到截取的任务id,然后再根据这个任务id轮询获取截取结果就可以了。

指令中的ss代表截取指令,后面跟截取的开始时间,/t代表时间单位秒,后面跟截取的结束时间。

截取成功后的key在拼接直播域名就是一个完整的访问地址。

在代码中可以看到operationManager.prefop(persistId)也是可以获取到任务执行结果的。

public static boolean interceptPart(){
         String path = "recordings/z1.hljtv-live.fmzb1682668851843/fmzb1682668851843.mp4";
         try {
             String streamKey = "fmzb1682668851843";
             logger.info("streamKey{}:",streamKey);
             String saveAsKey = new StringBuilder("recordings/z1.")
                     .append(QiNiuConfig.LIVE_HUB)
                     .append(".")
                     .append(streamKey)
                     .append("/")
                     .append(streamKey)
                     .append("cutVideo")
                     .append(System.currentTimeMillis())
                     .append(".mp4")
                     .toString();
             String encodedSaveAs = Base64.getUrlEncoder().encodeToString(("livecast" + ":" + saveAsKey).getBytes());
             StringBuilder sb = new StringBuilder();
             sb.append("avthumb/mp4/ss/");
             sb.append(0);
             sb.append("/t/").append(60).append("|saveas/").append(encodedSaveAs);
             String fops = sb.toString();
             String persistId = QiNiuConfig.operationManager.pfop("livecast", path, fops, pipeline,true);
             logger.info("mp4视频截取任务id:{}",persistId);
             //轮询截取进度
             // 查询持久化进度
             boolean isProcessing = true;
             while (isProcessing) {
                 Thread.sleep(3000);  // 每隔3秒查询一次
                 OperationStatus status = QiNiuConfig.operationManager.prefop(persistId);
                 System.out.println("mp4视频截取任务结果: " + status.code);
                 logger.info("mp4视频截取任务结果:{}",JSON.toJSONString(status));
                 if (status.code == 0 || status.code == 3) {
                     isProcessing = false;
                     if(status.code == 0){
                         String newUrl = new StringBuilder("https://")
                                 .append("/").append(saveAsKey)
                                 .toString();
                         System.out.println(newUrl);
                     }
                 }
             }
         } catch (Exception e) {
             logger.error("生成回放地址出错", e);
         }
         return false;
     }

说明:代码中的QiNiuConfig是七牛的一些配置,包括akskoperationManagerbucketManager等信息。

举报

相关推荐

0 条评论