Compare commits

...

3 Commits

Author SHA1 Message Date
孙小云 4820bab91d xx 2025-03-15 09:31:34 +08:00
孙小云 70c658ea8c xx 2025-03-13 10:43:03 +08:00
孙小云 785a4cd6d9 xx 2025-03-13 09:14:20 +08:00
5 changed files with 416 additions and 21 deletions

11
pom.xml
View File

@ -51,8 +51,17 @@
<artifactId>fastjson2</artifactId>
<version>2.0.53</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.minio</groupId>-->
<!-- <artifactId>minio</artifactId>-->
<!-- <version>3.0.10</version>-->
<!-- </dependency>-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.3</version>
</dependency>
</dependencies>

View File

@ -34,6 +34,9 @@ public class StreamRecordController {
@Autowired
IRecordService iRecordService;
@GetMapping("start")
public Response<StreamTask> startRecording(@RequestParam String streamUrl) {
System.out.println("启动录制 :"+streamUrl);

View File

@ -0,0 +1,214 @@
package com.tuoheng.steam.controller;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.credentials.AssumeRoleProvider;
import io.minio.credentials.Credentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@RestController()
@RequestMapping("/test")
public class TestController {
@Value("${minio.oss.endpoint}")
private String endpoint;
@Value("${minio.oss.accessKeyId}")
private String accessKeyId;
@Value("${minio.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${minio.oss.bucketName}")
private String bucketName;
//文件存储目录
@Value("${minio.oss.filedir}")
private String filedir;
@Value("${minio.oss.dajiangName}")
private String dajiangName;
@Value("${minio.oss.dajiangPassword}")
private String dajiangPassword;
//授权策略允许访问名为bucket的桶的目录
public static final String ROLE_ARN = "arn:aws:s3:::";
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
@GetMapping("/hello")
public String home() {
return "Hello World";
}
@GetMapping("/check")
public String check() throws Exception {
File file = new File("/Users/sunpeng/workspace/text.txt");
InputStream inputStream = new FileInputStream(file);
try {
uploadFile2OSS(inputStream,"text.txt",file.length());
}catch (Exception e) {
logger.error("uploadFile2OSS",e);
}
return "OK";
}
@GetMapping("/key")
public Credentials key() throws Exception {
return getCredentials();
}
private void uploadFile2OSS(InputStream inputStream, String fileName, long streamSize) throws Exception{
MinioClient minioClient = null;
try {
minioClient = MinioClient.builder()
.endpoint(endpoint) // MinIO 服务器地址
.credentials(accessKeyId, accessKeySecret) // 访问密钥和秘密密钥
.build();
}catch (Exception e) {
logger.error("builder",e);
}
String contentType = getContentType(fileName.substring(fileName.lastIndexOf("."))); // 获取文件类型
try {
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName) // 存储桶名称
.object(filedir + "/" + fileName) // 对象名称路径
.stream(inputStream, streamSize, -1) // 输入流文件大小-1 表示未知大小
.contentType(contentType) // 文件类型
.build()
);
}catch (Exception e) {
logger.error("putObject",e);
logger.info("bucketName:{}",bucketName);
logger.info("object:{}",filedir + "/" + fileName);
logger.info("inputStream:{}",inputStream);
logger.info("contentType:{}",contentType);
}
}
private static String getContentType(String FilenameExtension) {
if (FilenameExtension.equalsIgnoreCase(".bmp")) {
return "image/bmp";
}
if (FilenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
FilenameExtension.equalsIgnoreCase(".jpg") ||
FilenameExtension.equalsIgnoreCase(".png")) {
return "image/jpeg";
}
if (FilenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (FilenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (FilenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (FilenameExtension.equalsIgnoreCase(".pptx") ||
FilenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (FilenameExtension.equalsIgnoreCase(".docx") ||
FilenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (FilenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
//PDF
if (FilenameExtension.equalsIgnoreCase(".pdf")) {
return "application/pdf";
}
//excel
if (FilenameExtension.equalsIgnoreCase(".xls") ||
FilenameExtension.equalsIgnoreCase(".xlsx")) {
return "application/octet-stream";
}
//waypoints 拓恒+大疆的航线文件类型
if (FilenameExtension.equalsIgnoreCase(".waypoints") ||
FilenameExtension.equalsIgnoreCase(".kmz")) {
return "application/octet-stream";
}
return "image/jpeg";
}
/**
* 得到 临时凭据
*/
private Credentials getCredentials() throws Exception {
String POLICY_GET_AND_PUT = "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Action\": [\n" +
" \"s3:GetObject\",\n" +
" \"s3:GetBucketLocation\",\n" +
" \"s3:PutObject\"\n" +
" ],\n" +
" \"Resource\": [\n" +
" \"arn:aws:s3:::"+bucketName+"/*\"\n" +
" ]\n" +
" }\n" +
" ]\n" + "}";
int durationSeconds = 360000;//
//创建签名对象
AssumeRoleProvider provider = new AssumeRoleProvider(
endpoint,
dajiangName,
dajiangPassword,
durationSeconds,//默认3600秒失效设置小于这个就是3600大于3600就实际值
POLICY_GET_AND_PUT,
"us-east-1",
ROLE_ARN+bucketName+"/*",
"anysession",
null,
null);
Credentials credentials = provider.fetch();
/**
* 下面的值按照大疆的要求传给大疆
*/
System.out.println("sessionToken=" + credentials.sessionToken());
System.out.println("accessKey=" + credentials.accessKey());
System.out.println("secretKey=" + credentials.secretKey());
System.out.println("isExpired=" + credentials.isExpired());
return credentials;
}
}

View File

@ -7,18 +7,55 @@ import com.tuoheng.steam.service.dos.FlvRecord;
import com.tuoheng.steam.service.dos.Mp4Record;
import com.tuoheng.steam.service.dos.StreamRecord;
import com.tuoheng.steam.util.TimeUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.credentials.AssumeRoleProvider;
import io.minio.credentials.Credentials;
import io.minio.errors.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Component
public class Scheduler {
@Value("${minio.oss.endpoint}")
private String endpoint;
@Value("${minio.oss.accessKeyId}")
private String accessKeyId;
@Value("${minio.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${minio.oss.bucketName}")
private String bucketName;
//文件存储目录
@Value("${minio.oss.filedir}")
private String filedir;
@Value("${minio.oss.dajiangName}")
private String dajiangName;
@Value("${minio.oss.dajiangPassword}")
private String dajiangPassword;
//授权策略允许访问名为bucket的桶的目录
public static final String ROLE_ARN = "arn:aws:s3:::";
private static final Logger logger = LoggerFactory.getLogger(Scheduler.class);
@Autowired
@ -31,30 +68,154 @@ public class Scheduler {
* 初次执行延迟6秒执行
* 每隔 60 分钟执行一次 60*60*1000
*/
@Scheduled(fixedRate = 3600000, initialDelay = 6000)
public void mergeTask() {
System.out.println("开始FLV到MP4的转换 - " + System.currentTimeMillis() / 1000);
List<DayRecord> dayRecords = iRecordService.findDaysPath();
for (int index = 0; index < dayRecords.size(); index++) {
@Scheduled(fixedRate = 3600000, initialDelay = 10)
public void mergeTask() throws Exception {
// File file = new File("/Users/sunpeng/workspace/text.txt");
// InputStream inputStream = new FileInputStream(file);
// try {
// uploadFile2OSS(inputStream,"text.txt",file.length());
// }catch (Exception e) {
// logger.error(e.getMessage());
// }
DayRecord dayRecord = dayRecords.get(index);
if(TimeUtils.isBefore(dayRecord.getDay(),livedates)){
dayRecord.clear();
} else {
List<StreamRecord> streamRecords = dayRecord.getStreamRecords();
for(StreamRecord streamRecord : streamRecords){
List<FlvRecord> flvRecords = streamRecord.queryFlvRecords();
for(FlvRecord flvRecord : flvRecords){
iRecordService.mergeMp4(flvRecord);
}
}
}
}
getCredentials();
}
/**
* 得到 临时凭据
*/
private Credentials getCredentials() throws Exception {
String POLICY_GET_AND_PUT = "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Action\": [\n" +
" \"s3:GetObject\",\n" +
" \"s3:GetBucketLocation\",\n" +
" \"s3:PutObject\"\n" +
" ],\n" +
" \"Resource\": [\n" +
" \"arn:aws:s3:::"+bucketName+"/*\"\n" +
" ]\n" +
" }\n" +
" ]\n" + "}";
int durationSeconds = 360000;//
//创建签名对象
AssumeRoleProvider provider = new AssumeRoleProvider(
endpoint,
dajiangName,
dajiangPassword,
durationSeconds,//默认3600秒失效设置小于这个就是3600大于3600就实际值
POLICY_GET_AND_PUT,
"us-east-1",
ROLE_ARN+bucketName+"/*",
"anysession",
null,
null);
Credentials credentials = provider.fetch();
/**
* 下面的值按照大疆的要求传给大疆
*/
// System.out.println("sessionToken=" + credentials.sessionToken());
// System.out.println("accessKey=" + credentials.accessKey());
// System.out.println("secretKey=" + credentials.secretKey());
// System.out.println("isExpired=" + credentials.isExpired());
return credentials;
}
private void uploadFile2OSS(InputStream inputStream, String fileName, long streamSize) throws Exception{
// 初始化 MinioClient
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint) // MinIO 服务器地址
.credentials(accessKeyId, accessKeySecret) // 访问密钥和秘密密钥
.build();
String contentType = getContentType(fileName.substring(fileName.lastIndexOf("."))); // 获取文件类型
try {
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName) // 存储桶名称
.object(filedir + "/" + fileName) // 对象名称路径
.stream(inputStream, streamSize, -1) // 输入流文件大小-1 表示未知大小
.contentType(contentType) // 文件类型
.build()
);
}catch (Exception e) {
logger.error(e.getMessage());
}
}
private static String getContentType(String FilenameExtension) {
if (FilenameExtension.equalsIgnoreCase(".bmp")) {
return "image/bmp";
}
if (FilenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
FilenameExtension.equalsIgnoreCase(".jpg") ||
FilenameExtension.equalsIgnoreCase(".png")) {
return "image/jpeg";
}
if (FilenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (FilenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (FilenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (FilenameExtension.equalsIgnoreCase(".pptx") ||
FilenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (FilenameExtension.equalsIgnoreCase(".docx") ||
FilenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (FilenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
//PDF
if (FilenameExtension.equalsIgnoreCase(".pdf")) {
return "application/pdf";
}
//excel
if (FilenameExtension.equalsIgnoreCase(".xls") ||
FilenameExtension.equalsIgnoreCase(".xlsx")) {
return "application/octet-stream";
}
//waypoints 拓恒+大疆的航线文件类型
if (FilenameExtension.equalsIgnoreCase(".waypoints") ||
FilenameExtension.equalsIgnoreCase(".kmz")) {
return "application/octet-stream";
}
return "image/jpeg";
}
// public static boolean isWithin15Minutes(String timestamp1, String timestamp2) {
// // 将字符串转换为 long 类型
// long time1 = Long.parseLong(timestamp1);

View File

@ -1,5 +1,5 @@
spring.application.name=demo
server.port = 8989
server.port = 7788
srs.splitPath=/data/java/srs/stream_server/temp
srs.targetPath=/data/java/srs/srs/trunk/objs/nginx/html
ffmpeg=/data/ffmpeg/bin/ffmpeg
@ -12,3 +12,11 @@ livedates=8
#ffmpeg=ffmpeg
#recordPath=/Users/sunpeng/workspace/stream/record
#livedates=7
minio.oss.endpoint: https://minio-jndsj.t-aaron.com:2443
minio.oss.accessKeyId: PJM0c2qlauoXv5TMEHm2
minio.oss.accessKeySecret: Wr69Dm3ZH39M3GCSeyB3eFLynLPuGCKYfphixZuI
minio.oss.bucketName: th-airport
minio.oss.filedir: prodFile
minio.oss.dajiangName: dajiang
minio.oss.dajiangPassword: dajiang2025