Android MediaCodec解码音频,AudioTrack播放音频,PCM数据写入文件

电脑端FFmpeg直接操作PCM


提取PCM数据
ffmpeg -i out.mp4 -vn -ar 44100 -ac 2 -f s16le out.pcm

播放PCM
ffplay -ar 44100 -ac 2 -f s16le -i out.pcm

PCM转WAV
ffmpeg -f s16be -ar 8000 -ac 2 -acodec pcm_s16be -i input.raw output.wav


解码播放音频

package com.zhangyu.myopengl.testMediaCodec;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.text.TextUtils;
import android.util.Log;

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

/**
 * MediaCodec解码器
 */
public class MCDecoderAudio {
    private static final String TAG = "MCDecoder";
    private MediaExtractor mediaExtractor;
    private MediaCodec mediaCodec;
    private AudioTrack audioTrack;
    private String srcPath;
    private boolean isFinish = false;
    private String dstPath;

    public void setDstPath(String dstPath) {
        this.dstPath = dstPath;
    }

    /**
     * 解码音频
     *
     * @param srcPath 源文件路径
     */
    public void decodeAudio(String srcPath) {
        this.srcPath = srcPath;
        //初始化解码器
        initMediaCodec();
        //初始化播放器
        initAudioTrack();
        //开始解码播放
        new Thread(new Runnable() {
            @Override
            public void run() {
                decodeAndPlay();
            }
        }).start();
    }

