Advertisement
Watrik

Untitled

Jun 8th, 2023
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.81 KB | None | 0 0
  1. package ru.bump.util.mediainfo;
  2.  
  3. import com.mpatric.mp3agic.*;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import ru.bump.core.util.ArgumentAssertUtil;
  7. import ru.bump.util.process.ProcessRunException;
  8. import ru.bump.util.process.ProcessRunner;
  9. import ru.bump.util.string.StringUtil;
  10.  
  11. import java.io.IOException;
  12. import java.io.UnsupportedEncodingException;
  13. import java.util.Arrays;
  14. import java.util.Collections;
  15. import java.util.HashMap;
  16. import java.util.List;
  17. import java.util.concurrent.TimeoutException;
  18.  
  19.  
  20. public final class MediaInfoUtil {
  21.  
  22. private static final String UTILITY_NAME = "mediainfo";
  23. private static final String TEMPLATE = "--Inform={0};";
  24.  
  25. private static final String TEMPLATE_GENERAL = StringUtil.getFormatedString(TEMPLATE, "General");
  26. private static final String TEMPLATE_VIDEO = StringUtil.getFormatedString(TEMPLATE, "Video");
  27. private static final String TEMPLATE_AUDIO = StringUtil.getFormatedString(TEMPLATE, "Audio");
  28. private static final String TEMPLATE_IMAGE = StringUtil.getFormatedString(TEMPLATE, "Image");
  29.  
  30. private static final String FORMAT = "%Format%";
  31. private static final String FORMAT_PROFILE = "%Format_Profile%";
  32. private static final String FORMAT_PARAMETER = TEMPLATE_GENERAL.concat(FORMAT);
  33. private static final String FORMAT_PROFILE_PARAMETER = TEMPLATE_GENERAL.concat(FORMAT_PROFILE);
  34. private static final String DURATION_PARAMETER = TEMPLATE_GENERAL.concat("%Duration%");
  35. private static final String ARTIST_PARAMETER = TEMPLATE_GENERAL.concat("%Performer%");
  36. private static final String TRACK_NAME_PARAMETER = TEMPLATE_GENERAL.concat("%Track%");
  37. private static final String FRAME_RATE_PARAMETER = TEMPLATE_VIDEO.concat("%FrameRate%");
  38. private static final String HEIGHT_PARAMETER = TEMPLATE_VIDEO.concat("%Height%");
  39. private static final String WIDTH_PARAMETER = TEMPLATE_VIDEO.concat("%Width%");
  40.  
  41. private static final String VIDEO_FORMAT_PARAMETER = TEMPLATE_VIDEO.concat(FORMAT);
  42. private static final String VIDEO_BIT_RATE_PARAMETER = TEMPLATE_VIDEO.concat("%BitRate%");
  43. private static final String VIDEO_CODEC_ID_PARAMETER = TEMPLATE_VIDEO.concat("%CodecID%");
  44.  
  45. private static final String AUDIO_CHANNELS_PARAMETER = TEMPLATE_AUDIO.concat("%Channel(s)%");
  46. private static final String AUDIO_CODEC_ID_PARAMETER = TEMPLATE_AUDIO.concat("%CodecID%");
  47.  
  48. private static final String IMAGE_HEIGHT_PARAMETER = TEMPLATE_IMAGE.concat("%Height%");
  49. private static final String IMAGE_WIDTH_PARAMETER = TEMPLATE_IMAGE.concat("%Width%");
  50.  
  51. private static final Logger LOG = LoggerFactory.getLogger(MediaInfoUtil.class);
  52.  
  53. private static final byte TEXT_ENCODING_WINDOWS_1251 = 0;
  54. private static final byte TEXT_ENCODING_UTF_16 = 1;
  55. private static final byte TEXT_ENCODING_UTF_16BE = 2;
  56. private static final byte TEXT_ENCODING_UTF_8 = 3;
  57. private static final String[] ENCODING_CHARSETS = {"windows-1251", "UTF-16LE", "UTF-16BE", "UTF-8"};
  58.  
  59. // -------------------------------------------------------
  60. // - LOGIC -
  61. // -------------------------------------------------------
  62.  
  63. private MediaInfoUtil() {
  64. }
  65.  
  66. private static List<String> getMediaInfo(String parameter, String filePath) {
  67. try {
  68. return new ProcessRunner(UTILITY_NAME)
  69. .addParameter(parameter)
  70. .addParameter(filePath)
  71. .run();
  72. } catch (IOException e) {
  73. LOG.error("Error get media info. I/O problem. Parameter = `{}`, filePath = `{}`.", e, parameter, filePath);
  74. } catch (InterruptedException e) {
  75. LOG.error("Error get media info. Process is interrupted. Parameter = `{}`, filePath = `{}`.", e,
  76. parameter, filePath);
  77. } catch (ProcessRunException e) {
  78. LOG.error("Error get media info. Parameter = `{}`, filePath = `{}`.", e, parameter, filePath);
  79. } catch (TimeoutException e) {
  80. LOG.error("Error get media info. Timeout is expired. Parameter = `{}`, filePath = `{}`.", e,
  81. parameter, filePath);
  82. }
  83.  
  84. return Collections.EMPTY_LIST;
  85. }
  86.  
  87. private static String getMediaInfoOneLine(String parameter, String filePath) {
  88. List<String> outputLines = getMediaInfo(parameter, filePath);
  89. if (outputLines.size() > 0) {
  90. String line = outputLines.get(0);
  91. LOG.info("MediaInfoOneLine: `{}`, parameter: `{}`, filePath : `{}`", line, parameter, filePath);
  92. return line;
  93. } else {
  94. LOG.warn("MediaInfoOneLine is empty");
  95. }
  96.  
  97. return "";
  98. }
  99.  
  100. public static MediaInfoFormat getMediaInfoFormat(String filePath) {
  101. List<String> allMediaInfo = getMediaInfo("", filePath);
  102. HashMap<String, HashMap<String, String>> sections = new HashMap<String, HashMap<String, String>>();
  103.  
  104. String currentSection = "";
  105. HashMap<String, String> currentSectionElements = new HashMap<String, String>();
  106.  
  107. for (String mediaInfo : allMediaInfo) {
  108. if (mediaInfo.equals("General") || mediaInfo.equals("Video")
  109. || mediaInfo.equals("Audio") || mediaInfo.equals("Text")
  110. || mediaInfo.equals("Chapter") || mediaInfo.equals("Image")
  111. || mediaInfo.equals("Menu")) {
  112.  
  113. currentSection = mediaInfo;
  114. continue;
  115. }
  116.  
  117. if (mediaInfo.equals("")) {
  118. if (!currentSectionElements.isEmpty()) {
  119. sections.put(currentSection, currentSectionElements);
  120. currentSectionElements = new HashMap<String, String>();
  121. }
  122.  
  123. continue;
  124. }
  125.  
  126. mediaInfo = mediaInfo.trim().replaceAll(" +", " ");
  127. String[] splittedMediaInfo = mediaInfo.split(":", 2);
  128.  
  129. if (splittedMediaInfo.length < 2) {
  130. continue;
  131. }
  132.  
  133. currentSectionElements.put(splittedMediaInfo[0].trim(), splittedMediaInfo[1].trim());
  134. }
  135.  
  136. HashMap<String, String> generalSection = sections.get("General");
  137.  
  138. if (generalSection == null) {
  139. throw new RuntimeException("Can't find general section");
  140. }
  141.  
  142. String generalFormat = generalSection.get("Format");
  143. String generalFormatProfile = generalSection.get("Format profile");
  144.  
  145. if (generalFormat == null) {
  146. generalFormat = "";
  147. }
  148.  
  149. if (generalFormatProfile == null) {
  150. generalFormatProfile = "";
  151. }
  152.  
  153. MediaInfoFormat mediaInfoFormat = MediaInfoFormat.getFormat(generalFormat, generalFormatProfile);
  154.  
  155. //this fix for WMV format, if video stream excepted
  156. if (mediaInfoFormat.equals(MediaInfoFormat.WINDOWS_MEDIA)) {
  157.  
  158. HashMap<String, String> videoSection = sections.get("Video");
  159. String videoFormat = "";
  160.  
  161. if (videoSection != null) {
  162. if (videoSection.get("Format") != null) {
  163. videoFormat = videoSection.get("Format");
  164. }
  165. }
  166.  
  167. if ("".equalsIgnoreCase(videoFormat.trim())) {
  168. return MediaInfoFormat.WINDOWS_MEDIA_AUDIO;
  169. }
  170. }
  171. return mediaInfoFormat;
  172. }
  173.  
  174. public static long getMediaInfoDuration(String filePath) {
  175. return Long.valueOf(getMediaInfoOneLine(DURATION_PARAMETER, filePath));
  176. }
  177.  
  178. public static String getMediaInfoArtist(String filePath) {
  179. return getMediaInfoOneLine(ARTIST_PARAMETER, filePath);
  180. }
  181.  
  182. public static String getMediaInfoTrackName(String filePath) {
  183. return getMediaInfoOneLine(TRACK_NAME_PARAMETER, filePath);
  184. }
  185.  
  186. public static String getFrameRate(String filePath) {
  187. return getMediaInfoOneLine(FRAME_RATE_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  188. }
  189.  
  190. public static String getVideoHeight(String filePath) {
  191. return getMediaInfoOneLine(HEIGHT_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  192. }
  193.  
  194. public static String getImageHeight(String filePath) {
  195. return getMediaInfoOneLine(IMAGE_HEIGHT_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  196. }
  197.  
  198. public static String getImageWidth(String filePath) {
  199. return getMediaInfoOneLine(IMAGE_WIDTH_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  200. }
  201.  
  202. public static String getVideoWidth(String filePath) {
  203. return getMediaInfoOneLine(WIDTH_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  204. }
  205.  
  206. public static String getImageFormat(String filePath) {
  207. return getMediaInfoOneLine(FORMAT_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  208. }
  209.  
  210. public static String getAudioChannels(String filePath) {
  211. return getMediaInfoOneLine(AUDIO_CHANNELS_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  212. }
  213.  
  214. public static String getVideoBitRate(String filePath) {
  215. return getMediaInfoOneLine(VIDEO_BIT_RATE_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  216. }
  217.  
  218. public static String getVideoCodecId(String filePath) {
  219. return getMediaInfoOneLine(VIDEO_CODEC_ID_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  220. }
  221.  
  222. public static String getAudioCodecId(String filePath) {
  223. return getMediaInfoOneLine(AUDIO_CODEC_ID_PARAMETER, filePath).replaceAll("\n", "").replaceAll("\r", "");
  224. }
  225.  
  226. public static boolean isImage(MediaInfoFormat mediaInfoFormat) {
  227. ArgumentAssertUtil.nullCheck("mediaInfoFormat", mediaInfoFormat);
  228.  
  229. switch (mediaInfoFormat) {
  230. case BITMAP:
  231. case DIB:
  232. case GIF:
  233. case ICO:
  234. case JNG:
  235. case JPEG:
  236. case JPEG2000:
  237. case LZ77:
  238. case MNG:
  239. case RIFF:
  240. case PNG:
  241. case RLE:
  242. case TIFF:
  243. return true;
  244.  
  245. default:
  246. return false;
  247. }
  248. }
  249.  
  250. public static String getArtist(String filePath) {
  251. String artist = getId3tag(filePath, "TPE1");
  252. if (artist == null) {
  253. return getMediaInfoArtist(filePath);
  254. } else {
  255. return artist;
  256. }
  257. }
  258.  
  259. public static String getTrackName(String filePath) {
  260. String trackName = getId3tag(filePath, "TIT2");
  261. if (trackName == null) {
  262. return getMediaInfoTrackName(filePath);
  263. } else {
  264. return trackName;
  265. }
  266. }
  267.  
  268. public static String getId3tag (String filePath, String tagName) {
  269. String tagValue = null;
  270. try {
  271. Mp3File mp3file = new Mp3File(filePath);
  272. if (mp3file.hasId3v2Tag()) {
  273. ID3v2 id3v2Tag = mp3file.getId3v2Tag();
  274. byte[] data = id3v2Tag.getFrameSets().get(tagName).getFrames().get(0).getData();
  275. tagValue = getStringFromTagData(Arrays.copyOfRange(data, 1, data.length), data[0]);
  276. }
  277. } catch (Exception e) {
  278. LOG.warn("Error reading mp3 tags, trying other methods, {}, file: {}", e, filePath);
  279. }
  280. return tagValue;
  281. }
  282.  
  283. private static String getStringFromTagData(byte[] value, byte textEncoding) throws UnsupportedEncodingException {
  284. byte[][] terminators = {
  285. {0},
  286. {0, 0},
  287. {0, 0},
  288. {0}
  289. };
  290. int leadingCharsToRemove = 0;
  291.  
  292. // if encoding type 1 and big endian BOM is present, switch to big endian
  293. if ((textEncoding == TEXT_ENCODING_UTF_16) &&
  294. (textEncodingForBytesFromBOM(value) == TEXT_ENCODING_UTF_16BE)) {
  295. textEncoding = TEXT_ENCODING_UTF_16BE;
  296. }
  297.  
  298. if (value.length >= 2 && ((value[0] == (byte) 0xfe && value[1] == (byte) 0xff) || (value[0] == (byte) 0xff && value[1] == (byte) 0xfe))) {
  299. leadingCharsToRemove = 2;
  300. } else if (value.length >= 3 && (value[0] == (byte) 0xef && value[1] == (byte) 0xbb && value[2] == (byte) 0xbf)) {
  301. leadingCharsToRemove = 3;
  302. }
  303. int trailingCharsToRemove = 0;
  304. byte[] terminator = terminators[textEncoding];
  305. if (value.length - leadingCharsToRemove >= terminator.length) {
  306. boolean haveTerminator = true;
  307. for (int i = 0; i < terminator.length; i++) {
  308. if (value[value.length - terminator.length + i] != terminator[i]) {
  309. haveTerminator = false;
  310. break;
  311. }
  312. }
  313. if (haveTerminator) {
  314. trailingCharsToRemove = terminator.length;
  315. }
  316. }
  317. if (leadingCharsToRemove + trailingCharsToRemove > 0) {
  318. int newLength = value.length - leadingCharsToRemove - trailingCharsToRemove;
  319. byte[] newValue = new byte[newLength];
  320. if (newLength > 0) {
  321. System.arraycopy(value, leadingCharsToRemove, newValue, 0, newValue.length);
  322. }
  323. value = newValue;
  324. }
  325.  
  326. return new String(value, ENCODING_CHARSETS[textEncoding]);
  327. }
  328.  
  329. private static byte textEncodingForBytesFromBOM(byte[] value) {
  330. if (value.length >= 2 && value[0] == (byte) 0xff && value[1] == (byte) 0xfe) {
  331. return TEXT_ENCODING_UTF_16;
  332. } else if (value.length >= 2 && value[0] == (byte) 0xfe && value[1] == (byte) 0xff) {
  333. return TEXT_ENCODING_UTF_16BE;
  334. } else if (value.length >= 3 && (value[0] == (byte) 0xef && value[1] == (byte) 0xbb && value[2] == (byte) 0xbf)) {
  335. return TEXT_ENCODING_UTF_8;
  336. } else {
  337. return TEXT_ENCODING_WINDOWS_1251;
  338. }
  339. }
  340. }
  341.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement