• 【Android 多媒体应用】使用MediaCodec解码使用AudioTrack播放音频数据


    1.MainActivity.java

    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Environment;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    import java.io.IOException;
    
    public class MainActivity extends Activity {
    
        private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/test.aac";
        protected static AudioDecoderThread mAudioDecoder;
        private Button btn;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btn = (Button) findViewById(R.id.play);
            mAudioDecoder = new AudioDecoderThread();
            btn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    try {
                        mAudioDecoder.startPlay(SAMPLE);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            mAudioDecoder.stop();
        }
    
    }

    2.AudioDecoderThread.java

    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioTrack;
    import android.media.MediaCodec;
    import android.media.MediaCodec.BufferInfo;
    import android.media.MediaExtractor;
    import android.media.MediaFormat;
    import android.util.Log;
    
    import java.io.IOException;
    import java.nio.ByteBuffer;
    
    
    public class AudioDecoderThread {
        private static final int TIMEOUT_US = 1000;
        private MediaExtractor mExtractor;
        private MediaCodec mDecoder;
    
        private boolean eosReceived;
        private int mSampleRate = 0;
        int channel = 0;
        private final String TAG = "AACPlay";
        public void startPlay(String path) throws IOException {
            eosReceived = false;
            //创建MediaExtractor对象用来解AAC封装
            mExtractor = new MediaExtractor();
            try {
                //设置需要MediaExtractor解析的文件的路径
                mExtractor.setDataSource(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    
    
                MediaFormat format = mExtractor.getTrackFormat(0);
                if (format == null)
                {
                    Log.e(TAG,"format is null");
                    return;
                }
    
                //判断当前帧的文件类型是否为audio
                String mime = format.getString(MediaFormat.KEY_MIME);
                if (mime.startsWith("audio/")) {
                    Log.d(TAG, "format : " + format);
                    //获取当前帧的采样率
                    mExtractor.selectTrack(0);
                    mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
                    //获取当前帧的通道数
                    channel = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
                    //音频文件长度
                    long duration = format.getLong(MediaFormat.KEY_DURATION);
                    Log.d(TAG,"length:"+duration/1000000);
                }
    
    
            //创建MediaCodec对象
            mDecoder = MediaCodec.createDecoderByType(mime);
            //配置MediaCodec
            mDecoder.configure(format, null, null, 0);
    
            if (mDecoder == null) {
                Log.e(TAG, "Can't find video info!");
                return;
            }
            //启动MediaCodec
            mDecoder.start();
    
            new Thread(AACDecoderAndPlayRunnable).start();
        }
    
    
        Runnable AACDecoderAndPlayRunnable = new Runnable() {
    
            @Override
            public void run() {
                AACDecoderAndPlay();
            }
        };
    
    
        public void AACDecoderAndPlay() {
            ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
            ByteBuffer[] outputBuffers = mDecoder.getOutputBuffers();
    
            BufferInfo info = new BufferInfo();
    
            int buffsize = AudioTrack.getMinBufferSize(mSampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
            // 创建AudioTrack对象
            AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mSampleRate,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    buffsize,
                    AudioTrack.MODE_STREAM);
            //启动AudioTrack
            audioTrack.play();
    
            while (!eosReceived) {
                int inIndex = mDecoder.dequeueInputBuffer(TIMEOUT_US);
                if (inIndex >= 0) {
                    ByteBuffer buffer = inputBuffers[inIndex];
                    //从MediaExtractor中读取一帧待解数据
                    int sampleSize = mExtractor.readSampleData(buffer, 0);
                    if (sampleSize < 0) {
                        // We shouldn't stop the playback at this point, just pass the EOS
                        // flag to mDecoder, we will get it again from the
                        // dequeueOutputBuffer
                        Log.d(TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM");
                        mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
    
                    } else {
                        //向MediaDecoder输入一帧待解码数据
                        mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
                        mExtractor.advance();
                    }
                    //从MediaDecoder队列取出一帧解码后的数据
                    int outIndex = mDecoder.dequeueOutputBuffer(info, TIMEOUT_US);
                    switch (outIndex) {
                        case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                            Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
                            outputBuffers = mDecoder.getOutputBuffers();
                            break;
    
                        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                            MediaFormat format = mDecoder.getOutputFormat();
                            Log.d(TAG, "New format " + format);
                            audioTrack.setPlaybackRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
    
                            break;
                        case MediaCodec.INFO_TRY_AGAIN_LATER:
                            Log.d(TAG, "dequeueOutputBuffer timed out!");
                            break;
    
                        default:
                            ByteBuffer outBuffer = outputBuffers[outIndex];
                            //Log.v(TAG, "outBuffer: " + outBuffer);
    
                            final byte[] chunk = new byte[info.size];
                            // Read the buffer all at once
                            outBuffer.get(chunk);
                            //清空buffer,否则下一次得到的还会得到同样的buffer
                            outBuffer.clear();
                            // AudioTrack write data
                            audioTrack.write(chunk, info.offset, info.offset + info.size);
                            mDecoder.releaseOutputBuffer(outIndex, false);
                            break;
                    }
    
                    // 所有帧都解码、播放完之后退出循环
                    if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                        Log.d(TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
                        break;
                    }
                }
            }
    
            //释放MediaDecoder资源
            mDecoder.stop();
            mDecoder.release();
            mDecoder = null;
    
            //释放MediaExtractor资源
            mExtractor.release();
            mExtractor = null;
    
            //释放AudioTrack资源
            audioTrack.stop();
            audioTrack.release();
            audioTrack = null;
        }
    
        public void stop() {
            eosReceived = true;
        }
    
    }

    3.activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
    
        <Button
            android:id="@+id/play"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Play" />
    
    </LinearLayout>
  • 相关阅读:
    block本质探寻五之atuto类型局部实例对象
    block本质探寻四之copy
    block本质探寻三之block类型
    Android Studio使用时遇见的一些问题+解决方法(持续更新)
    Android之练习MVVM+DataBinding框架模式
    解决 Mac Android Studio Gradle Sync 慢的问题
    Android之MVC、MVP、MVVM
    Android之同步与异步
    Android之Fragment
    Android之Fragment栈操作 commit()问题分析
  • 原文地址:https://www.cnblogs.com/CoderTian/p/6220332.html
Copyright © 2020-2023  润新知