Showing
16 changed files
with
987 additions
and
16 deletions
| @@ -46,7 +46,6 @@ | @@ -46,7 +46,6 @@ | ||
| 46 | <artifactId>spring-boot-starter-json</artifactId> | 46 | <artifactId>spring-boot-starter-json</artifactId> |
| 47 | </dependency> | 47 | </dependency> |
| 48 | 48 | ||
| 49 | - | ||
| 50 | <dependency> | 49 | <dependency> |
| 51 | <groupId>org.springframework.boot</groupId> | 50 | <groupId>org.springframework.boot</groupId> |
| 52 | <artifactId>spring-boot-configuration-processor</artifactId> | 51 | <artifactId>spring-boot-configuration-processor</artifactId> |
| @@ -58,27 +57,18 @@ | @@ -58,27 +57,18 @@ | ||
| 58 | <artifactId>lombok</artifactId> | 57 | <artifactId>lombok</artifactId> |
| 59 | </dependency> | 58 | </dependency> |
| 60 | 59 | ||
| 61 | - | ||
| 62 | <dependency> | 60 | <dependency> |
| 63 | <groupId>com.baomidou</groupId> | 61 | <groupId>com.baomidou</groupId> |
| 64 | <artifactId>mybatis-plus-spring-boot3-starter</artifactId> | 62 | <artifactId>mybatis-plus-spring-boot3-starter</artifactId> |
| 65 | <version>3.5.7</version> | 63 | <version>3.5.7</version> |
| 66 | - | ||
| 67 | </dependency> | 64 | </dependency> |
| 68 | 65 | ||
| 69 | - | ||
| 70 | - | ||
| 71 | - | ||
| 72 | - | ||
| 73 | - | ||
| 74 | <dependency> | 66 | <dependency> |
| 75 | <groupId>com.alibaba</groupId> | 67 | <groupId>com.alibaba</groupId> |
| 76 | <artifactId>fastjson</artifactId> | 68 | <artifactId>fastjson</artifactId> |
| 77 | <version>1.2.47</version> | 69 | <version>1.2.47</version> |
| 78 | </dependency> | 70 | </dependency> |
| 79 | 71 | ||
| 80 | - | ||
| 81 | - | ||
| 82 | <dependency> | 72 | <dependency> |
| 83 | <groupId>com.alibaba</groupId> | 73 | <groupId>com.alibaba</groupId> |
| 84 | <artifactId>druid</artifactId> | 74 | <artifactId>druid</artifactId> |
| @@ -122,16 +112,12 @@ | @@ -122,16 +112,12 @@ | ||
| 122 | <version>23.0</version> | 112 | <version>23.0</version> |
| 123 | </dependency> | 113 | </dependency> |
| 124 | 114 | ||
| 125 | - | ||
| 126 | - | ||
| 127 | <dependency> | 115 | <dependency> |
| 128 | <groupId>ch.qos.logback</groupId> | 116 | <groupId>ch.qos.logback</groupId> |
| 129 | <artifactId>logback-classic</artifactId> | 117 | <artifactId>logback-classic</artifactId> |
| 130 | <!-- <version>1.2.3</version>--> | 118 | <!-- <version>1.2.3</version>--> |
| 131 | </dependency> | 119 | </dependency> |
| 132 | 120 | ||
| 133 | - | ||
| 134 | - | ||
| 135 | <dependency> | 121 | <dependency> |
| 136 | <groupId>org.codehaus.janino</groupId> | 122 | <groupId>org.codehaus.janino</groupId> |
| 137 | <artifactId>janino</artifactId> | 123 | <artifactId>janino</artifactId> |
| @@ -143,6 +129,12 @@ | @@ -143,6 +129,12 @@ | ||
| 143 | <version>5.8.32</version> | 129 | <version>5.8.32</version> |
| 144 | </dependency> | 130 | </dependency> |
| 145 | 131 | ||
| 132 | + <dependency> | ||
| 133 | + <groupId>commons-io</groupId> | ||
| 134 | + <artifactId>commons-io</artifactId> | ||
| 135 | + <version>2.15.1</version> | ||
| 136 | + </dependency> | ||
| 137 | + | ||
| 146 | </dependencies> | 138 | </dependencies> |
| 147 | 139 | ||
| 148 | <build> | 140 | <build> |
| 1 | +package com.wondertek.service; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import com.wondertek.vo.media.Media; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @description 媒体分析 | ||
| 8 | + * @author W5669 | ||
| 9 | + * @date 2025/8/19 17:27 | ||
| 10 | + | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +public interface MediaInfoService { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 获取媒体信息 | ||
| 17 | + * @param mediaPath 媒体文件路径 | ||
| 18 | + * @param logId 日志id | ||
| 19 | + * @return 返回null时说明处理有异常 | ||
| 20 | + */ | ||
| 21 | + Media getMediaInfo(String mediaPath, String logId) throws Exception; | ||
| 22 | +} |
| 1 | package com.wondertek.service.impl; | 1 | package com.wondertek.service.impl; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollectionUtil; | 3 | import cn.hutool.core.collection.CollectionUtil; |
| 4 | +import cn.hutool.core.convert.ConvertException; | ||
| 4 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.hutool.http.HttpRequest; | 6 | import cn.hutool.http.HttpRequest; |
| 6 | import cn.hutool.http.HttpResponse; | 7 | import cn.hutool.http.HttpResponse; |
| 8 | +import cn.hutool.json.JSONUtil; | ||
| 9 | +import com.alibaba.fastjson.JSON; | ||
| 7 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 10 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 8 | import com.baomidou.mybatisplus.core.metadata.IPage; | 11 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 12 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| @@ -23,7 +26,10 @@ import com.wondertek.mapper.BackupMaterialMapper; | @@ -23,7 +26,10 @@ import com.wondertek.mapper.BackupMaterialMapper; | ||
| 23 | import com.wondertek.mapper.StreamTaskMapper; | 26 | import com.wondertek.mapper.StreamTaskMapper; |
| 24 | import com.wondertek.service.BackupMaterialService; | 27 | import com.wondertek.service.BackupMaterialService; |
| 25 | import com.wondertek.service.FileService; | 28 | import com.wondertek.service.FileService; |
| 29 | +import com.wondertek.service.MediaInfoService; | ||
| 26 | import com.wondertek.util.*; | 30 | import com.wondertek.util.*; |
| 31 | +import com.wondertek.vo.media.Media; | ||
| 32 | +import com.wondertek.vo.media.MediaType; | ||
| 27 | import jakarta.annotation.Resource; | 33 | import jakarta.annotation.Resource; |
| 28 | import lombok.extern.slf4j.Slf4j; | 34 | import lombok.extern.slf4j.Slf4j; |
| 29 | import org.apache.commons.lang3.StringUtils; | 35 | import org.apache.commons.lang3.StringUtils; |
| @@ -59,6 +65,8 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, | @@ -59,6 +65,8 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, | ||
| 59 | private String recGetImageUrl; | 65 | private String recGetImageUrl; |
| 60 | @Value("${file.previewUrl}") | 66 | @Value("${file.previewUrl}") |
| 61 | private String previewUrl; | 67 | private String previewUrl; |
| 68 | + @Resource | ||
| 69 | + private MediaInfoService mediaInfoService; | ||
| 62 | 70 | ||
| 63 | 71 | ||
| 64 | @Override | 72 | @Override |
| @@ -289,8 +297,6 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, | @@ -289,8 +297,6 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, | ||
| 289 | } catch (Exception e) { | 297 | } catch (Exception e) { |
| 290 | return ResultBean.error("上传文件异常"); | 298 | return ResultBean.error("上传文件异常"); |
| 291 | } | 299 | } |
| 292 | - // | ||
| 293 | - | ||
| 294 | 300 | ||
| 295 | //保存垫片素材表 | 301 | //保存垫片素材表 |
| 296 | BackupMaterial backupMaterial = new BackupMaterial(); | 302 | BackupMaterial backupMaterial = new BackupMaterial(); |
| @@ -336,6 +342,23 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, | @@ -336,6 +342,23 @@ public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, | ||
| 336 | log.error("请求能力平台定帧抽图接口失败,url:{}", switchStreamUrl, e); | 342 | log.error("请求能力平台定帧抽图接口失败,url:{}", switchStreamUrl, e); |
| 337 | } | 343 | } |
| 338 | 344 | ||
| 345 | + //媒体分析获取时长 | ||
| 346 | + try { | ||
| 347 | + Media media = mediaInfoService.getMediaInfo(destFilePath, fileId); | ||
| 348 | + String type = media.getType(); | ||
| 349 | + Long duration = 0l;//时长 | ||
| 350 | + switch (type) { | ||
| 351 | + case MediaType.VIDEO_TYPE: | ||
| 352 | + cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(media); | ||
| 353 | + duration = Double.valueOf(jsonObject.get("duration", Double.class) * 1000).longValue(); | ||
| 354 | + backupMaterial.setDuration(duration); | ||
| 355 | + } | ||
| 356 | + } catch (NumberFormatException | ConvertException e) { | ||
| 357 | + log.error("媒体分析获取时长报错:e={}", e); | ||
| 358 | + } catch (Exception e) { | ||
| 359 | + throw new RuntimeException(e); | ||
| 360 | + } | ||
| 361 | + | ||
| 339 | backupMaterialMapper.insert(backupMaterial); | 362 | backupMaterialMapper.insert(backupMaterial); |
| 340 | 363 | ||
| 341 | return ResultBean.ok("新增素材成功"); | 364 | return ResultBean.ok("新增素材成功"); |
| 1 | +package com.wondertek.service.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollectionUtil; | ||
| 4 | +import cn.hutool.json.JSONUtil; | ||
| 5 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 6 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 7 | +import com.wondertek.service.MediaInfoService; | ||
| 8 | +import com.wondertek.util.MediaAnalysisHelper; | ||
| 9 | +import com.wondertek.util.MediaInfoUtil; | ||
| 10 | +import com.wondertek.vo.media.*; | ||
| 11 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | +import org.apache.commons.lang3.StringUtils; | ||
| 13 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 14 | +import org.springframework.stereotype.Service; | ||
| 15 | +import org.springframework.util.CollectionUtils; | ||
| 16 | + | ||
| 17 | +import java.util.ArrayList; | ||
| 18 | +import java.util.Arrays; | ||
| 19 | +import java.util.Iterator; | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * @description 媒体分析 | ||
| 24 | + * @author W5669 | ||
| 25 | + * @date 2025/8/19 17:57 | ||
| 26 | + * @param null | ||
| 27 | + | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | +@Service | ||
| 31 | +@Slf4j | ||
| 32 | +public class MediaInfoServiceImpl implements MediaInfoService { | ||
| 33 | + | ||
| 34 | + @Autowired | ||
| 35 | + private MediaInfoUtil mediaInfoUtil; | ||
| 36 | + | ||
| 37 | + private static final ObjectMapper MAPPER = new ObjectMapper(); | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public Media getMediaInfo(String mediaPath, String logId) throws Exception { | ||
| 41 | + log.info("[Media Analysis] getMediaInfo mediaPath:{},logId:{}", mediaPath, logId); | ||
| 42 | + long startTime = System.currentTimeMillis(); | ||
| 43 | + // 工具绝对路径 | ||
| 44 | + String mediaInfoPath = mediaInfoUtil.mediaInfoPath(); | ||
| 45 | + log.info("[Media Analysis] mediaInfo tool path:{} ", mediaInfoPath); | ||
| 46 | + | ||
| 47 | + String mediaInfoJson; | ||
| 48 | + try { | ||
| 49 | + mediaInfoJson = MediaAnalysisHelper.analysis(mediaInfoPath, mediaPath, logId); | ||
| 50 | + log.info("[Media Analysis] getMediaInfo mediaInfoJson:{}", mediaInfoJson); | ||
| 51 | + } catch (Exception e) { | ||
| 52 | + log.error("[Media Analysis] getMediaInfo Exception:{}", e); | ||
| 53 | + throw e; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + if (StringUtils.isBlank(mediaInfoJson)) { | ||
| 57 | + return null; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + Media media; | ||
| 61 | + // 解析工具返回JOSN数据 | ||
| 62 | + try { | ||
| 63 | + String mediaType = getMediaType(mediaInfoJson); | ||
| 64 | + log.info("[Media Analysis] getMediaInfo mediaType:{}", mediaType); | ||
| 65 | + | ||
| 66 | + switch (mediaType) { | ||
| 67 | + case MediaType.IMAGE_TYPE: | ||
| 68 | + media = parseImageMedia(mediaInfoJson); | ||
| 69 | + break; | ||
| 70 | + case MediaType.AUDIO_TYPE: | ||
| 71 | + media = parseAudioMedia(mediaInfoJson); | ||
| 72 | + break; | ||
| 73 | + case MediaType.VIDEO_TYPE: | ||
| 74 | + media = parseVideoMedia(mediaInfoJson); | ||
| 75 | + break; | ||
| 76 | + default: | ||
| 77 | + throw new Exception("MediaInfo Cannot analysis media format"); | ||
| 78 | + } | ||
| 79 | + } catch (Exception e) { | ||
| 80 | + log.error("[Media Analysis] getMediaInfo parse json error:{}", e); | ||
| 81 | + throw e; | ||
| 82 | + } | ||
| 83 | + log.info("[Media Analysis] getMediaInfo,mediaPath={}logId={},spendTime={}", mediaPath, logId, | ||
| 84 | + System.currentTimeMillis() - startTime); | ||
| 85 | + | ||
| 86 | + return media; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * 判断媒体类型 | ||
| 91 | + * | ||
| 92 | + * @param mediaInfoJson | ||
| 93 | + * @return MediaType类定义字符串,无法解析返回空字符串 | ||
| 94 | + * @throws Exception | ||
| 95 | + */ | ||
| 96 | + private String getMediaType(String mediaInfoJson) throws Exception { | ||
| 97 | + JsonNode root = MAPPER.readTree(mediaInfoJson); | ||
| 98 | + JsonNode trackNode = root.get("media").get("track"); | ||
| 99 | + Iterator<JsonNode> elements = trackNode.elements(); | ||
| 100 | + | ||
| 101 | + List<String> typeList = new ArrayList<>(); | ||
| 102 | + while (elements.hasNext()) { | ||
| 103 | + JsonNode node = elements.next(); | ||
| 104 | + String type = node.get("@type").asText(); | ||
| 105 | + typeList.add(type); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + if (!CollectionUtils.isEmpty(typeList)) { | ||
| 109 | + if (typeList.contains(MediaType.VIDEO_TYPE)) { | ||
| 110 | + return MediaType.VIDEO_TYPE; | ||
| 111 | + } | ||
| 112 | + if (typeList.contains(MediaType.AUDIO_TYPE)) { | ||
| 113 | + return MediaType.AUDIO_TYPE; | ||
| 114 | + } | ||
| 115 | + if (typeList.contains(MediaType.IMAGE_TYPE)) { | ||
| 116 | + return MediaType.IMAGE_TYPE; | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + return ""; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + /** | ||
| 124 | + * 图片JOSN数据的解析 | ||
| 125 | + * | ||
| 126 | + * @param mediaInfoJson | ||
| 127 | + * @return | ||
| 128 | + */ | ||
| 129 | + private Media parseImageMedia(String mediaInfoJson) throws Exception { | ||
| 130 | + log.info("[Media Analysis] parseImageMedia"); | ||
| 131 | + ImageMedia imageMedia = new ImageMedia(); | ||
| 132 | + | ||
| 133 | + JsonNode root = MAPPER.readTree(mediaInfoJson); | ||
| 134 | + JsonNode mediaNode = root.get("media"); | ||
| 135 | + | ||
| 136 | + // Media Type | ||
| 137 | + imageMedia.setType(MediaType.IMAGE_TYPE); | ||
| 138 | + | ||
| 139 | + // Media fileName | ||
| 140 | + String fileName = mediaNode.get("@ref").asText(); | ||
| 141 | + imageMedia.setFileName(fileName); | ||
| 142 | + | ||
| 143 | + JsonNode trackNode = mediaNode.get("track"); | ||
| 144 | + Iterator<JsonNode> elemIterator = trackNode.elements(); | ||
| 145 | + while (elemIterator.hasNext()) { | ||
| 146 | + JsonNode node = elemIterator.next(); | ||
| 147 | + String elementType = node.path("@type").asText(); | ||
| 148 | + if (elementType.equals("General")) { | ||
| 149 | + // Media fileExtension | ||
| 150 | + String fileExtension = paserUncertainNode(node, "FileExtension"); | ||
| 151 | + imageMedia.setFileExtension(fileExtension); | ||
| 152 | + // Media format | ||
| 153 | + String format = paserUncertainNode(node, "Format"); | ||
| 154 | + imageMedia.setFormat(format); | ||
| 155 | + // Media size | ||
| 156 | + String fileSize = paserUncertainNode(node, "FileSize"); | ||
| 157 | + imageMedia.setSize(fileSize); | ||
| 158 | + } else if (elementType.equals(MediaType.IMAGE_TYPE)) { | ||
| 159 | + // ImageMedia fileExtension | ||
| 160 | + String width = parseNumberValueNode(node, "Width"); | ||
| 161 | + imageMedia.setWidth(width); | ||
| 162 | + // ImageMedia Height | ||
| 163 | + String height = parseNumberValueNode(node, "Height"); | ||
| 164 | + imageMedia.setHeight(height); | ||
| 165 | + // ImageMedia colorSpace | ||
| 166 | + String colorSpace = paserUncertainNode(node, "ColorSpace"); | ||
| 167 | + imageMedia.setColorSpace(colorSpace); | ||
| 168 | + // ImageMedia chromaSubsampling | ||
| 169 | + String chromaSubsampling = paserUncertainNode(node, "ChromaSubsampling"); | ||
| 170 | + imageMedia.setChromaSubsampling(chromaSubsampling); | ||
| 171 | + // ImageMedia bitDepth | ||
| 172 | + String bitDepth = paserUncertainNode(node, "BitDepth"); | ||
| 173 | + imageMedia.setBitDepth(bitDepth); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + log.info("[Media Analysis] parseImageMedia over:{}", imageMedia); | ||
| 178 | + return imageMedia; | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + /** | ||
| 182 | + * 音频JOSN数据的解析 | ||
| 183 | + * | ||
| 184 | + * @param mediaInfoJson | ||
| 185 | + * @return | ||
| 186 | + */ | ||
| 187 | + private Media parseAudioMedia(String mediaInfoJson) throws Exception { | ||
| 188 | + log.info("[Media Analysis] parseAudioMedia"); | ||
| 189 | + AudioMedia audioMedia = new AudioMedia(); | ||
| 190 | + | ||
| 191 | + JsonNode root = MAPPER.readTree(mediaInfoJson); | ||
| 192 | + JsonNode mediaNode = root.get("media"); | ||
| 193 | + | ||
| 194 | + // Media Type | ||
| 195 | + audioMedia.setType(MediaType.AUDIO_TYPE); | ||
| 196 | + | ||
| 197 | + // Media fileName | ||
| 198 | + String fileName = mediaNode.get("@ref").asText(); | ||
| 199 | + audioMedia.setFileName(fileName); | ||
| 200 | + | ||
| 201 | + JsonNode trackNode = mediaNode.get("track"); | ||
| 202 | + Iterator<JsonNode> elemIterator = trackNode.elements(); | ||
| 203 | + | ||
| 204 | + List<Stream> streamList = new ArrayList<>(); | ||
| 205 | + while (elemIterator.hasNext()) { | ||
| 206 | + JsonNode node = elemIterator.next(); | ||
| 207 | + String elementType = node.path("@type").asText(); | ||
| 208 | + if (elementType.equals("General")) { | ||
| 209 | + // Media fileExtension | ||
| 210 | + String fileExtension = paserUncertainNode(node, "FileExtension"); | ||
| 211 | + audioMedia.setFileExtension(fileExtension); | ||
| 212 | + // Media format | ||
| 213 | + String format = paserUncertainNode(node, "Format"); | ||
| 214 | + audioMedia.setFormat(format); | ||
| 215 | + // Media size | ||
| 216 | + String fileSize = paserUncertainNode(node, "FileSize"); | ||
| 217 | + audioMedia.setSize(fileSize); | ||
| 218 | + // StreamMedia audioCount | ||
| 219 | + String audioCount = paserUncertainNode(node, "AudioCount"); | ||
| 220 | + audioMedia.setAudioCount(audioCount); | ||
| 221 | + // StreamMedia duration | ||
| 222 | + String duration = parseNumberValueNode(node, "Duration"); | ||
| 223 | + audioMedia.setDuration(duration); | ||
| 224 | + // StreamMedia overallBitRate | ||
| 225 | + String overallBitRate = paserUncertainNode(node, "OverallBitRate"); | ||
| 226 | + audioMedia.setOverallBitRate(overallBitRate); | ||
| 227 | + // StreamMedia overallBitRateMode | ||
| 228 | + String overallBitRateMode = paserUncertainNode(node, "OverallBitRate_Mode"); | ||
| 229 | + audioMedia.setOverallBitRateMode(overallBitRateMode); | ||
| 230 | + } else if (elementType.equals(MediaType.AUDIO_TYPE)) { | ||
| 231 | + Stream stream = parseStream(node, MediaType.AUDIO_TYPE); | ||
| 232 | + streamList.add(stream); | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + audioMedia.setSteams(streamList); | ||
| 236 | + | ||
| 237 | + log.info("[Media Analysis] parseAudioMedia over:{}", audioMedia); | ||
| 238 | + return audioMedia; | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + /** | ||
| 242 | + * 视频JOSN数据的解析 | ||
| 243 | + * | ||
| 244 | + * @param mediaInfoJson | ||
| 245 | + * @return | ||
| 246 | + */ | ||
| 247 | + private Media parseVideoMedia(String mediaInfoJson) throws Exception { | ||
| 248 | + log.info("[Media Analysis] parseVideoMedia"); | ||
| 249 | + VideoMedia videoMedia = new VideoMedia(); | ||
| 250 | + | ||
| 251 | + JsonNode root = MAPPER.readTree(mediaInfoJson); | ||
| 252 | + JsonNode mediaNode = root.get("media"); | ||
| 253 | + | ||
| 254 | + videoMedia.setOriginalInfo(JSONUtil.parseObj(mediaInfoJson).toString()); | ||
| 255 | + // Media Type | ||
| 256 | + videoMedia.setType(MediaType.VIDEO_TYPE); | ||
| 257 | + | ||
| 258 | + // Media fileName | ||
| 259 | + String fileName = mediaNode.get("@ref").asText(); | ||
| 260 | + videoMedia.setFileName(fileName); | ||
| 261 | + | ||
| 262 | + JsonNode trackNode = mediaNode.get("track"); | ||
| 263 | + Iterator<JsonNode> elemIterator = trackNode.elements(); | ||
| 264 | + | ||
| 265 | + List<Stream> streamList = new ArrayList<>(); | ||
| 266 | + while (elemIterator.hasNext()) { | ||
| 267 | + JsonNode node = elemIterator.next(); | ||
| 268 | + String elementType = node.path("@type").asText(); | ||
| 269 | + if (elementType.equals("General")) { | ||
| 270 | + // Media fileExtension | ||
| 271 | + String fileExtension = paserUncertainNode(node, "FileExtension"); | ||
| 272 | + videoMedia.setFileExtension(fileExtension); | ||
| 273 | + // Media format | ||
| 274 | + String format = paserUncertainNode(node, "Format"); | ||
| 275 | + videoMedia.setFormat(format); | ||
| 276 | + // Media size | ||
| 277 | + String fileSize = paserUncertainNode(node, "FileSize"); | ||
| 278 | + videoMedia.setSize(fileSize); | ||
| 279 | + // StreamMedia audioCount | ||
| 280 | + String audioCount = paserUncertainNode(node, "AudioCount"); | ||
| 281 | + videoMedia.setAudioCount(audioCount); | ||
| 282 | + // StreamMedia duration | ||
| 283 | + String duration = parseNumberValueNode(node, "Duration"); | ||
| 284 | + videoMedia.setDuration(duration); | ||
| 285 | + // StreamMedia overallBitRate | ||
| 286 | + String overallBitRate = paserUncertainNode(node, "OverallBitRate"); | ||
| 287 | + videoMedia.setOverallBitRate(overallBitRate); | ||
| 288 | + // StreamMedia overallBitRateMode | ||
| 289 | + String overallBitRateMode = paserUncertainNode(node, "OverallBitRate_Mode"); | ||
| 290 | + videoMedia.setOverallBitRateMode(overallBitRateMode); | ||
| 291 | + // VideoMedia videoCount | ||
| 292 | + String videoCount = paserUncertainNode(node, "VideoCount"); | ||
| 293 | + videoMedia.setVideoCount(videoCount); | ||
| 294 | + // VideoMedia formatProfile | ||
| 295 | + String formatProfile = paserUncertainNode(node, "Format_Profile"); | ||
| 296 | + videoMedia.setFormatProfile(formatProfile); | ||
| 297 | + } else if (elementType.equals(MediaType.AUDIO_TYPE)) { | ||
| 298 | + Stream stream = parseStream(node, MediaType.AUDIO_TYPE); | ||
| 299 | + streamList.add(stream); | ||
| 300 | + } else if (elementType.equals(MediaType.VIDEO_TYPE)) { | ||
| 301 | + Stream stream = parseStream(node, MediaType.VIDEO_TYPE); | ||
| 302 | + streamList.add(stream); | ||
| 303 | + } | ||
| 304 | + } | ||
| 305 | + videoMedia.setSteams(streamList); | ||
| 306 | + | ||
| 307 | + log.info("[Media Analysis] parseVideoMedia over:{}", videoMedia); | ||
| 308 | + return videoMedia; | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + /** | ||
| 312 | + * 处理一些不确定的节点 | ||
| 313 | + * | ||
| 314 | + * @param parentNode | ||
| 315 | + * 父节点 | ||
| 316 | + * @param name | ||
| 317 | + * 子节点名称 | ||
| 318 | + * @return | ||
| 319 | + */ | ||
| 320 | + private String paserUncertainNode(JsonNode parentNode, String name) { | ||
| 321 | + JsonNode node = parentNode.get(name); | ||
| 322 | + if (node != null) { | ||
| 323 | + return node.asText(); | ||
| 324 | + } | ||
| 325 | + return ""; | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + /** | ||
| 329 | + * 解析数值字段 | ||
| 330 | + * | ||
| 331 | + * @param parentNode | ||
| 332 | + * @param name | ||
| 333 | + * @return | ||
| 334 | + */ | ||
| 335 | + private String parseNumberValueNode(JsonNode parentNode, String name) { | ||
| 336 | + String parseResult = null; | ||
| 337 | + try { | ||
| 338 | + parseResult = paserUncertainNode(parentNode, name); | ||
| 339 | + if (StringUtils.isNotBlank(parseResult)) { | ||
| 340 | + String valueString = parseResult; | ||
| 341 | + // 处理MediaInfo异常返回,比如:分辨率返回"1920 / 1920"这种情形 | ||
| 342 | + if (parseResult.contains("/")) { | ||
| 343 | + List<String> splitResult = Arrays.asList(StringUtils.split(parseResult, "/")); | ||
| 344 | + if (CollectionUtil.isNotEmpty(splitResult)) { | ||
| 345 | + valueString = splitResult.get(0).trim(); | ||
| 346 | + } | ||
| 347 | + } | ||
| 348 | + Double valueDouble = Double.parseDouble(valueString); // 目的做个校验 | ||
| 349 | + log.info("[Media Analysis] parseNumberValueNode check number value:{}", valueDouble); | ||
| 350 | + return valueString; | ||
| 351 | + } | ||
| 352 | + } catch (Exception e) { | ||
| 353 | + log.error("[Media Analysis] parseNumberValueNode parser value:{} error:{}", parseResult, e); | ||
| 354 | + return "0"; | ||
| 355 | + } | ||
| 356 | + | ||
| 357 | + return "0"; | ||
| 358 | + } | ||
| 359 | + | ||
| 360 | + /** | ||
| 361 | + * 解析音视频流JSON数据 | ||
| 362 | + * | ||
| 363 | + * @param parentNode | ||
| 364 | + * 节点 | ||
| 365 | + * @param streamType | ||
| 366 | + * 音频或者视频 MediaType取值 | ||
| 367 | + * @return | ||
| 368 | + */ | ||
| 369 | + private Stream parseStream(JsonNode parentNode, String streamType) { | ||
| 370 | + Stream stream = null; | ||
| 371 | + if (streamType.equals(MediaType.AUDIO_TYPE)) { | ||
| 372 | + stream = new AudioSteam(); | ||
| 373 | + } else if (streamType.equals(MediaType.VIDEO_TYPE)) { | ||
| 374 | + stream = new VideoStream(); | ||
| 375 | + } | ||
| 376 | + | ||
| 377 | + if (stream == null) { | ||
| 378 | + return null; | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + // 共同的属性 | ||
| 382 | + String steamType = paserUncertainNode(parentNode, "@type"); | ||
| 383 | + stream.setStreamType(steamType); | ||
| 384 | + | ||
| 385 | + String id = paserUncertainNode(parentNode, "ID"); | ||
| 386 | + stream.setId(id); | ||
| 387 | + | ||
| 388 | + String streamOrder = paserUncertainNode(parentNode, "StreamOrder"); | ||
| 389 | + stream.setStreamOrder(streamOrder); | ||
| 390 | + | ||
| 391 | + String format = paserUncertainNode(parentNode, "Format"); | ||
| 392 | + stream.setFormat(format); | ||
| 393 | + | ||
| 394 | + String formatProfile = paserUncertainNode(parentNode, "Format_Profile"); | ||
| 395 | + stream.setFormatProfile(formatProfile); | ||
| 396 | + | ||
| 397 | + String duration = parseNumberValueNode(parentNode, "Duration"); | ||
| 398 | + stream.setDuration(duration); | ||
| 399 | + | ||
| 400 | + String bitRateMode = paserUncertainNode(parentNode, "BitRate_Mode"); | ||
| 401 | + stream.setBitRateMode(bitRateMode); | ||
| 402 | + | ||
| 403 | + String bitRate = paserUncertainNode(parentNode, "BitRate"); | ||
| 404 | + stream.setBitRate(bitRate); | ||
| 405 | + | ||
| 406 | + String bitRateMinimum = paserUncertainNode(parentNode, "BitRate_Minimum"); | ||
| 407 | + stream.setBitRateMinimum(bitRateMinimum); | ||
| 408 | + | ||
| 409 | + String bitRateMaximum = paserUncertainNode(parentNode, "BitRate_Maximum"); | ||
| 410 | + stream.setBitRateMaximum(bitRateMaximum); | ||
| 411 | + | ||
| 412 | + String frameRate = paserUncertainNode(parentNode, "FrameRate"); | ||
| 413 | + stream.setFrameRate(frameRate); | ||
| 414 | + | ||
| 415 | + String frameCount = paserUncertainNode(parentNode, "FrameCount"); | ||
| 416 | + stream.setFrameCount(frameCount); | ||
| 417 | + | ||
| 418 | + String bitDepth = paserUncertainNode(parentNode, "BitDepth"); | ||
| 419 | + stream.setBitDepth(bitDepth); | ||
| 420 | + | ||
| 421 | + String streamSize = paserUncertainNode(parentNode, "StreamSize"); | ||
| 422 | + stream.setStreamSize(streamSize); | ||
| 423 | + | ||
| 424 | + // 处理音视频独特的属性 | ||
| 425 | + if (streamType.equals(MediaType.AUDIO_TYPE)) { | ||
| 426 | + AudioSteam audioSteam = (AudioSteam) stream; | ||
| 427 | + String samplingRate = paserUncertainNode(parentNode, "SamplingRate"); | ||
| 428 | + audioSteam.setSamplingRate(samplingRate); | ||
| 429 | + | ||
| 430 | + String samplingCount = paserUncertainNode(parentNode, "SamplingCount"); | ||
| 431 | + audioSteam.setSamplingCount(samplingCount); | ||
| 432 | + | ||
| 433 | + String channels = paserUncertainNode(parentNode, "Channels"); | ||
| 434 | + audioSteam.setChannels(channels); | ||
| 435 | + | ||
| 436 | + } else if (streamType.equals(MediaType.VIDEO_TYPE)) { | ||
| 437 | + VideoStream videoStream = (VideoStream) stream; | ||
| 438 | + String formatLevel = paserUncertainNode(parentNode, "Format_Level"); | ||
| 439 | + videoStream.setFormatLevel(formatLevel); | ||
| 440 | + | ||
| 441 | + String formatSettingsGOP = paserUncertainNode(parentNode, "Format_Settings_GOP"); | ||
| 442 | + videoStream.setFormatSettingsGOP(formatSettingsGOP); | ||
| 443 | + | ||
| 444 | + String frameRateMode = paserUncertainNode(parentNode, "FrameRate_Mode"); | ||
| 445 | + videoStream.setFrameRateMode(frameRateMode); | ||
| 446 | + | ||
| 447 | + String width = parseNumberValueNode(parentNode, "Width"); | ||
| 448 | + videoStream.setWidth(width); | ||
| 449 | + | ||
| 450 | + String height = parseNumberValueNode(parentNode, "Height"); | ||
| 451 | + videoStream.setHeight(height); | ||
| 452 | + | ||
| 453 | + String displayAspectRatio = paserUncertainNode(parentNode, "DisplayAspectRatio"); | ||
| 454 | + videoStream.setDisplayAspectRatio(displayAspectRatio); | ||
| 455 | + | ||
| 456 | + String colorSpace = paserUncertainNode(parentNode, "ColorSpace"); | ||
| 457 | + videoStream.setColorSpace(colorSpace); | ||
| 458 | + | ||
| 459 | + String chromaSubsampling = paserUncertainNode(parentNode, "ChromaSubsampling"); | ||
| 460 | + videoStream.setChromaSubsampling(chromaSubsampling); | ||
| 461 | + | ||
| 462 | + String scanType = paserUncertainNode(parentNode, "ScanType"); | ||
| 463 | + videoStream.setScanType(scanType); | ||
| 464 | + | ||
| 465 | + } | ||
| 466 | + | ||
| 467 | + return stream; | ||
| 468 | + | ||
| 469 | + } | ||
| 470 | +} |
| 1 | +package com.wondertek.util; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.commons.io.IOUtils; | ||
| 5 | + | ||
| 6 | +import java.io.InputStream; | ||
| 7 | +import java.nio.charset.StandardCharsets; | ||
| 8 | +import java.util.ArrayList; | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @Auther: WANGJING | ||
| 13 | + * @Description: 媒体分析工具类 | ||
| 14 | + * @Date: 2019/11/1 9:40 | ||
| 15 | + * @Modifier: | ||
| 16 | + * @Version: | ||
| 17 | + * @TaskId: YJ-348 | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | +@Slf4j | ||
| 21 | +public class MediaAnalysisHelper { | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * @Description: 获取媒体分析JSON数据 | ||
| 25 | + * @Auther: WANGJING | ||
| 26 | + * @Param mediaInfoPath mediaInfo工具路径 | ||
| 27 | + * @Param mediaFilePath 媒体文件路径 | ||
| 28 | + * @Param logId 日志id | ||
| 29 | + * @Return: 返回分析结果JSON数据 | ||
| 30 | + * @Version: | ||
| 31 | + * @TaskId: YJ-348 | ||
| 32 | + */ | ||
| 33 | + public static String analysis(String mediaInfoPath, String mediaFilePath, String logId) throws Exception { | ||
| 34 | + long startTime = System.currentTimeMillis(); | ||
| 35 | + log.info("[Media Analysis] MediaAnalysisHelper mediaInfoPath:{}, mediaFilePath:{},logId:{}", mediaInfoPath, | ||
| 36 | + mediaFilePath, logId); | ||
| 37 | + List<String> commend = new ArrayList<>(); | ||
| 38 | + commend.add(mediaInfoPath); | ||
| 39 | + commend.add("--OUTPUT=JSON"); // json格式输出 | ||
| 40 | + commend.add(mediaFilePath); | ||
| 41 | + | ||
| 42 | + ProcessBuilder builder = new ProcessBuilder(); | ||
| 43 | + builder.command(commend); | ||
| 44 | + Process process = builder.start(); | ||
| 45 | + int result = process.waitFor(); | ||
| 46 | + | ||
| 47 | + if (result != 0) { | ||
| 48 | + log.info("[Media Analysis] MediaAnalysisHelper Process Failure result={}", result); | ||
| 49 | + throw new Exception("MediaInfo工具处理异常"); | ||
| 50 | + } | ||
| 51 | + log.info("[Media Analysis] MediaAnalysisHelper,mediaFilePath={}logId={},spendTime={}", mediaFilePath, logId, | ||
| 52 | + System.currentTimeMillis() - startTime); | ||
| 53 | + | ||
| 54 | + InputStream inputStream = process.getInputStream(); | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + String josnMediaInfo = IOUtils.toString(inputStream, StandardCharsets.UTF_8); | ||
| 58 | + | ||
| 59 | + return josnMediaInfo; | ||
| 60 | + | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | +} |
| 1 | +package com.wondertek.util; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Auther: WANGJING | ||
| 9 | + * @Description: | ||
| 10 | + * @Modifier: | ||
| 11 | + * @Version: | ||
| 12 | + * @TaskId: YJ-348 | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +@Component | ||
| 16 | +@Slf4j | ||
| 17 | +public class MediaInfoUtil { | ||
| 18 | + | ||
| 19 | + @Value("${file.mediainfoPath}") | ||
| 20 | + private String mediaInfoPath; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 获取MediaInfo工具的路径 | ||
| 24 | + * | ||
| 25 | + * @return | ||
| 26 | + */ | ||
| 27 | + public String mediaInfoPath() { | ||
| 28 | + log.info("[Media Analysis] mediaInfo path:{}", mediaInfoPath); | ||
| 29 | + return mediaInfoPath; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Auther: WANGJING | ||
| 7 | + * @Description: | ||
| 8 | + * @Modifier: | ||
| 9 | + * @Version: | ||
| 10 | + * @TaskId: YJ-348 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +@Data | ||
| 14 | +public class AudioSteam extends Stream { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 采样评率 单位是赫兹 | ||
| 18 | + */ | ||
| 19 | + private String samplingRate; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 采样个数 | ||
| 23 | + */ | ||
| 24 | + private String samplingCount; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 声道 | ||
| 28 | + */ | ||
| 29 | + private String channels; | ||
| 30 | + | ||
| 31 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Auther: WANGJING | ||
| 7 | + * @Description: | ||
| 8 | + * @Modifier: | ||
| 9 | + * @Version: | ||
| 10 | + * @TaskId: YJ-348 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +@Data | ||
| 14 | +public class ImageMedia extends Media { | ||
| 15 | + /** | ||
| 16 | + * 图片宽度 (单位:像素) | ||
| 17 | + */ | ||
| 18 | + private String width; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 图片高度(单位:像素) | ||
| 22 | + */ | ||
| 23 | + private String height; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 色彩空间 RGB YUV | ||
| 27 | + */ | ||
| 28 | + private String colorSpace; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 色度采用 4:2:0 4:4:4等 | ||
| 32 | + */ | ||
| 33 | + private String chromaSubsampling; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 位深 | ||
| 37 | + */ | ||
| 38 | + private String bitDepth; | ||
| 39 | + | ||
| 40 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonInclude; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @Auther: WANGJING | ||
| 8 | + * @Description: | ||
| 9 | + * @Modifier: | ||
| 10 | + * @Version: | ||
| 11 | + * @TaskId: YJ-348 | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | +@Data | ||
| 15 | +@JsonInclude(JsonInclude.Include.NON_NULL) | ||
| 16 | +public class Media { | ||
| 17 | + /** | ||
| 18 | + * 媒体文件 /mnt1/video/test.mp4 | ||
| 19 | + */ | ||
| 20 | + private String fileName; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 文件后缀名(传入媒体文件后缀,不是分析结果) | ||
| 24 | + */ | ||
| 25 | + private String fileExtension; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 媒体类型 MediaType取值之一 | ||
| 29 | + */ | ||
| 30 | + private String type; // 媒体类型 | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 媒体文件封装格式 视频:MPEG-4(mp4,mov),MPEG-TS(ts,mts),MPEG-PS(mpg),AVI(avi),Windows | ||
| 34 | + * Media(wmv),Matroska(mkv)等 音频:MPEG Audio(mp3),Wave(wav) | ||
| 35 | + * 图片:JPEG(jpg,jpeg),PNG(png),GIF(gif) | ||
| 36 | + */ | ||
| 37 | + private String format; | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * 文件大小(单位:字节) | ||
| 41 | + */ | ||
| 42 | + private String size; | ||
| 43 | + | ||
| 44 | + | ||
| 45 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * @Auther: WANGJING | ||
| 5 | + * @Description: 媒体类型 | ||
| 6 | + * @Modifier: | ||
| 7 | + * @Version: | ||
| 8 | + * @TaskId: YJ-348 | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +// 媒体类型 | ||
| 12 | +public class MediaType { | ||
| 13 | + public static final String IMAGE_TYPE = "Image"; // 图片 | ||
| 14 | + public static final String AUDIO_TYPE = "Audio"; // 音频 | ||
| 15 | + public static final String VIDEO_TYPE = "Video"; // 视频 | ||
| 16 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.List; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Auther: WANGJING | ||
| 9 | + * @Description: | ||
| 10 | + * @Modifier: | ||
| 11 | + * @Version: | ||
| 12 | + * @TaskId: YJ-348 | ||
| 13 | + */ | ||
| 14 | + | ||
| 15 | +@Data | ||
| 16 | +public class SteamMedia extends Media { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 音频流的个数 | ||
| 20 | + */ | ||
| 21 | + private String audioCount; | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 时长(单位是:秒 274.176 精确到毫秒) | ||
| 25 | + */ | ||
| 26 | + private String duration; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 平均混合码率(音视频) | ||
| 30 | + */ | ||
| 31 | + private String overallBitRate; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 码率模式 VBR 变码率 ,CBR恒定码率 | ||
| 35 | + */ | ||
| 36 | + private String overallBitRateMode; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 音视频流 | ||
| 40 | + */ | ||
| 41 | + private List<Stream> steams; | ||
| 42 | + | ||
| 43 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Auther: WANGJING | ||
| 7 | + * @Description: | ||
| 8 | + * @Modifier: | ||
| 9 | + * @Version: | ||
| 10 | + * @TaskId: YJ-348 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +@Data | ||
| 14 | +public class Stream { | ||
| 15 | + /** | ||
| 16 | + * 流的类型(Video,Audio) | ||
| 17 | + */ | ||
| 18 | + private String StreamType; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 流的编号 | ||
| 22 | + */ | ||
| 23 | + private String id; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 流的顺序 | ||
| 27 | + */ | ||
| 28 | + private String streamOrder; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 流的编码格式 视频AVC,MPEG Video 音频AAC,MPEG Audio,PCM等 | ||
| 32 | + */ | ||
| 33 | + private String format; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 编码的Profile:视频:Baseline Extended Main,High 音频:"Layer 3" | ||
| 37 | + */ | ||
| 38 | + private String formatProfile; | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 时长 单位是秒: | ||
| 42 | + */ | ||
| 43 | + private String duration; | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 码率模式 VBR 变码率 ,CBR恒定码率 | ||
| 47 | + */ | ||
| 48 | + private String bitRateMode; | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 码率 bps(VBR时是平均码率,CBR是恒定码率) | ||
| 52 | + */ | ||
| 53 | + private String bitRate; | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 码率最小值 bps | ||
| 57 | + */ | ||
| 58 | + private String bitRateMinimum; | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * 码率最大值 bps | ||
| 62 | + */ | ||
| 63 | + private String bitRateMaximum; | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * 帧率 fps | ||
| 67 | + */ | ||
| 68 | + private String frameRate; | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * 帧数 | ||
| 72 | + */ | ||
| 73 | + private String frameCount; | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * 视频图位深或者声音采样精度 | ||
| 77 | + */ | ||
| 78 | + private String bitDepth; | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 流大小 单位是字节 | ||
| 82 | + */ | ||
| 83 | + private String streamSize; | ||
| 84 | + | ||
| 85 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Auther: WANGJING | ||
| 7 | + * @Description: | ||
| 8 | + * @Modifier: | ||
| 9 | + * @Version: | ||
| 10 | + * @TaskId: YJ-348 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +@Data | ||
| 14 | +public class VideoMedia extends SteamMedia { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 视频流的个数 | ||
| 18 | + */ | ||
| 19 | + private String videoCount; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 视频封装Profile | ||
| 23 | + */ | ||
| 24 | + private String formatProfile; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * media原始分析数据 | ||
| 28 | + */ | ||
| 29 | + private String originalInfo; | ||
| 30 | + | ||
| 31 | +} |
| 1 | +package com.wondertek.vo.media; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Auther: WANGJING | ||
| 7 | + * @Description: | ||
| 8 | + * @Modifier: | ||
| 9 | + * @Version: | ||
| 10 | + * @TaskId: YJ-348 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +@Data | ||
| 14 | +public class VideoStream extends Stream { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 编码的Level 3.1, | ||
| 18 | + */ | ||
| 19 | + private String formatLevel; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 视频GOP值 例子"M=2, N=30" | ||
| 23 | + */ | ||
| 24 | + private String formatSettingsGOP; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 帧模式 CFR 恒帧 VFR变帧 | ||
| 28 | + */ | ||
| 29 | + private String frameRateMode; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 视频宽度 单位像素 | ||
| 33 | + */ | ||
| 34 | + private String width; | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 视频高度 单位像素 | ||
| 38 | + */ | ||
| 39 | + private String height; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 视频比例 1.778(16:9);1.33(4:3) | ||
| 43 | + */ | ||
| 44 | + private String displayAspectRatio; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 色彩空间 RGB YUV | ||
| 48 | + */ | ||
| 49 | + private String colorSpace; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * 色度采用 4:2:0 4:4:4等 | ||
| 53 | + */ | ||
| 54 | + private String chromaSubsampling; | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 视频扫描方式:Progressive 逐行扫描;Interlaced 隔行扫描 | ||
| 58 | + */ | ||
| 59 | + private String scanType; | ||
| 60 | + | ||
| 61 | +} |
| @@ -72,6 +72,7 @@ rec: | @@ -72,6 +72,7 @@ rec: | ||
| 72 | file: | 72 | file: |
| 73 | realPath: /home/wondertek/material_file_assets/dianpian/ | 73 | realPath: /home/wondertek/material_file_assets/dianpian/ |
| 74 | previewUrl: https://dev.aivideo.cn/mdi/rehuo-wucai-file-service/preview/crp/ #预览前缀 | 74 | previewUrl: https://dev.aivideo.cn/mdi/rehuo-wucai-file-service/preview/crp/ #预览前缀 |
| 75 | + mediainfoPath: /usr/bin/mediainfo | ||
| 75 | 76 | ||
| 76 | crp: | 77 | crp: |
| 77 | pIp: 180.167.180.242 | 78 | pIp: 180.167.180.242 |
-
Please register or login to post a comment