zoukankan      html  css  js  c++  java
  • 【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>
  • 相关阅读:
    pat 甲级 1065. A+B and C (64bit) (20)
    pat 甲级 1064. Complete Binary Search Tree (30)
    pat 甲级 1010. Radix (25)
    pat 甲级 1009. Product of Polynomials (25)
    pat 甲级 1056. Mice and Rice (25)
    pat 甲级 1078. Hashing (25)
    pat 甲级 1080. Graduate Admission (30)
    pat 甲级 团体天梯 L3-004. 肿瘤诊断
    pat 甲级 1099. Build A Binary Search Tree (30)
    Codeforce 672B. Different is Good
  • 原文地址:https://www.cnblogs.com/CoderTian/p/6220332.html
Copyright © 2011-2022 走看看