    /**
     * 实际的解码工作
     */
    private void decodeAndPlay() {
        OutputStream os = null;
        if (!TextUtils.isEmpty(dstPath)){
            try {
                os = new FileOutputStream(dstPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        ByteBuffer inputBuffer;
        while (!isFinish && mediaCodec != null) {
            //获取可用的inputBuffer,输入参数-1代表一直等到,0代表不等待,10*1000代表10秒超时
            //超时时间10秒
            long TIME_OUT_US = 10 * 1000;
            int inputIndex = mediaCodec.dequeueInputBuffer(TIME_OUT_US);
            if (inputIndex < 0) {
                break;
            }
            inputBuffer = mediaCodec.getInputBuffer(inputIndex);
            if (inputBuffer != null) {
                inputBuffer.clear();
            }else {
                continue;
            }
            //从流中读取的采用数据的大小
            int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);
            if (sampleSize > 0) {
                //入队解码
                mediaCodec.queueInputBuffer(inputIndex, 0, sampleSize, 0, 0);
                //移动到下一个采样点
                mediaExtractor.advance();
            } else {
                break;
            }
            //取解码后的数据
            int outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIME_OUT_US);
            //不一定能一次取完,所以要循环取
            ByteBuffer outputBuffer;
            byte[] pcmData;
            while (outputIndex >= 0) {
                outputBuffer = mediaCodec.getOutputBuffer(outputIndex);
                pcmData = new byte[bufferInfo.size];
                if (outputBuffer != null) {
                    outputBuffer.get(pcmData);
                    outputBuffer.clear();//用完后清空,复用
                }
                //播放pcm数据
                audioTrack.write(pcmData, 0, bufferInfo.size);
                //写入到本地文件中
                if (os != null) {
                    try {
                        os.write(pcmData);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //释放
                mediaCodec.releaseOutputBuffer(outputIndex, false);
                //再次获取数据
                outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIME_OUT_US);
            }
        }
        //释放解码器
        if (mediaCodec != null) {
            mediaCodec.stop();
            mediaCodec.release();
            mediaCodec = null;
            Log.e(TAG, "stopPlay");
        }
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 初始化MediaCodec
     */
    private void initMediaCodec() {
        try {
            mediaExtractor = new MediaExtractor();
            mediaExtractor.setDataSource(srcPath);
            //找到音频流的索引
            int audioTrackIndex = -1;
            String mime = null;
            MediaFormat trackFormat = null;
            for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
                trackFormat = mediaExtractor.getTrackFormat(i);
                mime = trackFormat.getString(MediaFormat.KEY_MIME);
                if (!TextUtils.isEmpty(mime) && mime.startsWith("audio")) {
                    audioTrackIndex = i;
                    Log.d(TAG, "找到音频流的索引为:" + audioTrackIndex);
                    break;
                }
            }
            //没有找到音频流的情况下
            if (audioTrackIndex == -1) {
                Log.e(TAG, "initAudioDecoder: 没有找到音频流");
                return;
            }
            //选择此音轨
            mediaExtractor.selectTrack(audioTrackIndex);
            //创建解码器
            mediaCodec = MediaCodec.createDecoderByType(mime);
            mediaCodec.configure(trackFormat, null, null, 0);
            mediaCodec.start();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化播放器
     */
    private void initAudioTrack() {
        int streamType = AudioManager.STREAM_MUSIC;
        int sampleRate = 44100;
        int channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int mode = AudioTrack.MODE_STREAM;

        int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);

        audioTrack = new AudioTrack(streamType, sampleRate, channelConfig, audioFormat,
                Math.max(minBufferSize, 2048), mode);
        audioTrack.play();
    }

    public void onDestroy() {
        isFinish = true;
    }
}

能转换下面这些音频和视频,压缩包有包和源码,还有文档api. 整理资料不易,不喜欢可以自己百度 Audio decoders adpcm_4xm adpcm_adx adpcm_ct adpcm_ea adpcm_ea_r1 adpcm_ea_r2 adpcm_ea_r3 adpcm_ea_xas adpcm_ima_amv adpcm_ima_dk3 adpcm_ima_dk4 adpcm_ima_ea_eacs adpcm_ima_ea_sead adpcm_ima_qt adpcm_ima_smjpeg adpcm_ima_wav adpcm_ima_ws adpcm_ms adpcm_sbpro_2 adpcm_sbpro_3 adpcm_sbpro_4 adpcm_swf adpcm_thp adpcm_xa adpcm_yamaha alac ape atrac 3 cook dca dsicinaudio flac g726 imc interplay_dpcm liba52 libamr_nb libamr_wb libfaad libgsm libgsm_ms mace3 mace6 mp2 mp3 mp3adu mp3on4 mpc sv7 mpc sv8 mpeg4aac nellymoser pcm_alaw pcm_mulaw pcm_s16be pcm_s16le pcm_s16le_planar pcm_s24be pcm_s24daud pcm_s24le pcm_s32be pcm_s32le pcm_s8 pcm_u16be pcm_u16le pcm_u24be pcm_u24le pcm_u32be pcm_u32le pcm_u8 pcm_zork qdm2 real_144 real_288 roq_dpcm shorten smackaud sol_dpcm sonic truespeech tta vmdaudio vorbis wavpack wmav1 wmav2 ws_snd1 xan_dpcm Audio encoders ac3 adpcm_adx adpcm_ima_wav adpcm_ms adpcm_swf adpcm_yamaha flac g726 libamr_nb libamr_wb libfaac libgsm libgsm_ms libmp3lame libvorbis mp2 pcm_alaw pcm_mulaw pcm_s16be pcm_s16le pcm_s24be pcm_s24daud pcm_s24le pcm_s32be pcm_s32le pcm_s8 pcm_u16be pcm_u16le pcm_u24be pcm_u24le pcm_u32be pcm_u32le pcm_u8 pcm_zork roq_dpcm sonic sonicls vorbis wmav1 wmav2 Video decoders 4xm 8bps VMware video aasc amv asv1 asv2 avs bethsoftvid bmp c93 camstudio camtasia cavs cinepak cljr cyuv dnxhd dsicinvideo dvvideo dxa ffv1 ffvhuff flashsv flic flv fraps gif h261 h263 h263i h264 huffyuv idcinvideo indeo2 indeo3 interplayvideo jpegls kmvc loco mdec mjpeg mjpegb mmvideo mpeg1video mpeg2video mpeg4 mpegvideo msmpeg4 msmpeg4v1 msmpeg4v2 msrle msvideo1 mszh nuv pam pbm pgm pgmyuv png ppm ptx qdraw qpeg qtrle rawvideo roqvideo rpza rv10 rv20 sgi smackvid smc snow sp5x svq1 svq3 targa theora thp tiertexseqvideo tiff truemotion1 truemotion2 txd ultimotion vb vc1 vcr1 vmdvideo vp3 vp5 vp6 vp6a vp6f vqavideo wmv1 wmv2 wmv3 wnv1 xan_wc3 xl zlib zmbv Video encoders asv1 asv2 bmp dnxhd dvvideo ffv1 ffvhuff flashsv flv gif h261 h263 h263p huffyuv jpegls libtheora libx264 libxvid ljpeg mjpeg mpeg1video mpeg2video mpeg4 msmpeg4 msmpeg4v1 msmpeg4v2 pam pbm pgm pgmyuv png ppm qtrle rawvideo roqvideo rv10 rv20 sgi snow svq1 targa tiff wmv1 wmv2 zlib zmbv
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值