Android 音视频数据播放封装类

音频

public class CAudioTrack {

    private final int mFrequency;
    private final int mChannel;
    private final int mAudioFormat;
    private AudioTrack mAudioTrack;

    public CAudioTrack(int frequency, int channel, int audioFormat) {
        this.mFrequency = frequency;
        this.mChannel = channel;
        this.mAudioFormat = audioFormat;
    }

    /**
     * 初始化
     */
    public void init() {
        if (mAudioTrack != null) {
            release();
        }
        // 获得构建对象的最小缓冲区大小
        int minBufSize = 2 * getMinBufferSize();
        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                mFrequency, mChannel, mAudioFormat, minBufSize, AudioTrack.MODE_STREAM);
        mAudioTrack.play();
    }

    /**
     * 释放资源
     */
    public void release() {
        if (mAudioTrack != null) {
            mAudioTrack.stop();
            mAudioTrack.release();
        }
    }

    private int getMinBufferSize() {
        return AudioTrack.getMinBufferSize(mFrequency, mChannel, mAudioFormat);
    }


    public void write(byte[] data) {
        if (mAudioTrack != null) {
            mAudioTrack.write(data, 0, data.length);
        }
    }

}

视频

public class CVideoPlayer {

    private volatile MediaCodec mDecoder;
    private volatile boolean mDecodeStarted = false;
    final private reentrantlock mPlayerLock = new reentrantlock();

    /**
     * 打开视频播放器
     *
     * @param width   视频宽度
     * @param height  视频高度
     * @param surface 播放视频的surface
     * @return 是否开启成功
     */
    public boolean open(int width, int height, Surface surface) {
        try {
            mPlayerLock.lock();
            Logger.d("CVideoPlayer open, mDecodeStarted is " + mDecodeStarted + " width is " + width + " ; height is " + height);
            if (mDecodeStarted) {
                //已经open无需重复操作
                return true;
            }

            //电话终端会出现解码器释放失败的问题,影响下一次的创建和播放
            //这里如果不为空,说明上一次释放出现异常,再手动调用下close,能保证此次正常
            if (mDecoder != null) {
                close();
            }

            MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
            mDecoder = MediaCodec.createDecoderByType("video/avc");
            mDecoder.configure(format, surface, null, 0);
            mDecoder.start();

            mDecodeStarted = true;
            Logger.d("open CVideoPlayer success");
        } catch (Exception e) {
            Logger.e("open CVideoPlayer exception: " + e.getMessage());
            mDecodeStarted = false;
            mDecoder = null;
            return false;
        } finally {
            mPlayerLock.unlock();
        }
        return true;
    }

    /**
     * 关闭视频播放器,释放资源
     */
    public void close() {
        try {
            mPlayerLock.lock();
            Logger.d("close CVideoPlayer begin");
            mDecodeStarted = false;
            if (mDecoder != null) {
                mDecoder.stop();
                mDecoder.release();
                mDecoder = null;
            }
            Logger.d("close CVideoPlayer end");
        } catch (Exception e) {
            Logger.e("close CVideoPlayer error : " + e.getMessage());
        } finally {
            mPlayerLock.unlock();
        }
    }

    /**
     * 播放视频流数据
     * @param data ES流
     * @param length 数据长度
     * @param pts presentation time
     */
    public void play(byte[] data, int length, int pts) {
        try {
            mPlayerLock.lock();
            if (!mDecodeStarted || mDecoder == null) {
                Logger.e("decoder is null, mDecodeStarted is " + mDecodeStarted + "; mDecoder is " + mDecoder);
                return;
            }
            onFrame(data, length, pts);
        } catch (Exception e) {
            Logger.e("CVideoPlayer play exception: " + e.getMessage());
        } finally {
            mPlayerLock.unlock();
        }
    }

    public void onFrame(byte[] buf, int length, long pts) {
        // Get input buffer index
        int inputBufferIndex = mDecoder.dequeueInputBuffer(100);

        if (inputBufferIndex >= 0) {
            //ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            ByteBuffer inputBuffer;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                inputBuffer = mDecoder.getInputBuffer(inputBufferIndex);
            } else {
                inputBuffer = mDecoder.getInputBuffers()[inputBufferIndex];
            }
            inputBuffer.clear();
            inputBuffer.put(buf, 0, length);
            mDecoder.queueInputBuffer(inputBufferIndex, 0, length, pts, 0);
        } else {
            return;
        }

        // Get output buffer index
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mDecoder.dequeueOutputBuffer(bufferInfo, 100);
        while (outputBufferIndex >= 0) {
            mDecoder.releaSEOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = mDecoder.dequeueOutputBuffer(bufferInfo, 0);
        }
    }
}

 

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...