Android 音频编码,含adts头

import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.SystemClock;
import android.util.Log;


import androidx.annotation.NonNull;


import com.r3ci.hdmiplayer.mediarender.AudioPlayer;
import com.r3ci.hdmiplayer.utils.DateUtils;
import com.r3ci.recordlib.VideoFactory;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


public class AACEncode2 {
    private final String TAG = AACEncode2.class.getSimpleName();
    private CodecThread mCodecThread = null;
    protected boolean mStreaming = false;
    private MediaCodec mMediaCodec = null;
    private int mChannelCount = 2;
    private int mBitsPerSample = 16;
    private int mBitrate = 64000;
    private int mSamperrate = 48000;


    private BlockingQueue<RawData> mQueue = new ArrayBlockingQueue(100);
    private Context mContext = null;
    private VideoFactory mFileMuxer = null;
    public AACEncode2(Context context, VideoFactory mMuxer, int bitrate, int samplerrate, int channel) {
        mContext = context;
        mFileMuxer = mMuxer;
        mBitrate = bitrate;
        mSamperrate = samplerrate;
        mChannelCount = channel;
        //createTestFile();
    }


    class CodecThread extends Thread {
        CodecThread(@NonNull String name) {
            super(name);
        }


        @Override
        public void run() {
            super.run();
            while (mStreaming) {
                try {
                    readOutputData();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private void readOutputData() throws IOException {


        RawData au = mQueue.poll();
        if(au == null)
            return;
        int index = mMediaCodec.dequeueInputBuffer(-1);


        if (index >= 0) {


            final ByteBuffer buffer = mMediaCodec.getInputBuffer(index);
            buffer.clear();
            buffer.put(au.buf);
            if (au.length > 0) {
                mMediaCodec.queueInputBuffer(index, 0, au.length, au.timeStamp, 0);
            }
        }
//queueInputBuffer一次,dequeueOutputBuffer可能需要几次
        MediaCodec.BufferInfo mInfo = new MediaCodec.BufferInfo();
        int outIndex;
        do {
            outIndex = mMediaCodec.dequeueOutputBuffer(mInfo, 100);


            if (outIndex >= 0) {
                ByteBuffer buffer = mMediaCodec.getOutputBuffer(outIndex);
                if (mInfo.size != 0) {
                    if (buffer == null) {
                        throw new RuntimeException("encodecOutputBuffer" + outIndex + "was null");
                    }
                    if(mFileMuxer != null) {
                        int totalLen = mInfo.size+7;
                        byte[] outStream = new byte[totalLen];
                        addADTStoPacket(outStream, totalLen, 2);
                        buffer.get(outStream, 7, mInfo.size);
                        //saveTestFile(outStream);
                        mFileMuxer.writeData(1, outStream, totalLen, mInfo.presentationTimeUs, 1);
                    }
                }


                mMediaCodec.releaseOutputBuffer(outIndex, false);
            }
        } while (outIndex >= 0);
    }
    public void addADTStoPacket(byte[] packet, int packetLen, int chancfg) {
        int profile = 2;  //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;
        int freqIdx = 3;  //见后面注释avpriv_mpeg4audio_sample_rates中48000对应的数组下标,来自ffmpeg源码
        int chanCfg = chancfg;  //见后面注释channel_configuration


        /*int avpriv_mpeg4audio_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350};
        channel_configuration: 表示声道数chanCfg
        0: Defined in AOT Specifc Config
        1: 1 channel: front-center
        2: 2 channels: front-left, front-right
        3: 3 channels: front-center, front-left, front-right
        4: 4 channels: front-center, front-left, front-right, back-center
        5: 5 channels: front-center, front-left, front-right, back-left, back-right
        6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
        7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
        8-15: Reserved
        */


        // fill in ADTS data
        packet[0] = (byte)0xFF;
        packet[1] = (byte)0xF1;
        packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
        packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
        packet[4] = (byte)((packetLen&0x7FF) >> 3);
        packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
        packet[6] = (byte)0xFC;


    }
    static class RawData {
        byte[] buf;
        int length;
        long timeStamp;


        RawData(byte[] data, int size, long pts) {
            length = size;
            buf = new byte[size];
            System.arraycopy(data, 0, buf, 0, length);
            timeStamp = pts;
        }
    }


    public void startCodec() {
        Log.d(TAG, "startCodec: ");
        int periodInFrames = 1024;
        int mBufferSize = periodInFrames * mBitsPerSample * mChannelCount / 8;


        MediaFormat format = new MediaFormat();
        format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
        format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrate);
        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, mChannelCount);
        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSamperrate);
        format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
        //format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, mBufferSize);


        try {
            mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);


        mMediaCodec.start();
        mStreaming = true;


        if (mCodecThread == null) {
            mCodecThread = new CodecThread("AudioEncode");
            mCodecThread.start();
        }
        Log.d(TAG, "startCodec: finish" );
    }


