经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
Html5页面播放M4a音频文件
来源:jb51  时间:2021/3/29 8:52:26  对本文有异议

业务场景:

手机app端录音,然后上传至后台服务器,前端从后台服务器获取录音,在PC端WEB页面播放。

实际问题:

首先app录音文件默认是m4a格式,而在PC端WEB H5页面,<audio>标签并没有明确写着支持m4a格式,如果app端生成的录音不做相关设置,而用默认设置,在H5上确实是播放不了的。

其实一开始,我没有想太多,也是想着把m4a文件转成mp3给前台用。

在网上查了一番,很多都说用jave-1.0.2.2.jar,然而其实这个包很旧,而且在windows上是可以转,但centos8上不支m4a格式转码,在系统上有兼容性问题。信我,别用它

然后又在码库里找了比较靠谱的是这个包,这里附个链接: https://github.com/a-schild/jave2,这个包也是基于ffmpeg的,提供了支持win64、osx64、linux64的依赖,建义在maven打包时,根据开发或生产环境的不同,打包时引用相应环境的依赖。

下面附上我的m4a转mp3的java代码:

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com</groupId>
  5. <artifactId>test</artifactId>
  6. <version>1.0.0-SNAPSHOT</version>
  7. <packaging>pom</packaging>
  8. <properties>
  9. <jave.version>2.7.1</jave.version>
  10. </properties>
  11. <dependencyManagement>
  12. <dependencies>
  13. <!--录音转换,jave-all-deps 包涵了所有平台的依赖,由于打包太大,建议打包时选指定的依赖-->
  14. <!--<dependency>-->
  15. <!--<groupId>ws.schild</groupId>-->
  16. <!--<artifactId>jave-all-deps</artifactId>-->
  17. <!--<version>${jave.version}</version>-->
  18. <!--</dependency>-->
  19. <!--录音转换,指定平台依赖,jave-core必需指定-->
  20. <dependency>
  21. <groupId>it.sauronsoftware</groupId>
  22. <artifactId>jave</artifactId>
  23. <groupId>ws.schild</groupId>
  24. <artifactId>jave-core</artifactId>
  25. <version>${jave.version}</version>
  26. </dependency>
  27. </dependencies>
  28. </dependencyManagement>
  29. <!--激活profile配置,用来切换不同环境的配置-->
  30. <profiles>
  31. <profile>
  32. <id>dev</id>
  33. <properties>
  34. <profiles.actives>dev</profiles.actives>
  35. </properties>
  36. <activation>
  37. <activeByDefault>true</activeByDefault>
  38. <activeByDefault>false</activeByDefault>
  39. </activation>
  40. <dependencies>
  41. <dependency>
  42. <groupId>ws.schild</groupId>
  43. <artifactId>jave-nativebin-linux64</artifactId>
  44. <version>${jave.version}</version>
  45. </dependency>
  46. </dependencies>
  47. </profile>
  48. <profile>
  49. <id>pro</id>
  50. <properties>
  51. <profiles.actives>pro</profiles.actives>
  52. </properties>
  53. <activation>
  54. <activeByDefault>false</activeByDefault>
  55. </activation>
  56. <dependencies>
  57. <dependency>
  58. <groupId>ws.schild</groupId>
  59. <artifactId>jave-nativebin-linux64</artifactId>
  60. <version>${jave.version}</version>
  61. </dependency>
  62. </dependencies>
  63. </profile>
  64. <profile>
  65. <id>test</id>
  66. <properties>
  67. <profiles.actives>test</profiles.actives>
  68. </properties>
  69. <activation>
  70. <activeByDefault>true</activeByDefault>
  71. </activation>
  72. <dependencies>
  73. <dependency>
  74. <groupId>ws.schild</groupId>
  75. <artifactId>jave-nativebin-win64</artifactId>
  76. <version>${jave.version}</version>
  77. </dependency>
  78. </dependencies>
  79. </profile>
  80. </profiles>
  81. </project>

