【HarmonyOS】实现将pcm音频文件进行编码并写入文件(API6 Java)

news/2024/7/21 8:48:52 标签: harmonyos, pcm

 【关键字】

音频编码、管道模式、createEncoder

【写在前面】

在使用API6开发HarmonyOS应用时,如何将pcm源文件进行编码并写入文件,最后生成aac文件,本文直接附上主要代码开发步骤供大家参考。

【主要功能代码】

import ohos.media.codec.Codec;
import ohos.media.common.BufferInfo;
import ohos.media.common.Format;
import ohos.media.common.Source;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class AudioEncoder {

    void creatEncoder(){

    }

    FileOutputStream fileOutputStream = null;

    public void encode(){
        System.out.println("encode start");
        try {
            File fd = new File("/data/data/com.example.myapplication/11.aac");
            fileOutputStream = new FileOutputStream(fd, true);
        } catch (FileNotFoundException e) {
            System.out.println("FileNotFoundException");
        } finally {
        }
        final Codec encoder = Codec.createEncoder();
        String path = "/data/data/com.example.myapplication/11.pcm";
        System.out.println("encoder = " + encoder);
        boolean ret = encoder.setSource(new Source(path), null);
        System.out.println("setSource ret = " + ret);
		
        Format fmt = new Format();
	// format格式中转码率和声道需与pcm相同
        fmt.putStringValue(Format.MIME, Format.AUDIO_AAC);
        fmt.putIntValue(Format.BIT_RATE, 128000);
        fmt.putIntValue(Format.CHANNEL, 2);
        fmt.putIntValue(Format.SAMPLE_RATE, 44100);
        fmt.putIntValue(Format.FRAME_RATE, 30); // 此设置必须,数值一般为30/60,或自行设置需要数值

        boolean b1 = encoder.setSourceFormat(fmt);
        System.out.println("setSourceFormat = " + b1);
        Codec.ICodecListener listener = new Codec.ICodecListener() {
            @Override
            public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {
                System.out.println("byteBuffer = " + byteBuffer + "trackId = " + trackId + "bufferinfo = " + bufferInfo.bufferType);
                if(bufferInfo.bufferType == 4){
                    encoder.stop();
                    encoder.release();
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
			// 打印异常
                        System.out.println("IOException");
                    }
                    return;
                }
                writeFile(byteBuffer,bufferInfo,trackId);

            }
            @Override
            public void onError(int errorCode, int act, int trackId) {
                System.out.println( "PlayerCallback onError errorCode: "+errorCode +", trackId:"+trackId);
            }
        };
        boolean b = encoder.registerCodecListener(listener);
        System.out.println("registerCodecListener = " + b);

        boolean start = encoder.start();
        System.out.println("start = " + start);
    }


    private void writeFile(ByteBuffer outputBuffer, BufferInfo info, int trackId) {
        try {
            final byte[] chunk = new byte[info.size+7];
            addADTSHeader(chunk,info.size+7);
            outputBuffer.get(chunk,7,info.size);
            fileOutputStream.write(chunk);
            outputBuffer.clear();
        } catch (FileNotFoundException e) {
            System.out.println("FileNotFoundException");
        } catch (IOException e) {
            System.out.println("IOException");
        } finally {
		
        }
    }
    /**
     * 添加AAC帧文件头
     *
     * @param packet    packet
     * @param packetLen packetLen
     */
    private void addADTSHeader(byte[] packet, int packetLen) {
        int profile = 2; // AAC
        int freqIdx = 4; // 44.1kHz
        int channelCount = 2;//声道
        packet[0] = (byte) 0xFF;
        packet[1] = (byte) 0xF9;
        packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (channelCount >> 2));
        packet[3] = (byte) (((channelCount & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
        packet[6] = (byte) 0xFC;
    }
}

【说明和注意事项】

1、AAC文件有两种添加头文件方式:ADIF与ADTS,此处使用ADTS方式,ADTS是每一段编码都有一个头部,因此并不能只添加一次,需要在回调中添加头文件;添加头文件保存的aac文件可以直接播放;

2、format中需要设置FRAME_RATE,即fmt.putIntValue(Format.FRAME_RATE, 30);,数值必须大于0,否则可能会编码失败

3、编解码功能建议在子线程中执行,不要在主线程中。

【参考文档】

视频编解码文档:文档中心:视频编码


http://www.niftyadmin.cn/n/4959491.html

相关文章

基于java羽毛球馆管理系统设计与实现

摘 要 时代的变化速度实在超出人类的所料&#xff0c;21世纪&#xff0c;计算机已经发展到各行各业&#xff0c;各个地区&#xff0c;它的载体媒介-计算机&#xff0c;大众称之为的电脑&#xff0c;是一种特高速的科学仪器&#xff0c;比人类的脑袋要灵光无数倍&#xff0c;什么…

关于linux上文件同步操作 inotify-tools

安装 inotify-tools 插件&#xff08;易可源码安装&#xff09; sudo apt-get update sudo apt-get install inotify-tools #或者 sudo yum install inotify-tools编写测试脚本&#xff08;如果脚本执行不成功&#xff0c;可能需要ssh-keygen 证书授权&#xff09; #!/bin/ba…

拯救工厂食堂,这才是真技术流!

智慧食堂是当今数字化时代赋予食堂管理的新领域&#xff0c;通过融合智能技术和数字化手段&#xff0c;为工厂食堂提供了更高效、便捷和精确的收银解决方案。 通过数字化点餐、多样化的支付方式、消费记录追踪、数据分析等功能&#xff0c;智慧收银系统正在重新定义着食堂管理的…

【HCIP】12.BGP基础

AS之间传递路由&#xff08;不产生路由&#xff0c;只传递路由&#xff09;BGP属于应用层&#xff0c;采用TLV价格。AS号&#xff0c;16bit与32bit。运行BGP的路由器成为BGP发言者&#xff0c;或者BGP路由器 概述 采用目的端口179&#xff0c;触发式更新能承载大量路由信息13…

【电商领域】Axure在线购物商城小程序原型图,抖音商城垂直电商APP原型

作品概况 页面数量&#xff1a;共 60 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;网上商城、品牌自营商城、商城模块插件 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为品牌自营网上商城…

双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化的应用

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。国家领导人在多次重要会议上讲到&#xff0c;要把“双碳”纳入经济社会发展和生态文明建设整体布局。同时&#xff0c;提到要把减污降碳协同增效作为促…

HTTP1.0 和 HTTP1.1 的区别

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是互联网上用于传输超文本的协议&#xff0c;它定义了客户端和服务器之间的通信规则。HTTP 协议经历了多个版本的演进&#xff0c;其中 HTTP1.0 和 HTTP1.1 是两个重要的版本。本文将介绍它们之间的区别&#xff0c;以…

【官方中文文档】Mybatis-Spring #使用 MyBatis API

使用 MyBatis API 使用 MyBatis-Spring&#xff0c;你可以继续直接使用 MyBatis 的 API。只需简单地使用 SqlSessionFactoryBean 在 Spring 中创建一个 SqlSessionFactory&#xff0c;然后按你的方式在代码中使用工厂即可。 public class UserDaoImpl implements UserDao {//…