Html5页面播放M4a音频文件


Posted in HTML / CSS onMarch 30, 2021

业务场景:

手机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

<?xml version="1.0" encoding="UTF-8"?>
<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">
	<modelVersion>4.0.0</modelVersion>
	
	<groupId>com</groupId>
	<artifactId>test</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
 
    <properties>       
        <jave.version>2.7.1</jave.version>
    </properties>
 
	<dependencyManagement>
		<dependencies>           
            <!--录音转换,jave-all-deps 包涵了所有平台的依赖,由于打包太大,建议打包时选指定的依赖-->
            <!--<dependency>-->
                <!--<groupId>ws.schild</groupId>-->
                <!--<artifactId>jave-all-deps</artifactId>-->
                <!--<version>${jave.version}</version>-->
            <!--</dependency>-->
            <!--录音转换,指定平台依赖,jave-core必需指定-->
            <dependency>
                <groupId>it.sauronsoftware</groupId>
                <artifactId>jave</artifactId>
                <groupId>ws.schild</groupId>
                <artifactId>jave-core</artifactId>
                <version>${jave.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
   
    <!--激活profile配置,用来切换不同环境的配置-->
    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <profiles.actives>dev</profiles.actives>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
                <activeByDefault>false</activeByDefault>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-linux64</artifactId>
                    <version>${jave.version}</version>
                </dependency>
            </dependencies>
        </profile>
 
        <profile>
            <id>pro</id>
            <properties>
                <profiles.actives>pro</profiles.actives>
            </properties>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-linux64</artifactId>
                    <version>${jave.version}</version>
                </dependency>
            </dependencies>
        </profile>
 
        <profile>
            <id>test</id>
            <properties>
                <profiles.actives>test</profiles.actives>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-win64</artifactId>
                    <version>${jave.version}</version>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
 
</project>

录音文件转换代码:

package com.utils;
 
import com.alibaba.fastjson.JSON;
import com.qirui.framework.common.base.syslog.SysLog;
import com.qirui.framework.common.base.syslog.SysLogAnnotation;
import com.qirui.framework.common.base.syslog.SysLogPrint;
import com.qirui.framework.common.utils.RequestUtil;
import org.springframework.stereotype.Component;
import ws.schild.jave.*;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
 
/**
 * @ClassName AudioTransUtil
 * @Description 录音转换
 * @Author admin
 * @Version 1.0.0
 **/
@Component
public class AudioTransUtil {
    static {
    // 项目是springboot jar包, jar包内的代码要读取外面文件夹的文件,需要处理一下读取路径,
    // 这里是把录音源文件和转换文件放在springboot jar包的同级文件夹下
        String path = AudioTransUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath();
 
        if(path.contains("jar")){
            //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!/
            //去掉 "file:"
            path = path.substring(path.indexOf("/"), path.length());
        }
        if(System.getProperty("os.name").contains("dows")) {
            path = path.substring(1, path.length());
            //widonws的jar包
            if(path.contains("jar")){
                path = path.substring(0, path.indexOf(".jar"));
                rootPath = path.substring(0, path.lastIndexOf("/"));
            }else{
                rootPath =  path.replace("/target/classes/", "");
            }
        }else if(System.getProperty("os.name").contains("Mac")){
            rootPath = path.replace("/target/classes/", "");
        }
        else {
            path = path.substring(0, path.indexOf(".jar"));
            rootPath = path.substring(0, path.lastIndexOf("/"));
        }
    }
 
 
    protected static final String rootPath;
    /**
     *目录路径
     */
    private static final StringBuilder dirPathStr = new StringBuilder(rootPath).append("/temp/audio/");
    private static final String MP3 = "mp3";
 
    @SysLogAnnotation(descript = "录音转换格式")
    public String trans2Mp3(byte[] sourceAudioBytes, String sourceAudioName){
        //文件路径
        String soureAudioFilePathStr = new StringBuilder(dirPathStr).append(sourceAudioName).toString();
        String sourceAudioType = sourceAudioName.substring(sourceAudioName.indexOf(".")+1);
        String targetAudioFilePathStr = new StringBuilder(soureAudioFilePathStr).toString().replace(sourceAudioType, MP3);
 
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        try{
            File dir = new File(dirPathStr.toString());
            if(!dir.exists()){
                dir.mkdirs();
            }
 
            File sourceAudioFile = new File(soureAudioFilePathStr);
            fos = new FileOutputStream(sourceAudioFile);
            bos = new BufferedOutputStream(fos);
            bos.write(sourceAudioBytes);
 
            File targetAudioFile = new File(targetAudioFilePathStr);
 
            AudioAttributes audioAttributes = new AudioAttributes();
            audioAttributes.setCodec("libmp3lame");
            audioAttributes.setBitRate(new Integer(32000));
//            audioAttributes.setChannels(new Integer(2));
//            audioAttributes.setSamplingRate(new Integer(22050));
 
            EncodingAttributes attrs = new EncodingAttributes();
            attrs.setFormat("mp3");
            attrs.setAudioAttributes(audioAttributes);
 
            Encoder encoder = new Encoder();
 
            //在有需要时添加,可根据不同系统环境,查看支持处理的文件格式
            System.out.println("encoder.getVideoDecoders():" + JSON.toJSON(encoder.getVideoDecoders()).toString());
            System.out.println("encoder.getSupportedDecodingFormats():" + JSON.toJSON(encoder.getSupportedDecodingFormats()).toString());
 
            MyJaveListener myJaveListener = new MyJaveListener();
 
            encoder.encode(new MultimediaObject(sourceAudioFile), targetAudioFile, attrs, myJaveListener);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(null != bos){
                    bos.close();
                }
                if(null != fos){
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
 
        SysLog sysLog = new SysLog();
        sysLog.setLogId(RequestUtil.getAccessLogId());
        sysLog.setParams(targetAudioFilePathStr);
        sysLog.setDescript("录音转换路径");
        SysLogPrint.printSysLogBody(sysLog);
 
        return targetAudioFilePathStr;
    }
 
    // 删除本地临时录音
    public void deleteTempAudio(String fileName){
        //文件路径
        String fileNameTemp = fileName.substring(fileName.lastIndexOf("/")+1, fileName.length());
        String soureAudioFilePathStr = new StringBuilder(dirPathStr).append(fileNameTemp).toString();
        String sourceAudioType = fileName.substring(fileName.indexOf(".")+1);
        String targetAudioFilePathStr = new StringBuilder(soureAudioFilePathStr).toString().replace(sourceAudioType, MP3);
 
        File file = new File(soureAudioFilePathStr);
        file.delete();
        file = new File(targetAudioFilePathStr);
        file.delete();
    }
 
    /**
     * 录音转码处理监听器,可监听文件处理结果,对于错误信息很有用
     */
    private class MyJaveListener implements EncoderProgressListener {
        @Override
        public void sourceInfo(MultimediaInfo multimediaInfo) {
            System.out.println("MyListener.sourceInfo:" + JSON.toJSON(multimediaInfo).toString());
        }
 
        @Override
        public void progress(int i) {
            System.out.println("MyListener.progress:" + i);
        }
 
        @Override
        public void message(String s) {
            System.out.println("MyListener.message:" + s);
        }
    }
}

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

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

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

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

Html5页面播放M4a音频文件

Html5页面播放M4a音频文件

Html5页面播放M4a音频文件

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

如第三图中所示:

setOutPutFormat(MediaRecorder.OutputFormat.MPEG_4)

setAudioEncoder(MediaRecorder.AudioEncoder.AAC)

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

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

 
HTML / CSS 相关文章推荐
五款漂亮的纯CSS3动画按钮的实例教程
Nov 21 HTML / CSS
浅析rem和em和px vh vw和% 移动端长度单位
Apr 28 HTML / CSS
Html5中的桌面通知Notification的实现
Sep 25 HTML / CSS
HTML5边玩边学(2)基础绘图实现方法
Sep 21 HTML / CSS
HTML5中判断用户是否正在浏览页面的方法
May 03 HTML / CSS
HTML5到底会有什么发展?HTML5的前景展望
Jul 07 HTML / CSS
HTML5 canvas实现移动端上传头像拖拽裁剪效果
Mar 14 HTML / CSS
HTML5页面中尝试调起APP功能
Sep 12 HTML / CSS
HTML5添加禁止缩放功能
Nov 03 HTML / CSS
Html5页面上如何禁止手机虚拟键盘弹出
Mar 19 HTML / CSS
HTML5输入框下拉菜单功能的示例代码
Sep 08 HTML / CSS
Unicode中的CJK(中日韩统一表意文字)字符小结
Dec 06 HTML / CSS
Html分层的box-shadow效果的示例代码
原生CSS实现文字无限轮播的通用方法
CSS3 菱形拼图实现只旋转div 背景图片不旋转功能
CSS3通过var()和calc()函数实现动画特效
CSS3实现模糊背景的三种效果示例
使用css样式设计一个简单的html登陆界面的实现
CSS实现漂亮的时钟动画效果的实例代码
You might like
php 表单数据的获取代码
2009/03/10 PHP
php实现encode64编码类实例
2015/03/24 PHP
Yii中CGridView禁止列排序的设置方法
2016/07/12 PHP
PHP将URL转换成短网址的算法分享
2016/09/13 PHP
PHP排序算法之简单选择排序(Simple Selection Sort)实例分析
2018/04/20 PHP
PHP连接MySQL数据库操作代码实例解析
2020/07/11 PHP
javascript各种复制代码收集
2008/09/20 Javascript
IE Firefox 使用自定义标签的区别
2009/10/15 Javascript
使用js声明数组,对象在jsp页面中(获得ajax得到json数据)
2013/11/05 Javascript
Javascript selection的兼容性写法介绍
2013/12/20 Javascript
jQuery select表单提交省市区城市三级联动核心代码
2014/06/09 Javascript
Jquery实现弹性滑块滑动选择数值插件
2015/08/08 Javascript
javascript性能优化之事件委托实例详解
2015/12/12 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
2016/10/14 Javascript
node.js部署之启动后台运行forever的方法
2018/05/23 Javascript
vue百度地图 + 定位的详解
2019/05/13 Javascript
微信小程序云开发使用方法新手初体验
2019/05/16 Javascript
JavaScript计算正方形面积
2019/11/26 Javascript
echarts实现折线图的拖拽效果
2019/12/19 Javascript
vant中的toast轻提示实现代码
2020/11/04 Javascript
jQuery实现tab栏切换效果
2020/12/22 jQuery
[01:21]DOTA2 新英雄 森海飞霞
2020/12/18 DOTA
Python输出PowerPoint(ppt)文件中全部文字信息的方法
2015/04/28 Python
Python简单调用MySQL存储过程并获得返回值的方法
2015/07/20 Python
Python爬虫获取整个站点中的所有外部链接代码示例
2017/12/26 Python
python禁用键鼠与提权代码实例
2019/08/16 Python
python通过SSH登陆linux并操作的实现
2019/10/10 Python
python如何操作mysql
2020/08/17 Python
python自动提取文本中的时间(包含中文日期)
2020/08/31 Python
美国高端医师级美容产品电商:BeautifiedYou.com
2017/04/17 全球购物
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
教师爱岗敬业演讲稿
2014/05/05 职场文书
党的群众路线教育实践活动对照检查材料范文
2014/09/24 职场文书
学生抄作业检讨书(2篇)
2014/10/17 职场文书
z-index不起作用
2021/03/31 HTML / CSS
MySQL的表级锁,行级锁,排它锁和共享锁
2022/07/15 MySQL