录音文件转换代码:

  1. package com.utils;
  2. import com.alibaba.fastjson.JSON;
  3. import com.qirui.framework.common.base.syslog.SysLog;
  4. import com.qirui.framework.common.base.syslog.SysLogAnnotation;
  5. import com.qirui.framework.common.base.syslog.SysLogPrint;
  6. import com.qirui.framework.common.utils.RequestUtil;
  7. import org.springframework.stereotype.Component;
  8. import ws.schild.jave.*;
  9. import java.io.BufferedOutputStream;
  10. import java.io.File;
  11. import java.io.FileOutputStream;
  12. import java.io.IOException;
  13. /**
  14. * @ClassName AudioTransUtil
  15. * @Description 录音转换
  16. * @Author admin
  17. * @Version 1.0.0
  18. **/
  19. @Component
  20. public class AudioTransUtil {
  21. static {
  22. // 项目是springboot jar包, jar包内的代码要读取外面文件夹的文件,需要处理一下读取路径,
  23. // 这里是把录音源文件和转换文件放在springboot jar包的同级文件夹下
  24. String path = AudioTransUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath();
  25. if(path.contains("jar")){
  26. //file:/F:/ideaWorkspace/test/smp-admin/framework-client/target/framework-client-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/framework-service-0.0.1-SNAPSHOT.jar!/
  27. //去掉 "file:"
  28. path = path.substring(path.indexOf("/"), path.length());
  29. }
  30. if(System.getProperty("os.name").contains("dows")) {
  31. path = path.substring(1, path.length());
  32. //widonws的jar包
  33. if(path.contains("jar")){
  34. path = path.substring(0, path.indexOf(".jar"));
  35. rootPath = path.substring(0, path.lastIndexOf("/"));
  36. }else{
  37. rootPath = path.replace("/target/classes/", "");
  38. }
  39. }else if(System.getProperty("os.name").contains("Mac")){
  40. rootPath = path.replace("/target/classes/", "");
  41. }
  42. else {
  43. path = path.substring(0, path.indexOf(".jar"));
  44. rootPath = path.substring(0, path.lastIndexOf("/"));
  45. }
  46. }
  47. protected static final String rootPath;
  48. /**
  49. *目录路径
  50. */
  51. private static final StringBuilder dirPathStr = new StringBuilder(rootPath).append("/temp/audio/");
  52. private static final String MP3 = "mp3";
  53. @SysLogAnnotation(descript = "录音转换格式")
  54. public String trans2Mp3(byte[] sourceAudioBytes, String sourceAudioName){
  55. //文件路径
  56. String soureAudioFilePathStr = new StringBuilder(dirPathStr).append(sourceAudioName).toString();
  57. String sourceAudioType = sourceAudioName.substring(sourceAudioName.indexOf(".")+1);
  58. String targetAudioFilePathStr = new StringBuilder(soureAudioFilePathStr).toString().replace(sourceAudioType, MP3);
  59. BufferedOutputStream bos = null;
  60. FileOutputStream fos = null;
  61. try{
  62. File dir = new File(dirPathStr.toString());
  63. if(!dir.exists()){
  64. dir.mkdirs();
  65. }
  66. File sourceAudioFile = new File(soureAudioFilePathStr);
  67. fos = new FileOutputStream(sourceAudioFile);
  68. bos = new BufferedOutputStream(fos);
  69. bos.write(sourceAudioBytes);
  70. File targetAudioFile = new File(targetAudioFilePathStr);
  71. AudioAttributes audioAttributes = new AudioAttributes();
  72. audioAttributes.setCodec("libmp3lame");
  73. audioAttributes.setBitRate(new Integer(32000));
  74. // audioAttributes.setChannels(new Integer(2));
  75. // audioAttributes.setSamplingRate(new Integer(22050));
  76. EncodingAttributes attrs = new EncodingAttributes();
  77. attrs.setFormat("mp3");
  78. attrs.setAudioAttributes(audioAttributes);
  79. Encoder encoder = new Encoder();
  80. //在有需要时添加,可根据不同系统环境,查看支持处理的文件格式
  81. System.out.println("encoder.getVideoDecoders():" + JSON.toJSON(encoder.getVideoDecoders()).toString());
  82. System.out.println("encoder.getSupportedDecodingFormats():" + JSON.toJSON(encoder.getSupportedDecodingFormats()).toString());
  83. MyJaveListener myJaveListener = new MyJaveListener();
  84. encoder.encode(new MultimediaObject(sourceAudioFile), targetAudioFile, attrs, myJaveListener);
  85. }catch (Exception e){
  86. e.printStackTrace();
  87. }finally {
  88. try {
  89. if(null != bos){
  90. bos.close();
  91. }
  92. if(null != fos){
  93. fos.close();
  94. }
  95. } catch (IOException e) {
  96. e.printStackTrace();
  97. }
  98. }
  99. SysLog sysLog = new SysLog();
  100. sysLog.setLogId(RequestUtil.getAccessLogId());
  101. sysLog.setParams(targetAudioFilePathStr);
  102. sysLog.setDescript("录音转换路径");
  103. SysLogPrint.printSysLogBody(sysLog);
  104. return targetAudioFilePathStr;
  105. }
  106. // 删除本地临时录音
  107. public void deleteTempAudio(String fileName){
  108. //文件路径
  109. String fileNameTemp = fileName.substring(fileName.lastIndexOf("/")+1, fileName.length());
  110. String soureAudioFilePathStr = new StringBuilder(dirPathStr).append(fileNameTemp).toString();
  111. String sourceAudioType = fileName.substring(fileName.indexOf(".")+1);
  112. String targetAudioFilePathStr = new StringBuilder(soureAudioFilePathStr).toString().replace(sourceAudioType, MP3);
  113. File file = new File(soureAudioFilePathStr);
  114. file.delete();
  115. file = new File(targetAudioFilePathStr);
  116. file.delete();
  117. }
  118. /**
  119. * 录音转码处理监听器,可监听文件处理结果,对于错误信息很有用
  120. */
  121. private class MyJaveListener implements EncoderProgressListener {
  122. @Override
  123. public void sourceInfo(MultimediaInfo multimediaInfo) {
  124. System.out.println("MyListener.sourceInfo:" + JSON.toJSON(multimediaInfo).toString());
  125. }
  126. @Override
  127. public void progress(int i) {
  128. System.out.println("MyListener.progress:" + i);
  129. }
  130. @Override
  131. public void message(String s) {
  132. System.out.println("MyListener.message:" + s);
  133. }
  134. }
  135. }