    public void stop() {
        mStreaming = false;


        try {
            Thread t1 = mCodecThread;
            mCodecThread = null;
            if (t1 != null) {
                t1.interrupt();
                t1.join();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        if(mMediaCodec != null)
        {
            mMediaCodec.stop();
            mMediaCodec.release();
            mMediaCodec=null;
        }


        mQueue.clear();
    }


    public void addData(byte[] data, int size, long pts) {
        mQueue.offer(new RawData(data, size, pts));
    }


    private String sendFileVideo = "";
    public void createTestFile(){
        try {
            String file = mContext.getExternalCacheDir() + "/" + "testAudio.aac";


            sendFileVideo = file;
            File videofile = new File(sendFileVideo);


            if (videofile.exists()) {
                videofile.delete();
            }
            videofile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void saveTestFile(byte[] buffer){
        FileOutputStream out = null;
        try {
            String testfile = sendFileVideo;
            out = new FileOutputStream(testfile,true);
            if(buffer.length > 0)
            {
                out.write(buffer);
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

### 回答1: ADT(抽象数据类型)是一种计算机科学中用于描述数据类型的数学模型,它可以通过定义一组操作来描述数据类型,并且不涉及具体的实现细节。在 Python 中,我们可以使用类来实现 ADT。 以下是一个 Python 中实现 ADT 文件的示例代码: ```python class AbstractDataType: def __init__(self): pass def operation1(self): pass def operation2(self, param1, param2): pass def operation3(self): pass ``` 在这个示例代码中,我们定义了一个名为 AbstractDataType 的类,并在其中定义了一些方法。这些方法可以视为 ADT 中定义的操作。在这个示例中,我们定义了三个操作:operation1、operation2 和 operation3。每个操作都可以包零个或多个参数,并且可以返回一个值或不返回任何值。 在实际使用中,我们可以根据需要定义更多的操作,并且可以根据需要在操作中实现具体的数据处理逻辑。 ### 回答2: 在Python中编写ADTs(抽象数据类型)的文件,通常是通过使用类来实现。以下是一个示例: ```python class ADT: def __init__(self): pass def insert(self, item): pass def remove(self, item): pass def search(self, item): pass def is_empty(self): pass def size(self): pass ``` 在上面的示例中,我们定义了一个ADT(抽象数据类型)的基本结构,其中包了常见的操作方法。每个方法都定义了一个占位符或者抛出一个`NotImplementedError`异常,需要在实际使用中根据具体的需求进行实现。 - `__init__(self)`:构造方法,可以在其中初始化类的属性。 - `insert(self, item)`:向ADT中插入一个元素。 - `remove(self, item)`:从ADT中删除一个元素。 - `search(self, item)`:在ADT中搜索指定的元素。 - `is_empty(self)`:检查ADT是否为空。 - `size(self)`:返回ADT中元素的数量。 在实际使用中,我们可以根据ADT的具体需求,编写每个方法的具体实现。这些方法可以根据不同的数据结构和算法进行优化,以满足特定的性能要求。此外,我们还可以添加其他需要的方法来扩展ADT的功能。 编写ADT文件有助于提供一个规范的接口,以便其他开发人员能够理解和使用ADT。同时,它也有助于提高代码的可读性和可维护性,因为每个方法的用途和行为都得到了明确的定义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值