上面的代码,在centos8环境是可以正常转换的,开一始,我的生产环境也用了这份。

后来,我去找了m4a和mp3、mp4的区别,发现 mp4是使用了MPEG-4进行封装的AAC编码,而M4A的本质和音频MP4相同,它是区别纯音频MP4文件和包含视频的MP4文件而由苹果(Apple)公司使用的扩展名。

那么疑问来了,竟然m4a和mp4的本质相同,那么竟然浏览器H5可以播放mp4,为什么m4a不行,原因在音频的编码上,AAC编码是解决问题的关键。

下面附上安卓内部输出录音代码中的几个关键截图:

默认如果不设置,AudioEncoder是0,0并不是AAC编码,我们需要在输出格式上设置MPEG_4,并把编码格式设置成AAC,

如第三图中所示:

  1. setOutPutFormat(MediaRecorder.OutputFormat.MPEG_4)
  2.  
  3. setAudioEncoder(MediaRecorder.AudioEncoder.AAC)

这样,生成的m4a录音文件,就可以直接在浏览器H5页面中播放了,完全不需要后台,在整个程序个不仅少了代码的转码时间,本身m4a文件也很小。

到此这篇关于Html5页面播放M4a音频文件的文章就介绍到这了,更多相关Html5播放M4a 内容请搜索w3xue以前的文章或继续浏览下面的相关文章,希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号